Hallo, bei mir ist ein brandneues Nexys2 Board mit Spartan3 fpga eingetroffen :-). Das ist kein Zufall, denn ich möchte bei den Diskussionen um vhdl und fpgas etwas mehr verstehen und hoffentlich selber einmal etwas damit basteln. Meine konkrete Frage ist folgende: Es wird allgemein empfohlen, das package numeric_std zu verwenden anstelle von IEEE.STD_LOGIC_UNSIGNED.ALL. Weil dann direkt arithetische Operationen wie +1 damit möglich sind. Das wird von der Mehrheit der thematisch orientierten Seiten allerdings nicht gemacht. Wenn ich Lothars Homepage einigermaßen richtig verstehe, ist ein unsigned array dann vom typ std_logic_vector, d.h. wenn ich code nachvollziehen und umsetzen möchte, muss ich entsprechend deren std_logix vektoren in unsigned/singned vektoren umwandeln? Gemischte Zuweisungen, also ein leds_int : unsigned(7 downto 0) kann ich nicht einem led : std_logic_vector(7 downto 0) zuweisen? Mehr plagt mich noch gar nicht.
Das bedarf nur einer simplen Umwandlung : unsigned(std_logic_vector) bzw std_logic_vector(unsigned). Bei deinem Design würdest du dann normalerweise std_logic_vector nur im top-level direkt bei den Ports anwenden und innerhalb nur unsigned. Kann man zwar auch anders machen, aber dann wirds unübersichtlich.
> Weil dann direkt arithetische Operationen wie +1 damit möglich sind.
Das ist aber nicht Hauptgrund. Mittels numeric_std musst du jedes
Signals als signed oder unsigned deklarieren. Das verhindert viele
Fehler, da das Sysnthesetool den Typ überprüfen kann. So kann z.B. eine
(versehentliche) Addition von signed und unsigned verhindert werden.
> Es wird allgemein empfohlen, das package numeric_std zu verwenden... > Das wird von der Mehrheit der thematisch orientierten Seiten allerdings > nicht gemacht. Ganz einfach, weil die alten Synopsis-Libs in allen Lehrbüchern und Skripten und daraus resultierend in dem herunterladebaren Code verwendet werden. So werden z.B. auch heute noch beim Generieren eines Projekts bei Xilinx diese Libs eingebunden. Weil (wie schon geschrieben) bei der numeric_std jede Umwandlung explizit geschrieben werden muß, kann es z.B. nicht passieren, dass ein Codeschnipsel, der aus einer Beschreibung mit IEEE.STD_LOGIC_SIGNED.ALL herauskopiert und in eine andere mit IEEE.STD_LOGIC_UNSIGNED.ALL hineinkopiert und dort ganz anders interpretiert wird. > Das wird von der Mehrheit der thematisch orientierten Seiten allerdings > nicht gemacht. Aber genauso steht noch in jedem Lehrbuch die Schreibweise eines getakteten Prozesses mit asynchronem globalem Reset. Und das ist anerkanntermaßen ein für FPGAs suboptimaler Beschreibungsstil.
> Aber genauso steht noch in jedem Lehrbuch die Schreibweise eines > getakteten Prozesses mit asynchronem globalem Reset. Und das ist > anerkanntermaßen ein für FPGAs suboptimaler Beschreibungsstil. Ja, so habe ich es auch in der Uni gelernt. Heißt das, ich könnte ruhigen Gewissens in meinem Design alle asynchronen resets durch einen synchronen globalen reset ersetzen? Wäre das tatsächlich die technisch bessere Lösung? Irgendwie habe ich da Hemmungen, aber ich denke ich werd's bald mal machen...
Hi, synchrone Resets sind für das Timing nicht unbedingt immer besser, das hängt ganz davon ab --> A,X,L ;O) Am besten mal ausprobieren, kannst ja mal alle Resets über ein globales Generic auf asynchron oder synchron stellen und schauen, wie das Timing sich verhält. Wenn es irgendwie geht: Resets dort weglassen, wo man sie nicht braucht, z.B. Daten-Pipelines. Bei L bspw. kannst du nicht davon ausgehen, dass die Register ohne Reset den Initialzustand haben, den du in einer Default-Zuweisung definierst, die Default-Zuweisung wird einfach ignoriert. Bei X kann man wohl mit einer Default-Zuweisung erreichen, dass das Register im Power-Up-Fall den richtigen Wert annimmt, also mit
1 | signal ls_richtiger_ini_wert_bei_X : std_logic := '0'; |
VG, SuperWilly
dito schrieb: >> Aber genauso steht noch in jedem Lehrbuch die Schreibweise eines >> getakteten Prozesses mit asynchronem globalem Reset. Und das ist >> anerkanntermaßen ein für FPGAs suboptimaler Beschreibungsstil. > > Ja, so habe ich es auch in der Uni gelernt. Heißt das, ich könnte > ruhigen Gewissens in meinem Design alle asynchronen resets durch einen > synchronen globalen reset ersetzen? Wäre das tatsächlich die technisch > bessere Lösung? Für ein synchrones Signal kann das PAR-Tool die Laufzeiten berechnen und dafür sorgen, dass alle Register in demselben Takt (rück)gesetzt werden. Probleme gibt es, wenn das Netz zu umfangreich wird und viele Eingänge daran hängen. Darum gibt es in einigen FPGAs dafür spezielle Routing-Ressourcen (Netze) > > Irgendwie habe ich da Hemmungen, aber ich denke ich werd's bald mal > machen... > Oder sollte ich die Resets ganz rausnehmen? Das hängt vom FPGA ab. Xilinx empfiehlt für seine FPGAs mit einer Signalinitialisierung zu arbeiten und rät von einem Reset ab (www.xilinx.com/support/documentation/white_papers/wp272.pdf). In Actel (ProASIC3) und Lattice FPGAs (ECP2(M) und ECP-S, ECP3) wird ein Reset benötigt. Lattice hält dafür ein spezielle Netz vor. Mit Altera FPGAs kenne ich mich nicht aus. Tom
Ich finde asynchrone Resets praktischer als die Zuweisung bei der Deklaration, weil die vom restlichen Code so weit weg ist. Der asynchrone Reset ist genau in dem Prozess, der die Signale auch treibt. Die Synthese mit xst erkennt das auch problemlos als Initialisierung, auch wenn im Top-Level das globale Reset-Signal auf 0 gezogen wird und gar nicht aus dem Chip rauskommt. Einen externen Chip-Reset habe ich bislang noch nie gebraucht...
> Ich finde asynchrone Resets praktischer als die Zuweisung bei der > Deklaration, weil die vom restlichen Code so weit weg ist. Die Gefahr dabei ist nur, dass dieser Reset dann irgendwann mal wirklich verwendet wird... Und was dabei herauskommen kann sieht man im Beitrag "Hardware mit VHDL "richtig" beschreiben."
Wenn man den Reset wirklich hernehmen würde, taucht das im Timinganalyzer als zusätzlicher (und wahrscheinlich seeehr lahmer) Pfad auf. Vermutlich würde es dann schon an den input-to-setup-Constraints scheitern. Nur weil Unerfahrene sich damit ins Knie schiessen können, ist das doch kein Grund gleich alles zu verbannen :)
> Nur weil Unerfahrene sich damit ins Knie schiessen können, > ist das doch kein Grund gleich alles zu verbannen :) Ein Anfänger FPGA-Design hat genau 1 Takt und 0 Reset. Punkt. Wenn es mehr sein muss, dann mit fundierter Begründung. Und genau mit/an/bei dieser Begründung lernen Unerfahrene. Und einmal fertig gelernt dürfen alle Tricks aus der FPGA-Trickkiste geholt werden. Wie war nochmal die Geschichte mit dem Zauberlehrling, der die Geister rief...
Hi, wenn du bei einem synchronen Reset ein Timing-Problem kriegst, dann solltest du dir auch tiiiieeeeefe Gedanken machen, was du denn da so tust. Und dementsprechend deine Logik bauen.... Bei einem asynchronen Reset kriegst du kein Timing-Problem gemeldet und wunderst dich dann, dass die Schaltung in 2 von 3 Faellen nicht richtig funktioniert... meine 2 cents...
>> Ein Anfänger FPGA-Design hat genau 1 Takt und 0 Reset. Punkt. > Klasse Argumentation. Das war keine Argumentation sondern ein Postulat. Ich versuche mich selber daran zu halten. Und es ist erstaunlich, wie oft das geht ;-) Das ist so ähnlich, wie z.B. auf Landstaßen die Maximalgeschwindigkeit auf 100 km/h festgelegt ist. Ich kenne etliche Landstraßen, die deutlich mehr aushalten... Von mir aus kann jeder zehn Takte (also z.B. 2 mehr als er Taktnetze hat) und 36 Resets (gerne auch lokal und kombinatorisch) in seine Designs einbauen. Aber dann darf er sich hinterher nicht wundern warum das nicht zuverlässig geht. > wenn du bei einem synchronen Reset ein Timing-Problem kriegst Mit so einem synchronen Reset wie hier kannst du durchaus Probleme bekommen:
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | |
5 | entity SYNCRST is |
6 | Port ( clk : in STD_LOGIC; |
7 | reset : in STD_LOGIC; |
8 | :
|
9 | );
|
10 | end SYNCRST; |
11 | |
12 | architecture Behavioral of SYNCRST is |
13 | begin
|
14 | P1: process (clk) begin |
15 | if rising_edge(clk) then |
16 | if (reset='1') then |
17 | -- tuwas
|
18 | else
|
19 | -- tuwasanderes
|
20 | end if; |
21 | end if; |
22 | end process; |
23 | |
24 | P2: process (clk) begin |
25 | if rising_edge(clk) then |
26 | if (reset='1') then |
27 | -- tusonstwas
|
28 | else
|
29 | -- tusonstwasanderes
|
30 | end if; |
31 | end if; |
32 | end process; |
33 | end Behavioral; |
Hier steht in beiden Prozessen bildhübsch ein synchroner Reset. Allerdings wird der beim P1 und beim P2 u.U. zu unterschiedlichen Zeiten inaktiv werden. Und das kann durchaus zu eigenartigem Verhalten führen...
>Das war keine Argumentation sondern ein Postulat
Ceterum censeo Carthaginem esse delendam ;O)
Gruß,
SuperWilly
> Hier steht in beiden Prozessen bildhübsch ein synchroner Reset. > Allerdings wird der beim P1 und beim P2 u.U. zu unterschiedlichen Zeiten > inaktiv werden. Und das kann durchaus zu eigenartigem Verhalten > führen... deshalb den Reset erstmal mit 'n paar Flipflops einsynchronisieren und damit sauber de-glitchen. Dann sehen P1 und P2 den gleichen Reset oder es hagelt ein Timing-Problem...
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.