Forum: FPGA, VHDL & Co. Synthesefähiger Code


von FPGA-Küchle (Gast)


Lesenswert?

Im folgenden meine Überlegungen wie man (als Anfänger) synthesefähigen 
code schreiben kann. ich konzentriere mich dabei auf vhdl das kenn ich 
am besten.


Nicht alles was vhdl/verilog versteht und simulierbar ist (modelsim) 
wird mit dem selben verhalten in einen FPGA/cpld synthetisiert. das 
liegt an zwei gründen:

-(synchrones) digitales design hat seine regeln, die Gatter und ff auf 
dem chip können nicht alles was (man|aNFÄNGER) sich wünscht.
-Vhdl ist geschwätzig, die synthese ist nur künstlich intelligent (also 
dumm)

Folgende Regeln sind strenger formuliert als nötig damit sie anfänger 
vor fallgruben schützen. ein erfahrener Anwender kann in spezialfällen 
dagegen verstossen, wenn er weiss was er tut:
 Only true fools and true experts use gated clocks


(1) Flankenwechsel ('event, rising_edge, posedge) nur bei taktsignalen 
verwenden.

(2) keine Takte multiplexen oder abschalten (gated clocks)

(3) den zustand hochohmig ('Z') nur an fpga/cpld pins verwenden.

(4) Nur die ports am Top level modul dürfen die richtung inout verwenden

(5) für Ports nur in,out oder inout benutzen.

(6) in statemachines nur einfache zuweisungen verwenden, Zähler (counter 
<= counter + 1) oder multiplexer in einem extra process oder ausserhalb 
eines processes verwenden.

(7) ein process hat immer folgenden Rahmen und sens list, ausnahmen 
reset mit andere Polarität, takt mit anderer flanke, kein reset
1
process(clk,rst)
2
begin
3
  if rst = '1' then
4
   --..
5
   elsif rising_edge(clk) then
6
   --..
7
  end if
8
end process;

Ausnahmen wie erwähnt meinen:
1
process(clk,rst_n)
2
begin
3
  if rst_n = '0' then
4
   --..
5
   elsif rising_edge(clk) then
6
   --auch falling_edge(clk) then 
7
   --..
8
  end if;
9
end process;


(8) in einem design takt immer mit derselben Flanke verwenden

(9) Flanken bedingen nicht mit anderen signalen verwenden, also Nie:
   if rising_edge(clk_i) and signal2 = '0' then --bullshit

(10) nur die typen std_logic, std_logic_vector, unsigned oder signed 
verwenden.

(11) verwende bedingte zuweisungen
1
       sig3 <= '1' when (zustand = aktiv) and enable = '1' else
2
                '0';

(12) verwende nie wait oder after


(13) Nutze applicationnotes und synthese style guides des 
chipherstellers (Altera, xilinx)

(14) Verstehe jede warning, error in der reportdatei des synthesetools
 (Xilinx:XST:*.syr)

(15) nutze die Möglichkeit einen stromlaufplan des syntheseergebnises 
anzuschauen (Xilinx:ise:RTL-view)


Das sollte für den dikussionsstart genügen. Bitte ergänzen und beachte 
das ist für anfänger gedacht, Beschreibungen für Sonderfälle wo diese 
reglen aufgeweicht werden verwirren mehr als das sie helfen.






























von HubiHubi (Gast)


Lesenswert?

vielleicht als Tips im Wiki festhalten!

von fpgakuechle (Gast)


Lesenswert?

#vielleicht als Tips im Wiki festhalten!
Nach einer diskussion hier mach ich das.

von +++ (Gast)


Lesenswert?

Den Sinn von (9) versteht ich nicht ganz, mein altes Xilinx-ISE hat da 
immer den invertierten Clk-Enable-Eingang für Signal2 verwendet, 
genauso, wie ich es haben wollte!?

von fpgakuechle (Gast)


Lesenswert?

#(9) Flanken bedingen nicht mit anderen signalen verwenden, also Nie:
#   if rising_edge(clk_i) and signal2 = '0' then --bullshit


Also für mich sieht das nach gated clock aus. Was du meinst ist wohl
1
if rising_edge(clk_i) then
2
  if signal2 = '0' then
3
   q <= d;
4
  end if;
5
end if;

und nach meiner regel wäre folgendes verboten:
1
if rising_edge(clk_i) and signal2 = '0' then
2
   q <= d;
3
end if;


Hm, grübel simutechnisch ist beides wohl identisch. ist halt ne Frage 
wie ein synthesefähiges FF für die verscheidenen hersteller zu 
beschreiben ist. Kann sein das die auf Takt als einziges bedingung in 
der zeile mit der edge abfrage bestehen, also zeilenweise jeden 
ff-eingang beschreiben.

Die idee hinter dem verbot von log. verknüpfungen mit der 
Flankenerkennung ist Verhindern von gated clocks. Vielleicht kommt es 
darauf an, ob in der sens list wirklich nur der takt und evt. der 
asynchrone reset steht.

von Hagen R. (hagen)


Lesenswert?

Es macht ein Unterschied in der Synthese, das konnte ich feststellen. 
Schreibt man es in eine Zeile so wirds ein Gated Clock, schreibt man's 
in zwei Zeilen mit separater IF abfrage so wird es ein getaktes FF für 
die zweite Zeile. Das ist also besser und deshalb benutze ich immer
1
if rising_edge(clk_i) then
2
  if signal2 = '0' then
3
   q <= d;
4
  end if;
5
end if;

Deine Regeln sind super gut und teilweise mache ich das schon intuitiv 
so (komme aus der normalen sequientiellen Programmierung ;)
nur 6.) solltest du ganz genau erklären. Verstehe schon das WARUM aber 
nicht das WIE ?

Wenn ich einen getakteten Counter habe wie soll ich diesen ausserhalb 
meines getakteten Hautprozesses der die State Machine (getaktet 
natürlich) enthält, ebenfalls im gleichen Takt aber in eigenem Process 
implementieren ? Als kombinatorische Logik ?

Gruß Hagen

von na (Gast)


Lesenswert?

Vielleicht sollte noch in die Regeln, dass Standardzuweisungen bei 
Signaldeklaration nicht synthesefähig sind, genauso wie initial-Blöcke, 
die in etwa das gleiche machen. Außerdem keine for-Schleifen für Zähler 
verwenden :-) .

von +++ (Gast)


Lesenswert?

Ich kann es im Moment nicht ausprobieren, soweit ich mich erinnere, 
führten beide Varianten auf das gleiche Ergebnis mit Benutzung des 
Clk-Enable-Eingangs.
Die gated Clock bekam ich, wenn ich ein Signal aus zwei anderen via 
"and" Verknüpfung erzeugte und dann auf das Steigen des neuen Signals 
wartete.
So tiefgehend habe ich mich mit der Materie nicht beschäftigt, aber wenn 
ich auf die RTl-Schematik geschaut habe, waren die Möglichkeiten der FFs 
immer voll genutzt. Trotzdem hast du Recht, dass man es von vorneherein 
so schreiben sollte, dass unterschiedliche Interpretationen 
ausgeschlossen sind.
Da hast du eine wirklich gute Richtlinie erstellt!

von FPGA-Küchle (Gast)


Lesenswert?

#Wenn ich einen getakteten Counter habe wie soll ich diesen ausserhalb
#meines getakteten Hautprozesses der die State Machine (getaktet
#natürlich) enthält, ebenfalls im gleichen Takt aber in eigenem Process
#implementieren ? Als kombinatorische Logik ?

Beispiel
1
--counter in FSM process
2
3
process(clk_i)
4
begin
5
 case fsm_state_q is
6
  when IDLE => 
7
   count_q <= "000";
8
   if sig_start = '1' then
9
     fsm_state_q <= CNT_ACT;
10
   end if;
11
 
12
 when CNT_ACT =>
13
   if sig_event = '1' then
14
     count_q <= count_q + 1;
15
   end if;
16
   if sig_stop = '1' then
17
     fsm_state_q <= IDLE;
18
   end if;
19
 end case;
20
end process;
21
22
23
--counter ausserhalb
24
25
process(clk_i)
26
begin
27
 if reset_sig <= '1' then
28
  count2_q <= "000";
29
 elsif cnt_ena = '1' then 
30
  count2_q <= count_q + 1;
31
 end if;
32
end process;
33
34
--und das entscheidende
35
reset_sig  <= '1' when fsm_state_q = IDLE else '0';
36
cnt_ena    <= '1' when (fsm_state_q = CNT_ACT) and (sig_event = '1') else          
37
              '0';


beide counter verhalten sich identisch, aber in der zweiten varianten 
erkennt die synthese sicher sinen Zähler, während sie in der zweiten 
durch den "zerissenen" counter Probleme haben kann.

setzt man dagegen reset_sig und cnt_ena von der fsm aus, hat man einen 
Takt verspätung zwischen count_q und count2_q.

der "trick" liegt in der Abfrage der zustandsvariable für den 
Zustandsübergang und für das setzen des counters extra. das entspricht 
genau den Teilschaltungen die die synthese bauen muss:
-Kombinatorik von den Q-Ausgängen der FF des Zustandssignals und einiger 
Eingangssignale zu den R/S/CE(?)-Eingängen der selben FF.
-Kombinatorik von den Q der FF des Zustandssignals und einiger (andere) 
Eingangssignale zu den CE und R der FF des counters.

Wird es so zerteilt, hat es das Synthesetool leichter. Sonst droht Murks 
(zu groß, falsches Verhalten) oder es geht garnicht. Aber zumindest die 
ISE ist inzwischen schlau genug da fast immer noch was draus zu machen. 
Mit dieser regel sollten es aber auch "dümmere" tools den code 
übersetzten können.




-

von GümmelTürk (Gast)


Lesenswert?

der Anhang beinhaltet noch ein paar interessante Details

von GümmelTürk (Gast)


Angehängte Dateien:

Lesenswert?

Mist Anhang vergessen

von Holger H. (holger-h-hennef) Benutzerseite


Lesenswert?

@GümmelTürk
Danke für den Anhang.
Das bringt auch Licht in die Sache mit dem  use Befehl,
wen ich das Projekt nicht in einem eizigen File halten will.
Aber die Referenz in dem anderen File nutzen will. ???
Gruss, Holger.

von FPGA-Küchle (Gast)


Lesenswert?

# GümmelTürk

Im Anhang seite 25 ist ein Fehler.

Ein FF mit asynchronen Reset wird nicht wie angegeben so beschrieben:
1
architecture rtl of reg areset is
2
 begin -- rtl
3
 reg : process ( clk , rst )
4
   begin  -- process reg
5
    if rising edge ( clk) then
6
     q <= d;
7
    end if ;
8
    if rst = '0' then
9
     q <= '0';
10
    end if ;
11
  end process reg;
12
end rtl ;

sondern
1
reg : process ( clk , rst )
2
   begin -- process reg
3
    if rst = '0' then
4
     q <= '0';
5
    elsif rising edge ( clk) then
6
     q <= d;
7
    end if ;
8
end process reg;


Es scheint elegant zu sein, im Process Zuweisungen im IF nicht durch ein 
elsif zu verbinden (es ist wird eben immer die letzte (untere) gültige 
Zuweisung ausgeführt), aber das ist unübersichtlich und unlogisch (die 
höchst priore Anweisung steht zuletzt.

Auch die folgende seite ist inkorrekt, mindestens Xilinx fordert das man 
einen synchronen reset wie folgt beschreibt:
1
reg : process (clk)
2
   begin -- process reg
3
   if rising edge ( clk) then
4
    if rst = '0' then
5
     q <= '0';
6
    else
7
     q <= d;
8
    end if;
9
    end if; 
10
end process reg;


Und statt '0' steht auf der Folie ’0’ (falsches Hockomma), auch das 
Kommantarzeichen -- kommt verhunzt von der Folie rüber, vielleicht ein 
PDF Problem.

und low-aktive signale sollten im namen als solche gekennzeichnet sein, 
also rst_n statt rst.


Ob ich dem Prof mal schreiben tu?

von FPGA-Küchle (Gast)


Lesenswert?

Noch ein Problem beim cut&Paste von der Folie, der unterstrich bei 
rising_edge ist entschwunden.

von Neuer G. (vhdl_progger)


Angehängte Dateien:

Lesenswert?

Da fallen mir auch noch ein paar Regeln ein:

- in der Syntese keine Variablen verwenden (falls doch dann
   nur innherhalb eines Processes.

- nicht die Bibliotheken
     use ieee.std_logic_arith.all;
     use ieee.std_logic_unsigned.all;
   sonder numeric_std einbinden
     use ieee.numeric_std.all;

Eine meiner Meinung nach gute Zusammenfassung (leider in Englisch)
habe ich mal im Anhang beigefügt.


Zu Punkt (7). Mann sollte eigentlich nur

  if (rst = '1') then

verwenden. Falls dann irgend ein Design mit '0' resettet wird
so kann das reset-Signal einmal im Toplevel invertiert werden.
Sonst baut der Compiler vor jedem Modul eine Inverter
ins reset-Signal ein.

Gruß

Ralf

von Christian P. (kron)


Lesenswert?

Erstmal Danke und Händeklatschen für den
schönen Beitrag und die hehren Ziele.
Ich habe ein paar Fragen, deren Beantwortung
sicher auch anderen helfen wird.

zu 8.:
Falls ich doch etwas auf die andere Flanke
machen will (weil z.B. irgendein
Chip, den man ansteuert, das braucht),
ist es das Richtige, ein CLK2 <= NOT CLK; zu nutzen?

zu 6.:
Das ist glaube ich die einschneidenste "Regel". :)
Das Beispiel, was du (FPGA-Küchle) dann gegeben hast,
habe ich gesehen und auch halbwegs verstanden.
Aber trotzdem fällt es mir schwer, dass jetzt auf
vorhandene "echte" Fälle anzuwenden bzw. umzusetzen.
Hast du evtl. ein "wirkliches", also komplettes Beispiel
in deiner Küche, wo man alles komplett sieht und dadurch
genau sehen kann, wie man das aufbaut?

von fpgakuechle (Gast)


Lesenswert?

zu 6.:
#Hast du evtl. ein "wirkliches", also komplettes Beispiel
#in deiner Küche, wo man alles komplett sieht und dadurch
#genau sehen kann, wie man das aufbaut?

Aus rechtlichen Gründen werde ich Designs die für Geld enstanden sind 
nicht veröffentlich (dürfen). Ich schau mal nach freien designs, die den 
regeln genügen. meine erster Kandidat wäre der 8 bit uC Picoblaze von 
Xilinx. der liegt in vhdl vor und der autor Ken chapman schreibt nur 
brauchbaren code (ne menge tips hab ich von ihm gelernt). man schon ob 
der die counter auch anfängergerecht auslagert.

von fpgakuechle (Gast)


Lesenswert?

#zu 8.:
#Falls ich doch etwas auf die andere Flanke
#machen will (weil z.B. irgendein
#Chip, den man ansteuert, das braucht),
#ist es das Richtige, ein CLK2 <= NOT CLK; zu nutzen?

Keine allgemeine Antwort, außer beim FPGA, synthesestool hersteller 
nachzuschauen.

Xilinx sagt (es klappt auch ab ise 8.1.)

-allgemein statt rising_edge falling edge verwenden (klappt gut, neuere 
tools erkennen auch selbstständig das das timing sich halbiert (wenn 
signale zwischen FF mit rising und FF mit falling wandern )
-für DDR-IOB-FF den negativen takt per inverter zu erzeugen also clk_n 
<= not clk;
-falls du wirklich einen zweiten negierten Takt brauchst, also nicht die 
FF mit den invertierten takteingang benutzen kannst, dann erzeuge diesen 
takt nicht per inverter sondern mit einem Taktmanagere oder 
takt-regelkreis(DCM,DLL).


von Alban (Gast)


Lesenswert?

Was vielleicht noch nicht explizit gesagt wurde, dass für sequentielle 
Logik alle process (always) Konstrukte in einer Takt-Domäne sein 
sollten. Also nur mit ein und dem selben Takt versorgt werden sollten.

Gerade für Anfänger mag es vielleicht sinnvoll sein erst mal für eine 
Entwicklung nur eine Takt-Domäne zu nutzen.

von Joerg W. (joergwolfram)


Lesenswert?

vielleicht sollte man hier aber zwischen CPLD und FPGA unterscheiden, da 
sich die interne Struktur doch stark unterscheidet. Bei ersteren dienen 
die globalen Clocks letztendlich nur zum Einsparen von Produkttermen, 
ansonsten kann jede Makrozelle theoretisch mit einem anderen Signal als 
Takt versorgt werden. Für den Anfänger mag das zwar nicht von Belang 
sein, aber spätestens wenn die Projekte etwas grösser werden, kann ein 
zentraler Takt, mit dem alles synchron läuft, ziemlich viele Resourcen 
fressen. Und die gibt es bei CPLD's nicht gerade in grossen Mengen.

von Alban (Gast)


Lesenswert?

@ Joerg

Das ist ein gute Punkt. Mit CPLDs kenne ich mich nicht so aus und ich 
hab vergessen dazu zu schreiben das ich das mal für FPGAs gelernt habe.

von alex (Gast)


Lesenswert?

@FPGA-Küchle:
Kann das sein, dass in deinem Beispiel weiter oben, wie man einen Zähler 
außerhalb von FSM betreibt, die Abfrage nach Takt-Flanke fehlt und in 
der Zeile count2_q <= count_q + 1, statt count_q count2_q stehen soll, 
und reset_sig in die Sens Liste des Prozesses aufgenommen werden muss?
Statt:
1
--counter ausserhalb
2
3
process(clk_i)
4
begin
5
 if reset_sig <= '1' then
6
  count2_q <= "000";
7
 elsif cnt_ena = '1' then 
8
  count2_q <= count_q + 1;
9
 end if;
10
end process;
11
12
--und das entscheidende
13
reset_sig  <= '1' when fsm_state_q = IDLE else '0';
14
cnt_ena    <= '1' when (fsm_state_q = CNT_ACT) and (sig_event = '1') else          
15
              '0';

das hier:
1
--counter ausserhalb
2
3
process(clk_i, reset_sig)
4
begin
5
 if reset_sig <= '1' then
6
  count2_q <= "000";
7
 elsif rising_edge(clk_i) then
8
  if cnt_ena = '1' then 
9
   count2_q <= count2_q + 1;
10
  end if:
11
 end if;
12
end process;
13
14
--und das entscheidende
15
reset_sig  <= '1' when fsm_state_q = IDLE else '0';
16
cnt_ena    <= '1' when (fsm_state_q = CNT_ACT) and (sig_event = '1') else          
17
              '0';

Ich weiß, ich bin manchmal kleinlich, aber bitte um Aufklärung, denn ich 
möchte gerne das mit dem Auslagern des Zählers aus der FSM voll und ganz 
verstanden haben.

Gruß,
Alex

von Volker (Gast)


Lesenswert?

begin
 if reset_sig <= '1' then
  count2_q <= "000";

dumme Frage, müsste das nicht if reset_sig = '1' then heissen?

Gruß Volker

von alex (Gast)


Lesenswert?

>begin
> if reset_sig <= '1' then
>  count2_q <= "000";
>
>dumme Frage, müsste das nicht if reset_sig = '1' then heissen?

stimmt, da müsste auch noch if reset_sig = '1' heissen:
1
--counter ausserhalb
2
3
process(clk_i, reset_sig)
4
begin
5
 if reset_sig = '1' then
6
  count2_q <= "000";
7
 elsif rising_edge(clk_i) then
8
  if cnt_ena = '1' then 
9
   count2_q <= count2_q + 1;
10
  end if:
11
 end if;
12
end process;
13
14
--und das entscheidende
15
reset_sig  <= '1' when fsm_state_q = IDLE else '0';
16
cnt_ena    <= '1' when (fsm_state_q = CNT_ACT) and (sig_event = '1') else          
17
              '0';

  

von fpgakuechle (Gast)


Lesenswert?

#Abfrage nach Takt-Flanke fehlt und in
Ja
#der Zeile count2_q <= count_q + 1, statt count_q count2_q stehen soll,
Ja
#und reset_sig in die Sens Liste des Prozesses aufgenommen werden muss?
nein
(soll ein synchroner reset werden, aber ohne rising_edge ist das ja 
nicht erkenntlich.


Asche aufs Haupt, sollte wohl länger ausschlafen ...


#dumme Frage, müsste das nicht if reset_sig = '1' then heissen?

ja

ich knüppele es abends mal durch die synthese eh ich wieder so nen shit 
verbreite.

von Volker (Gast)


Lesenswert?

@fpgakuechle,

ne ne, ist halb so schlimm, ich finde es super, dass du dir soviel Mühe 
machst, da können solche Fehler schnell mal vorkommen.
Wenn sich Leser aktiv mit der Materie beschäftigen werden sie auch diese 
Fehler finden, Alex und ich hamse ja auch gefunden.

Viel wichtiger ist das Prinzip bzw. ein Konzept, und das hast du super 
erklärt.

Danke auch an Alex.

Ich fange übrigens gerade mit VHDL an, habe aber zuvor schon einige CPLD 
Projekte in ABEL gemacht.

Gruß Volker

von Michael (Gast)


Lesenswert?

Ich finde es wichtig das man unbedingt ein syncrones Design erzugen 
sollte und asyncrone Designs als Anfänger meiden sollte. Zudem müssen 
die SIGNALE oder PORTS immer durch ein RESET in einen definierten 
Anfangszustand gesettz werden. Dies sind aus meiner Sicht die 
wichtigsten Regeln Werden diese nicht befolgt kommt es zu Fehlern die 
man ganz schwer findet.

von ChrisV (Gast)


Lesenswert?

Zu beginn des Designs sollte man sich überlegen, ob ein asynchroner 
Reset nötig ist.
In 99% aller Fälle kommt man bei FPGAs ohne Reset aus, da nach der 
Konfiguration das komplette FPGA in einem definierten Zustand ist.

Einige sehr hilfreiche Designregeln dazu finden sich auch in den 
TechXclusives von Xilinx:

http://www.xilinx.com/xlnx/xweb/xil_tx_display.jsp?iLanguageID=1&category=&sGlobalNavPick=&sSecondaryNavPick=&multPartNum=1&sTechX_ID=kc_smart_reset

http://www.xilinx.com/xlnx/xweb/xil_tx_display.jsp?iLanguageID=1&category=&sGlobalNavPick=&sSecondaryNavPick=&multPartNum=1&sTechX_ID=kc_priorities

von Lothar (Gast)


Lesenswert?

Da muss ich ChrisV doch voll unterstützen:

So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen 
(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der 
Resetleitung auch recht interessant:
Ein Teil vom  FPGA wird zurückgesetzt, der Rest kriegt davon nichts mit
--> Statemachines laufen Amok, Zähler zählen Käse...
Probierts mal aus.

Kurz und gut:
Ein Reset von aussen ist ein asynchrones Signal, das gehört erst mal zum 
FPGA-Takt synchronisiert und dann intern verarbeitet. So ist das.

Und Michael hat im ersten Satz auch recht:
nur Anfänger können mal (aus Versehen) ein asynchrones Design 
hervorzaubern, einem Profi, der sein Geld mit FPGA-Design verdient, darf 
das nicht passieren.

Nur müssen Signale nicht mit einem Reset auf definierte Werte gesetzt 
werden, ich kann (zumindest für Xilinx FPGAS) schon bei der Synthese 
Startwerte angeben (ein FPGA ist eh' nur eine Art RAM, das geladen 
wird):
1
signal flag1 : STD_LOGIC := '1';
2
signal flag0 : STD_LOGIC := '0';
3
signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
4
signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";
Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.
Das passt dann auch für die Simulation.

Gruß Lothar


Am Rande:
Eine Einstellungs-Frage für FPGA-Designer könnte übrigens lauten:
"Weiviele Takte hatte Ihr letztes Design?"
Die richtige Antwort darauf ist:
"Einen"

von Falk (Gast)


Lesenswert?

@Lothar

>So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen
>(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der
>Resetleitung auch recht interessant:

Wir wollen mal die Kirche im Dorf lassen. Ein auf einen ein paar (1..10) 
Picosekunden langen Puls reagieren wahrscheinlich nicht mal die 
schnellsten FPGAs. Bei 100ps würde ich mal frühestens was vermuten.

>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.

Er ist implizit (=0).

>Das passt dann auch für die Simulation.

Dort wird deine Zuweisung ausgeführt. Und damit hast du eine 
wunderschöne Inkonsistenz zwischen Simulation und Synthese. -> 
SCHROTT!!!

>Eine Einstellungs-Frage für FPGA-Designer könnte übrigens lauten:
>"Weiviele Takte hatte Ihr letztes Design?"
>Die richtige Antwort darauf ist:
>"Einen"

Noch so ein Durchblicker-Satz. :-(
Die richtige Antwort wäre wohl eher

"So viel wie nötig, so wenig wie möglich"

Das üben wir nochmal.

MFG
Falk

von Christian H. (cavorca)


Lesenswert?

Hallo,
schönes posting.

Ich habe mir auch ein paar Anregungen überlegt:
zum einen fände ich auch, wie andere schon gesagt haben, die 
unterscheidung CPLD <-> FPGA wichtig. So wie ich es verstanden habe ist 
regel 8 für CPLDs nicht nötig.

Obohl oder gerade weil ich Anfänger bin habe ich auch einen vorschlag 
für eine Ergänzung: Modelliert man eine FSM muss man immer im

case(zustand)

einen default teil haben. auch wenn dieser default teil nie ausgeführt 
werden wird. na hat mich heute Morgen darauf gebracht.

dann muss immer in jedem zustand jede verwendete variable zugewiesen 
werden (z.B. next_state) sonst werden latches modelliert (hat mich auch 
na drauf gebracht.

Vielleicht trifft das auch nur für Verilog und nicht für VHDL zu. Für 
den Fall würde ich auch eine Unterscheidung verilog <-> vhdl 
vorschlagen.

Das waren 2 der größten Probleme die ich als Anfänger hatte, die ich nie 
selbst hätte lösen können und nur durch dieses Forum weiter gekommen 
bin.

in einem wiki eintrag fände ich als Anfänger auch ein Gerüst einer fsm 
hilfreich. na hat in einem anderen posting sowas geschrieben:
Beitrag "Problem in Verilog: Simulation läuft,Fit gibt falsches Desi"
(weit unten. 17.2.)

von Christian H. (cavorca)


Lesenswert?

mir kommt aber auch schon eine frage zur regel (2). was mache ich, wenn 
ich einen sram ansteuern will. an write enable muss dann ja ein je nach 
anwendung schneller takt anliegen. aber wenn ich aus dem ram lesen will 
muss der natürlich abgeschaltet sein. wie mache ich das dann? externe 
elektronik?
bzw habe ich die bedeutung des wortes gated clock falsch verstanden?

von na (Gast)


Lesenswert?

Zu dieser Standardwert-Initialsierungs-Diskussion und damit verbundenes 
weglassen des reset:

Es mag ja sein, dass Xilinx-Tools für FPGAs oder auch die anderer 
Hersteller Standardwerte bei Signaldeklaration in der Synthese 
akzeptieren und den FPGA entsprechend initialisieren. Wobei mich mal 
interessieren würde inwieweit das wirklich so ist, scheint es ja viele 
Meinungen zu geben?

Allerdings sollen das hier ja vielleicht auch allgemeine Regeln zu 
synthesefähigem Code werden. Eventuell beachtet nicht jedes Synthesetool 
diese Standardwerte. Abgesehen davon kann man ja mit VHDL und Verilog 
auch ASICs beschreiben und dann sind Standardwerte erst recht fehl am 
Platz, außerdem ist dann ein reset mehr als nötig. (Daher vielleicht 
auch die verbreitete Meinung, Standardzuweisungen seien grundsätzlich 
nicht synthesefähig.) Das hat zwar nicht viel mit programmierbarer Logik 
zu tun aber man sollte es vielleicht zumindest erwähnen bevor jemand es 
falsch lernt.

Meinungen?

von Klaus Falser (Gast)


Lesenswert?

Die Initialisierung über VHDL bei den Xilinx-Tools funktioniert 
(jedenfalls bei den letzten Versionen), das ist keine Frage von 
Meinungen.
Vielleicht kann jemand aus der ALTERA-Ecke uns mitteilen, wie es damit 
bei Quartus ausschaut.

Da sich die Abfänger ja wahrscheinlich das letzte WebPack holen, sind 
diese Initialisierungenn in jedem Fall empfehlenswert.
Und einen Abfänger wird man ja wohl hoffentlich nicht an ein ASIC 
ranlassen.

Klaus

von Joerg W. (joergwolfram)


Lesenswert?

Bei Xilinx wird, soweit ich weiss und es auch nutze der 
Initialisierungswert in der ucf-Datei angegeben z.B.:

NET "signalname" INIT='0'

Ich will nicht darauf herumreiten, aber vielleicht ist es sinnvoll, ein 
bisschen den internen Aufbau von FPGAs und CPLDs zu erklären. Dann wird 
auch klar, warum z.B. Punkt (1) bei FPGAs Pflicht ist und bei CPLDs 
weitestgehend irrelevant. Die meisten Anfänger werden sich wohl eher ein 
billiges CPLD-Board holen.

von Klaus Falser (Gast)


Lesenswert?

Welchen Punkt (1) meinst Du ?

(1) Flankenwechsel ('event, rising_edge, posedge) nur bei taktsignalen
verwenden.

Dies gilt für CPLD wie für FPGA's genauso.
Das Design eines CPLD sollte synchron sein, sonst ist das Timing nicht 
verläßlich. Ein CPLD hat deshalb genauso dedizierte, intere 
Taktleitungen wie ein FPGA.

von na (Gast)


Lesenswert?

Naja, ein Anfänger wird nicht gleich einen ASIC bauen, das ist richtig. 
Aber vielleicht soll man einen ASIC-Entwurf machen und den Prototyp auf 
einem FPGA testen, dann ist es besser sich gar nicht erst an 
Initialisierungszuweisungen gewöhnt zu haben, außer man weiß genau was 
man tut bzw. dass man nur für die spezielle Plattform entwickelt.

von ChrisV (Gast)


Lesenswert?

>>So ein asnychroner Reset verhält sich z.B. bei sehr sehr kurzen Impulsen
>>(Spikes, Störungen, nur so ein paar pico-Sekunden lang) auf der
>>Resetleitung auch recht interessant:

>Wir wollen mal die Kirche im Dorf lassen. Ein auf einen ein paar (1..10)
>Picosekunden langen Puls reagieren wahrscheinlich nicht mal die
>schnellsten FPGAs. Bei 100ps würde ich mal frühestens was vermuten.

Egal ob es jetzt 1, 10, oder 100ps braucht, dass intern ein FF das 
Zittern anfängt, dass sind Fehler die erstens: Sehr schwer zu finden 
sind und zweitens: Zu verhindern sind, indem ein synchroner reset 
eingesetzt wird. Mir fällt keine Situation ein, wo mir ein asynchroner 
reset schon mal Vorteile gebracht hätte.

von Falk (Gast)


Lesenswert?

@ChrisV

>Egal ob es jetzt 1, 10, oder 100ps braucht, dass intern ein FF das
>Zittern anfängt, dass sind Fehler die erstens: Sehr schwer zu finden
>sind und zweitens: Zu verhindern sind, indem ein synchroner reset

Schon klar, das steht ausser Frage. Ich wollte lediglich der 
aufkeimenden Hysterie etwas entgegen setzten, dass jeder physikalisch 
noch so kleine Puls die FlipFlops aus dem Takt bringt.

MFG
Falk

von Lothar (Gast)


Lesenswert?

@Falk: auf die Gefahr hin, dass ich mich wiederhole:

>signal flag1 : STD_LOGIC := '1';
>signal flag0 : STD_LOGIC := '0';
>signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
>signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";
>
>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.
>Das passt dann auch für die Simulation.

Probiers einfach mal aus (wie gesagt mit Xilinx):
Gleich nach dem Laden des FPGAs ist flag1 = 1, flag0 = 0, count1 = 1100 
und count2 = 1234abcd.
Genauso wie in der Simulation.

Wenn ich NICHTS angebe, ist die Initialisierung der Hardware implizit = 
0 (null, low) und in der Simulation = U (undefined), und das gibt dann 
ohne so einen expliziten Reset unschöne Effekte. Weil eben U verknüpft 
mit irgendwas anderem (1,0,H,L,Z...) immer noch U gibt.

Und jetzt meine Ansicht: wenn ich der Hardware Startwerte im Sourcecode 
vorgeben kann, die dann ja einfach von der Toolchain in den Bitstrom 
eingesetzt und bei jedem FPGA-Start neu aus dem Config-ROM geladen 
werden, dann brauche ich für solche Startwerte keinen Reset.


>Das üben wir nochmal

Ich für meinen Teil habe das ausgiebig geübt.
Aber bitte, wenn nötig üben wir beide das nochmal.

von Falk (Gast)


Lesenswert?

@Lothar

@Falk: auf die Gefahr hin, dass ich mich wiederhole:

>Daraus folgt: für Initialisierungswerte brauche ich keinen Reset.
>Das passt dann auch für die Simulation.

>Probiers einfach mal aus (wie gesagt mit Xilinx):
>Gleich nach dem Laden des FPGAs ist flag1 = 1, flag0 = 0, count1 = 1100
>und count2 = 1234abcd.
>Genauso wie in der Simulation.

Huch, was ist das denn?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity test is
    Port (  flag1_o : out STD_LOGIC;
            flag0_o : out STD_LOGIC;
            count1_o : out STD_LOGIC_VECTOR (3 downto 0);
            count2_o : out STD_LOGIC_VECTOR (31 downto 0);
            clk: in std_logic
    );
end test;

architecture Behavioral of test is

signal flag1 : STD_LOGIC := '1';
signal flag0 : STD_LOGIC := '0';
signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";

begin

  flag1_o <= flag1;
  flag0_o <= flag0;
  count1_o <= count1;
  count2_o <= count2;

end Behavioral;

Erst sagt mir der Depp von XST das

Compiling vhdl file C:/Data/work/VHDL/ram_emu/test.vhd in Library work.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 16. 
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 17. 
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 18. 
Default values are ignored in synthesis.
WARNING:HDLParsers:533 - C:/Data/work/VHDL/ram_emu/test.vhd Line 19. 
Default values are ignored in synthesis.
Entity <test> (Architecture <behavioral>) compiled.

und dann das???

Synthesizing Unit <test>.
    Related source file is C:/Data/work/VHDL/ram_emu/test.vhd.
WARNING:Xst:653 - Signal <flag1> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <flag0> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count1<3>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count1<2>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count1<1>> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count1<0>> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count2<31>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<30>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<29>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<28>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<27>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<26>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<25>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<24>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<23>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<22>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<21>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<20>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<19>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<18>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<17>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<16>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<15>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<14>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<13>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<12>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<11>> is used but never assigned. Tied 
to value 1.
WARNING:Xst:653 - Signal <count2<10>> is used but never assigned. Tied 
to value 0.
WARNING:Xst:653 - Signal <count2<9>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<8>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<7>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<6>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<5>> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count2<4>> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count2<3>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<2>> is used but never assigned. Tied to 
value 1.
WARNING:Xst:653 - Signal <count2<1>> is used but never assigned. Tied to 
value 0.
WARNING:Xst:653 - Signal <count2<0>> is used but never assigned. Tied to 
value 1.
Unit <test> synthesized.

>Und jetzt meine Ansicht: wenn ich der Hardware Startwerte im Sourcecode
>vorgeben kann, die dann ja einfach von der Toolchain in den Bitstrom
>eingesetzt und bei jedem FPGA-Start neu aus dem Config-ROM geladen
>werden, dann brauche ich für solche Startwerte keinen Reset.

Richtig, aber in den Mauals von Xilinx stand immer EXPLIZIT drin, dass 
die Initialisierung NICHT für die Synthese verwendet wird (so wie auch 
die erste Ausschrift von XST). So waren z.B. bei Simulationsmodellen von 
BRAMs immer die Initialisierungswerte UND Attribute gesetzt, einmal für 
die Simulation und einmal für die Synthese. Aber dann verwendet XST sie 
DOCH???
Muss ich das versetehen?

>>Das üben wir nochmal
>Aber bitte, wenn nötig üben wir beide das nochmal.

Was ich hiermit getan habe. Versteh ich dennoch nicht so ganz. Die XST 
Entwickler wissen wohl auch nichst so recht was sie wollen?

Aber halt! Das war jetzt nur ein gaaanz einfacher Test. Was ist mit 
"echten" Signalen?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity test is
    Port (  flag1_o : out STD_LOGIC;
            flag0_o : out STD_LOGIC;
            count1_o : out STD_LOGIC_VECTOR (3 downto 0);
            count2_o : out STD_LOGIC_VECTOR (31 downto 0);
            clk: in std_logic
    );
end test;

architecture Behavioral of test is

signal flag1 : STD_LOGIC := '1';
signal flag0 : STD_LOGIC := '0';
signal count1 : STD_LOGIC_VECTOR (3 downto 0) := "1100";
signal count2 : STD_LOGIC_VECTOR (31 downto 0) := x"1234abcd";

begin

process(clk)
begin
  if rising_edge(clk) then
    flag1 <= not flag1;
    flag0 <= not flag0;
    count1 <= count1 +1;
    count2 <= count2 +5;
  end if;
end process;

  flag1_o <= flag1;
  flag0_o <= flag0;
  count1_o <= count1;
  count2_o <= count2;

end Behavioral;

Ich bekomme die gleiche Ausschrift wie oben "Default values are ignored 
in synthesis.". ABer keine Ausschrift über die Zuweisung von 
Defaultwerten. Leider kann mir das Design nicht im FPGA-Editor 
anschauen, ich hab hier im Moment nur Webpack 4.2. Der Fall bleibt also 
vorerst offen.

MFG
Falk

von Joerg W. (joergwolfram)


Lesenswert?

@Falk
Soviel ich weiß und auch weiter oben beschrieben habe, wird der 
Startwert in der ucf-Datei festgelegt. Da sich im ersten Fall die 
Signalwerte nicht ändern können, werden nach der Optimierung die 
Ausgangsstufen fest auf '0' oder '1' gelegt und eigentlich gar keine 
Logik erzeugt. Im zweiten Fall können sich die Ausgangssignale ändern 
und werden somit nicht mit '0' oder '1' verbunden.

Jörg

von Lothar (Gast)


Lesenswert?

@Falk: Ich hatte vergessen zu sagen, dass diese Defaultwert-Zuweisung 
meines Wissens erst ab WebPack Version 7 funktioniert. Jedenfalls ohne 
Fehlermeldungen.


Gruß
Lothar

von Falk (Gast)


Lesenswert?

@Joerg Wolfram

>Soviel ich weiß und auch weiter oben beschrieben habe, wird der
>Startwert in der ucf-Datei festgelegt. Da sich im ersten Fall die

Dieses Verfahren kenn ich auch. Ist aber unschön, weil es leicht zu 
Inkonsistenzen kommt.

@Lothar

>@Falk: Ich hatte vergessen zu sagen, dass diese Defaultwert-Zuweisung
>meines Wissens erst ab WebPack Version 7 funktioniert. Jedenfalls ohne
>Fehlermeldungen.

Ahhhja, das erklärt einiges. Ich hab immer nur bis ISE 6.3 verwendet.

MfG
Falk

von KingSize (Gast)


Lesenswert?

@fpgakuechle

Auch welchen Wiki wurde das den genau festgehalten?

von Kalle (Gast)


Lesenswert?

würde mich auch interessieren, danke!

von Artur Funk (Gast)


Lesenswert?

Hier ist meine Erfahrung:

Wenn man z.B. zwei Werte (a 128 bit) arithmetisch behandeln möchte.

variable als natural -> sehr langsam ~ 20 MHz
variable als std_logic_vector schneller ~ 110 MHz
signale (arch intern) -> am schnellsten  ~ 310 MHz

Von shematic's her sehen die erstellten vhdl files auch besser aus, als 
wenn man mit variablen arbeitet.

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.