Hallo zusammen,
ich habe eine größere Logik, die ich gerne fest definieren würde, so
dass ich sie in meinem entity immer wieder verwenden kann.
Ich weiß, dass es procedure und function gibt, auch ein package ist mir
bekannt.
Nur wie definiere ich diesen Logikblock, dass die Synthese diesen immer
wieder verwendet und nur die Logik zum ansteuern und der statemachine
drum herum baut?
Hintergrund ist, dass ich begrenzte Ressourcen habe.
Diesen großen Logikblock möchte ich in verschiedenen states einer FSM
immer wieder ansteuern/nutzen.
also z.B.
1
CASEstate_fsmIS
2
WHENstate_1=>function1(a,b,c);
3
WHENstate_2=>function1(d,e,f);
4
WHENstate_2=>function1(g,h,i);
5
WHENOTHERS=>
6
ENDCASE;
Wird in diesem Falle für "function1" nur einmal Logik benötigt, oder
wird function1 wirklich 3mal eingebaut.
Wie kann ich der Synthese mitteilen, dass er doch bitte für function1
nur einmal Gatter vorsehen soll und die Glue-Logic dann so darum bauen?
Oder macht das ein normales Synthese Tool ganz automatisch?
Vielen Dank!
Ralf
Dann mußt du multiplexer drumherum bauen die jeden input und output
dieser Einheit an die gewollte andere Einheit schalten können.
Macht man auch in CPUs so. Die Additionseinheit kann mit
unterschiedlichen Registern verdrahtet werden je nach Befehl. Sowohl
Eingangs wie auch ausgangsseitig (wenn man keine lust auch soviele
Multiplexer hatte, hat man sich mit nem Accumulator und dem Datenbus
(extern) begnügt).
Ein Addierer ist manchmal kleiner als die ganzen notwendigen Multiplexer
usw.
Es lohnt nur wenn die Komponente sehr groß ist und von vielen
(langsamen) anderen Einheiten nicht gleichzweitig) benutzt wird.
Man könnte sogar als Extrembeispiel eine CPU annehmen, die mal mit dem
Interupt Controller verbunden ist und mal mit dem DMA Controller.
Da kann die CPU von beiden genutzt werden, ist ziemlich komplex, und
beide greifen ncht gleichzeitig darauf zu bzw. nicht allzu oft (grins).
>Hintergrund ist, dass ich begrenzte Ressourcen habe.>Diesen großen Logikblock möchte ich in verschiedenen states einer FSM>immer wieder ansteuern/nutzen.
Dann zeichne dir mal den Schalplan auf. Also deine FSM, die muß ja nun
irgendwelche inputs oder outputs haben und Steuereingänge.
Da hängst du jetzt deine Funktion ran. Und die willst du nun immer von
dem selben Block also von der selben FSM in unterschiedlichen States
benutzen.
Tja merkst du was ?
Da muß man nichts (multiplexen) anders verdrahten ... sind ja immer die
gleichen Einheiten die verbunden sind.
Scheint so als wenn du in den States (leicht) unterschiedliche
Funktionen verwendest bzw. andere Datenpfade.
Ah ich glaube ich weiß was dein Problem ist (Glaskugel geguckt) ...
Wenn du in deiner FSM Signal A und B und C und D usw. hast und du in dem
einem State A und B miteinander Multiplizierst und in einem nächsten C
und D dann macht er (der Synthetisierer) daraus zwei multiplizierer !?
Dann mußt du den Multilizierer ausserhalb der Statemachine machen und
ihn mit der Statemachine Steuern. Die Statemachine bekommt zwei Ausgangs
Datenbusse und einen Eingangsdaten bus und Steuerleitungen.
Nun bedient die Statemachine die Datenbusse und die Steuerleitungen so
das sie das ergebnis zurückkriebt. Das kann Sie für beide States machen
(jetzt mehrere States). Und du hast nur einen Multiplizierer gebraucht.
Das geht fast mit allem.
Ralf schrieb:> Ich weiß, dass es procedure und function gibt, auch ein package ist mir> bekannt.
Dann vergiss die ersten beiden davon mal vorerst schnell wieder, denn
augenscheinlich weißt du zwar, dass es sie gibt, aber nicht, was sie
machen und wie sie das tun.
Ralf schrieb:> Wird in diesem Falle für "function1" nur einmal Logik benötigt, oder> wird function1 wirklich 3mal eingebaut.
Sie wird 3 mal eingabeut, weil sie ja auch 3 mal unterschiedliche
Parameter hat. Der Synthesizer, der aus deiner Hardwarebeschreibung ja
richtige Hardware machen muss, erkennt das und macht folglich 3 mal die
für "function1()" nötige Hardware auf. Nur als kleiner Denkanstoss:
rising_edge() ist auch eine Funktion...
Du wirst das etwa so machen müssen:
1
CASEstate_fsmIS
2
WHENstate_1=>p1<=a;p2<=b;p3<=c;
3
WHENstate_2=>p1<=d;p2<=e;p3<=f;
4
WHENstate_2=>p1<=g;p2<=h;p3<=i;
5
WHENOTHERS=>
6
ENDCASE;
7
8
function1(p1,p2,p3);
Allerdings scheint mir "function1()" sowieso ziemlich sinnlos, weil sie
nur Eingangsparameter und kein Ergebnis hat...
Und ich vermute sehr, dass du für diese Aufgabe eh' keine Funktion oder
Prozedur benötigst.
Hallo und vielen Dank!
Lothar Miller schrieb:> Dann vergiss die ersten beiden davon mal vorerst schnell wieder, denn> augenscheinlich weißt du zwar, dass es sie gibt, aber nicht, was sie> machen und wie sie das tun.
Function => wiederkehrende Logik die man verwenden kann, um den VHDL
Code übersichtlicher zu gestalten, wenn diese Logik immer wieder
verwendet werden soll. Kann nur innerhalb eines entity verwendet werden.
Es gibt nur ein Rückgabewert!
Procedure => Eigentlich das gleiche wie die Function, nur dass mehrere
Rückgabewerte definiert werden können.
Package => hier können Elemente definiert werden, die auch
entity-übergreifend verwendet werden können. Ein Package kann also auch
Functions und Packages enthalten.
Liege ich mit dieser Ansicht so weit daneben?
Lothar Miller schrieb:> Allerdings scheint mir "function1()" sowieso ziemlich sinnlos, weil sie> nur Eingangsparameter und kein Ergebnis hat...
Ja das stimmt, weil es nur ein "sinnloses" Beispiel war :)
Lothar Miller schrieb:> Und ich vermute sehr, dass du für diese Aufgabe eh' keine Funktion oder> Prozedur benötigst.
Ich möchte einfach meinen Code nicht unnötig aufblähen und Ressourcen
sparen :)
Bisher habe ich es so umgesetzt (auf ein simples Beispiel
heruntergebrochen!)
z.B.
1
functionand_and
2
(A:std_logic;
3
B:std_logic)
4
returnstd_logicis
5
variableAandB:std_logic;
6
begin
7
AandB:=AANDB;
8
returnAandB;
9
endand_and;
Mit dieser Funktion beschreibe ich ein einfaches AND-Gatter.
Dieses Gatter möchte ich nun 4mal in Reihe schalten.
1
WHENstate1=>
2
variable(0):=and_and(DATA_IN(0),signal1);
3
variable(1):=and_and(DATA_IN(1),variable(0));
4
variable(2):=and_and(DATA_IN(2),variable(1));
5
variable(3):=and_and(DATA_IN(3),variable(2));
6
signal1<=variable(3);
7
8
WHENstate2=>-- anderes DATA_IN
9
variable(0):=and_and(DATA_IN(0),signal1);
10
variable(1):=and_and(DATA_IN(1),variable(0));
11
variable(2):=and_and(DATA_IN(2),variable(1));
12
signal1<=variable(2);
13
14
WHENstate3=>-- anderes DATA_IN
15
variable(0):=and_and(DATA_IN(0),signal1);
16
variable(1):=and_and(DATA_IN(1),variable(0));
17
signal1<=variable(1);
Ich möchte also mit diesem Beispiel folgendes erreichen:
- signal 1 soll als Eingang der vier seriellen AND Gatter dienen und
soll mit den von state zu state wechselnden Daten ver-und-et werden.
- je nach state möchte ich die Zwischensignale abgreifen. Also z.B. das
signal1 mit dem Wert nach dem dritten AND Gatter belegen.
- ich möchte, dass dennoch nur 4 AND Gatter vorhanden sind, diese also
in jedem state wiederverwendet werden.
Wie ich nun gelernt habe, wird das so nicht gehen und in meinem Bsp.
werden wohl 9 statt 4 AND Gatter implementiert.
Wäre es so korrekt?
1
CASExyzIS
2
WHENstate1=>
3
a1:=DATA_IN(0);b1:=signal1;
4
a2:=DATA_IN(1);b2:=variable(0);
5
a3:=DATA_IN(2);b3:=variable(1);
6
a4:=DATA_IN(3);b4:=variable(2);
7
signal1<=variable(3);
8
9
WHENstate2=>-- anderes DATA_IN
10
a1:=DATA_IN(0);b1:=signal1;
11
a2:=DATA_IN(1);b2:=variable(0);
12
a3:=DATA_IN(2);b3:=variable(1);
13
signal1<=variable(2);
14
15
WHENstate3=>-- anderes DATA_IN
16
a1:=DATA_IN(0);b1:=signal1;
17
a2:=DATA_IN(1);b2:=variable(0);
18
signal1<=variable(1);
19
WHENOTHERS=>
20
ENDCASE;
21
22
variable(0):=and_and(a1,b1);
23
variable(1):=and_and(a2,b2);
24
variable(2):=and_and(a3,b3);
25
variable(3):=and_and(a4,b4);
Ich habe bewusst so ein einfaches Bsp gewählt, um den Sachverhalt der
Wiederverwendung von Logik zu verstehen, auch wenn es logisch überhaupt
keinen Sinn ergibt, ein solches Konstrukt dafür zu verwenden, um ein
paar AND Gatter zu sparen.
Ich denke keinem würde es etwas nützen, wenn ich statt dem AND Gatter
meine eigentliche Funktion nutzen würde, der Code 100 Zeilen hat und
sich dann niemand mehr die Mühe macht, alles anzuschauen und zu
verstehen ;)
Vielen Dank!
Ralf
PS: eventuelle Syntaxfehler möge man mir verzeihen...
Abgesehen davon, dass dein Beispielcode, wie du ja selbst sagst, nur
Anschauung dient, und es in 99,9% der synthetisierbaren VHDL-Designs
überhaupt gar keinen Grund gibt, mit Variablen oder Funktionen zu
arbeiten, würde ich sagen, dass in deinem zweiten Beispiel die Logik
hiner and_and() viermal instanziiert wird....
.... wenn da nicht die Synthese eine Optimierung durchführen würde und
sich die gesamte Logik jedes Datenpfades anschauen würde, um diese
zusammenzufassen.
Schlumpf schrieb:> Abgesehen davon, dass dein Beispielcode, wie du ja selbst sagst, nur> Anschauung dient, und es in 99,9% der synthetisierbaren VHDL-Designs> überhaupt gar keinen Grund gibt, mit Variablen oder Funktionen zu> arbeiten,
Wenn du geschrieben hättest 99,9 der Zeilen Code, würde ich das
unterschreiben. Aber wenn man einigermassen weiss was man tut (oder mal
seinen Syntesizer ausprobiert, ob das passiert was man sich ausgedacht
hat), kann man mit Funktionen gut lesbare Beschreibungen machen (Setze
das z. B. für Adressdecoder und dazugehörigen Busmultiplexer ein).
Variablen kommen bei mir eigentlich nur in Zusammenhang mit Zählern oder
for...loop bzw. for...generate vor.
Die Grundregel aus der Software Entwicklung gilt auch hier: Wenn es
mehrere schreib Varianten gibt, wähle die übersichtlichere/schneller
nachvollziehbare.
Uwe schrieb:>>Hintergrund ist, dass ich begrenzte Ressourcen habe.>>Diesen großen Logikblock möchte ich in verschiedenen states einer FSM>>immer wieder ansteuern/nutzen.>> Dann zeichne dir mal den Schalplan auf. Also deine FSM, die muß ja nun> irgendwelche inputs oder outputs haben und Steuereingänge.> Da hängst du jetzt deine Funktion ran. Und die willst du nun immer von> dem selben Block also von der selben FSM in unterschiedlichen States> benutzen.
Das nennt sich FSMD, finite-state-machine with datapath. Ist das übliche
Vorgehen wie Hardware geplant und gebaut wird. Dazu gibt es diverse
Literatur und auch passende Threads hier im Forum. Z. B.:
Beitrag "Wie behandelt man Daten bei einem FPGA?"
Ich habe es jetzt etwas umgeschrieben und bin auf den Hinweis mit den
Variablen eingegangen.
Die FSM ist in einem getakteten Prozess und daher wären die Variablen ja
nicht außerhalb verfügbar :)
1
fsm:PROCESS(CLK,NRES)
2
BEGIN
3
IFNRES='0'THEN
4
...
5
ELSIFrising_edge(CLK)THEN
6
CASExyzIS
7
WHENstate1=>
8
a1<=DATA_IN(0);
9
a2<=DATA_IN(1);
10
a3<=DATA_IN(2);
11
a4<=DATA_IN(3);
12
signal1<=signal_erg(3);-- diese Zuweisung klappt nicht!
13
WHENstate1=>...
14
WHENOTHERS=>
15
ENDCASE;
16
ENDPROCESS;
17
18
signal_erg(0)<=and_and(a1,signal1);
19
signal_erg(1)<=and_and(a2,signal_erg(0));
20
signal_erg(2)<=and_and(a3,signal_erg(1));
21
signal_erg(3)<=and_and(a4,signal_erg(2));
Nun habe ich das Problem, dass meine Idee mit der kombinatorischen Logik
nicht so ganz aufgeht, oder ich noch ein Knoten im Kopf habe.
Mit der steigenden Flanke von CLK werden die Signale zugewiesen. Diese
werden aber erst mit dem kommenden Takt übernommen, so dass die
Zuweisung signal1 <= signal_erg(3); nicht funktioniert bzw. nicht das
Ergebnis der 4 functions übernimmt, sondern den vorhergehenden Zustand.
Ich glaube in diesem Fall bin ich doch auf Variablen angewiesen, die
ihren Zustand sofort ändern?
An welche Stelle im Prozess müsste ich dann die vier Funktionen
schreiben, damit ich in diesen die Variablen verwenden kann?
Direkt hinter das Process - BEGIN?
Vielen Dank!
Ralf schrieb:> Mit der steigenden Flanke von CLK werden die Signale zugewiesen. Diese> werden aber erst mit dem kommenden Takt übernommen,
Das ist das grundlegende Prinzip eines synchronen Designs. So
funktioniert "echte" Hardware.
Du versuchst hier, syntaktische Klimmzüge durchzuführen, um irgendein
Ergebnis zu erreichen und ich habe den Verdacht, dass du nicht wirklich
eine Vorstellung davon hast, was diese Konstrukte dann bei der Synthese
an Hardware erzeugen.
Wenn deine Funktion and_and() nur aus einer kombinatorischen Verknüpfung
besteht, dann wird auch diese als reine Kombinatorik in Form von LUTs
abgebildet.
Fütterst du diesen Haufen aus LUTs mit Ausgängen von Registern, dann
erscheint das Ergebnis nach eine Durchlaufzeit T am Ausgang deiner LUTs.
Das heißt, du KANNST es erst mit dem nächsen Takt verwenden, weil das
Ergebnis vorher elektrisch gar nicht zur Verfügung steht.
Wenn du es einen Takt früher benötigst, dann musst du es auch einen Takt
früher erzeugen. Dazu könnte man ggf die FSM cleverer gestalten.
Variablen helfen dir auch nicht aus dem Problem. Das einzige, was
passieren kann, ist, dass die Synthese daraus eine deutlich komplexere
Logik generiert, um die Funktionalität, wie du sie mit Variablen
bekommst, wieder auf reale Hardware-Elemente abzubilden.
Daher bin ich ein Gegner von Variablen in synthetisierbarem VHDL-Code.
Bei der Verwendung von Signalen ist die Trennung zwischen Kombinatorik
und Registern viel leichter zu überblicken. Bzw. man hat eine viel
klarere Sicht darauf, welche Logikpfade entstehen und wo diese durch
Register begrenzt sind. Man beschreibt einfach "näher" an der realen
Hardware.
Bei Variablen ist diese Trennung natürlich auch möglich, aber man kann
sich viel schneller ein Bein stellen, ohne es zu merken.
Und aus Erfahrung kann ich sagen:
Es gibt kein einziges VHDL-Design, welches die Benutzung von Variablen
erforderlich macht. Und genauso verhält es sich mit Schleifen,
Funktionen, ....
Man kann diese Elemente benutzen, weil sie, wenn man weiss, was man tut,
an der einen oder anderen Stelle eine übersichtlichere Darstellung
ermöglichen, aber selbst in wirklich komplexen Designs gibt es immer
eine Lösung ohne diese Elemente.
Aus diesem Grund rate ich Anfängern dringend davon ab, Variablen und
dergleichen zu verwenden. Es stiftet mehr Verwirrung, wenn es darum
geht, zu verstehen, was der Code nachher für Hardware erzeugt.
Ralf schrieb:> Die FSM ist in einem getakteten Prozess und daher wären die Variablen ja> nicht außerhalb verfügbar
Schon wieder einen Nachteil der (von ehemaligen Software-Progremmierern
so heißgelibten) Variablen erkannt. Und dort gibt es noch mehr:
Beitrag "Variable vs Signal"> Mit der steigenden Flanke von CLK werden die Signale zugewiesen.
Die Denkweise ist noch grundlegend falsch!
Durch die Flanke übernimmt das Flipflop die Daten, die zu diesem
Zeitpunkt an seinem Eingang anliegen. Dieses Bild musst du haben und mit
der HardwareBESCHREIBUNGssprache VHDLbeschreiben. Wie willst du etwas
beschreiben können, von dem du dir selber kein Bild machen kannst?
Deine Beschreibung muss vom Synthesizer in LUTs und Flipflops umgesetzt
werden. Er hat (mal abgesehen von deutlich komplexeren Elementen wie
einem Multiplizierer) nur deise beiden Elemente. Und deshalb muss deine
Beschreibung etwas abbilden, was wieder auf diese Elemente
Flipflop+Logik reduziert werden kann.
> Ich glaube in diesem Fall bin ich doch auf Variablen angewiesen, die> ihren Zustand sofort ändern?
Was ist in der Hardware der Unterschied zwischen Variablen und Signalen?
Keiner, nichts, nada! Eine Beschreibung wird mit Signalen oder mit
Variablen genau gleich umgesetzt. Ein "sofort" gibt es in der Hardware
nicht, das ist nur eine Krücke fürs Denken. Mal angenommen, du hast
diesen Prozess:
1
process(din)
2
variabledo:std_logic;
3
begin
4
do:='1';
5
do:='0';
6
do:=din;
7
endif;
Welchen Signalverlauf wird do hier haben? Was wird daraus gemacht?
Ralf schrieb:> signal1 <= signal_erg(3); -- diese Zuweisung klappt nicht!
Mein Glückwunsch, du hast die "Latency" entdeckt. Mach dir klar, was da
passiert, du wirst dieses Problem laufend haben. Und am einfachsten ist
es, das vorher schon zu wissen, dann umgehst du es irgendwann einfach
so, wie du auf dem Gehweg einen Mülleimer oder einen Laternenmast
umgehst: ohne jeglichen Zeitverlust...