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
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
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
useIEEE.NUMERIC_STD.ALL;
4
5
entitySYNCRSTis
6
Port(clk:inSTD_LOGIC;
7
reset:inSTD_LOGIC;
8
:
9
);
10
endSYNCRST;
11
12
architectureBehavioralofSYNCRSTis
13
begin
14
P1:process(clk)begin
15
ifrising_edge(clk)then
16
if(reset='1')then
17
-- tuwas
18
else
19
-- tuwasanderes
20
endif;
21
endif;
22
endprocess;
23
24
P2:process(clk)begin
25
ifrising_edge(clk)then
26
if(reset='1')then
27
-- tusonstwas
28
else
29
-- tusonstwasanderes
30
endif;
31
endif;
32
endprocess;
33
endBehavioral;
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...
> 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...