Forum: FPGA, VHDL & Co. Synthese dauer ewig, Grund: RAM


von Andy (Gast)


Lesenswert?

Hallo zusammen,

die Synthese meines Projekts in ISE wurde nun nach knapp 24h Stunden 
durch mich abgebrochen. Um den Fehler zu finden wurde ein RAM-Modul 
(siehe Code) auskommentiert und siehe da, die Synthese benötigt nur 
wenige Minuten.
Ich habe nun herausgefunden, dass diese Verzögerungen in der Synthese 
durch die Wahl des RAMs hervorgerufen wird 
(http://stackoverflow.com/questions/20853824/synthesize-xst-in-xillinx-get-a-long-time). 
Laut diesem Beitrag soll die Synthese eines Distributed-RAMs sehr lange 
dauern. Meiner Meinung nach erzeuge ich allerdings einen Block-RAM (nach 
http://www.lothar-miller.de/s9y/archives/20-RAM.html).
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
use work.ADC_INTERFACE_LIB.all;
5
library IEEE_PROPOSED;
6
use IEEE_PROPOSED.FIXED_PKG.ALL;
7
8
entity CAL_MATRIX_RAM is
9
  port( 
10
      CLK       : in  std_logic;
11
      RST       : in  std_logic;  
12
      WRITE_PIN   : in  std_logic;
13
         READ_PIN    : in  std_logic;
14
      DATA_RE_IN   : in  RAM_IN;
15
      DATA_IM_IN   : in  RAM_IN;
16
      
17
         DATA_RE_OUT : out RAM_OUT(CHANNELS-1 downto 0);
18
      DATA_IM_OUT : out RAM_OUT(CHANNELS-1 downto 0);
19
      DV        : out std_logic;
20
      RDY      : out std_logic
21
         );
22
end CAL_MATRIX_RAM;
23
24
architecture behavioral of CAL_MATRIX_RAM is
25
26
signal rdy_net      : std_logic := '0';
27
28
type memory_type is array(0 to (SAMPLES*CHANNELS-1)) of RAM_IN;
29
signal memory_re : memory_type;
30
signal memory_im : memory_type;
31
   
32
begin
33
  process (CLK)
34
    variable ADR_W : integer := 0;
35
    variable ADR_R : integer := 0;
36
  begin
37
    
38
    if (RST='1') then
39
      ADR_W := 0;
40
      ADR_R  := 0;
41
      DV <= '0';
42
      rdy_net <= '0';
43
    
44
    elsif CLK='1' and WRITE_PIN='1' then
45
      memory_re(ADR_W) <= DATA_RE_IN;
46
      memory_im(ADR_W) <= DATA_IM_IN;
47
      ADR_W := ADR_W + 1;
48
      if ADR_W = SAMPLES*CHANNELS-1 then
49
        rdy_net <= '1';
50
      end if;
51
   
52
    elsif CLK='1' and READ_PIN='1' and rdy_net='1' then
53
      if ADR_R < SAMPLES*CHANNELS then
54
        DV <= '1';
55
        for i in CHANNELS-1 downto 0 loop
56
          DATA_RE_OUT(i) <= memory_re(ADR_R);
57
          DATA_IM_OUT(i) <= memory_im(ADR_R);
58
          ADR_R := ADR_R + 1;
59
        end loop;
60
      end if;
61
      
62
    elsif CLK='1' and ADR_R > SAMPLES*CHANNELS-1 then
63
        ADR_R := 0;
64
        DV <= '0';
65
    end if;
66
  end process;
67
  
68
  RDY <= rdy_net;
69
end behavioral;

Zur Funktion des Moduls:
Bei aktivem WRITE_PIN werden die Daten für Realteil und Imaginärteil 
taktweise eingelesen, bis der Speicher voll ist. Nach jedem Takt wird 
dazu die Schreibadresse um 1 erhöht. Das Einlesen der 8 verschiedenen 
Kanäle erfolgt sequenziell.
Bei aktivem READ_PIN werden die Daten für Realteil und Imaginärteil 
taktweise ausgelesen. Nach jedem Takt wird dazu die Leseadresse um 1 
erhöht. Das Auslesen der 8 verschiedenen Kanäle erfolgt parallel.

Zu den Definitionen:
1
subtype RAM_IN is sfixed(8 downto -8);
2
type RAM_OUT is array (integer range <>) of RAM_IN;
3
4
constant  DATA_WD        : integer := 12;
5
constant  CHANNELS       : integer := 8;
6
constant  SAMPLES        : natural := 1024;

Worin liegt hier mein Problem, dass die Synthese so lange dauert? Gibt 
es Lösungsmöglichkeiten?
Was ich bereits versucht habe ist, den RAM-Style in den 
Syntheseeinstellungen auf "Block" zu stellen, aber ohne Erfolg.

Vielen Dank schonmal und Grüße
Andy

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Andy schrieb:
> Meiner Meinung nach erzeuge ich allerdings einen Block-RAM
Niemals. Du hast ja nicht mal einen Takt im System!
Das ganze Ding ist ein Mega-Monster-Latch!

So wird kein Takt beschrieben, und der RST fehlt in der Sensitivliste 
(eigentlich nocht viel mehr, aber das nur weil fehlerhafterweise der 
Takt keiner ist...).
Weil 'event fehlt ist hier nirgends ein Takt:
1
    if (RST='1') then
2
    
3
    elsif CLK='1' and WRITE_PIN='1' then    
4
   
5
    elsif CLK='1' and READ_PIN='1' and rdy_net='1' then
6
      
7
    elsif CLK='1' and ADR_R > SAMPLES*CHANNELS-1 then

Das hier ist dann im selben Zusammehang noch eine gut versteckte 
kombinatorische Schleife:
1
    elsif CLK='1' ... then    
2
       ADR_W := ADR_W + 1;
Siehe 
http://www.lothar-miller.de/s9y/archives/42-Kombinatorische-Schleifen.html

> Gibt es Lösungsmöglichkeiten?
Ja.
1. Simuliere das Design.
2. lies die Synthese-Warnungen und Meldungen. Wenn da was von 
"incomplete sensitivity list" steht, dann ist die Simulation falsch. 
Wenn da was von "latch" oder "combinatorial loop" steht, dann hast du 
Murks im Design.
3. verwende KEINE speichernden Variablen (die sind hier zwar nicht der 
Grund für den Fehler, aber sie verschleiern ihn zusätzlich).
4. mach die Fehler raus...  ;-)

: Bearbeitet durch Moderator
von Duke Scarring (Gast)


Lesenswert?

Wenn man mal die CHANNELS und die SAMPLES reduziert, sieht man die 
Misere:
1
    Found 32-bit comparator greater for signal <GND_9_o_ADR_R[31]_LessThan_69_o> created at line 72
2
    Found 32-bit comparator greater for signal <ADR_R[31]_GND_9_o_LessThan_81_o> created at line 81
3
    Summary:
4
  inferred   3 Adder/Subtractor(s).
5
  inferred 1222 Latch(s).
6
  inferred   2 Comparator(s).
7
  inferred 102 Multiplexer(s).
8
Unit <CAL_MATRIX_RAM> synthesized.
Jede Menge Latches...

Das Problem liegt hier:
1
    if (RST='1') then
2
    ...
3
    elsif CLK='1' and WRITE_PIN='1' then
4
    ...
5
    elsif CLK='1' and READ_PIN='1' and rdy_net='1' then
6
    ...
7
    elsif CLK='1' and ADR_R > SAMPLES*CHANNELS-1 then
8
    ...
BRAM mit Reset und Takteingängen für jeder Operation gibt's im FPGA 
nicht.

Bei meinen (B)RAMs sieht das so aus:
1
process
2
begin
3
    wait until rising_edge( clk);
4
5
    if memWriteEnable = '1' then
6
        ram( to_integer( unsigned( memAddr))) := memWrite;
7
        memRead <= memWrite;
8
    else
9
        memRead <= ram( to_integer( unsigned( memAddr)));
10
    end if;
11
end process;

Duke

von Falk B. (falk)


Lesenswert?

Man nehme Dr. Oetker, oder schlicht einen RAM aus dem Core Generator. 
Dann muss die Synthese auch nicht raten. Wenn es nach 24h immer noch 
nicht fertig war, ist das ein Bug in der Software, die hätte eigentlich 
viel eher fertig sein müssen oder selber mit einem Fehler abbrechen 
sollen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> oder schlicht einen RAM aus dem Core Generator.
Oder man instatiiert das RAM manuell, dann kann man es sogar noch nach 
Jahren und nach mehreren Updates pflegen und ändern.

> einen RAM aus dem Core Generator.
Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben 
hat, und kann z.B. nicht einfach parallel das ganze RAM woanders 
hinkopieren.

von Falk B. (falk)


Lesenswert?

@ Lothar Miller (lkmiller) (Moderator) Benutzerseite

>> oder schlicht einen RAM aus dem Core Generator.
>Oder man instatiiert das RAM manuell, dann kann man es sogar noch nach
>Jahren und nach mehreren Updates pflegen und ändern.

Das ist was für die alten Haudegen und Könner!

>> einen RAM aus dem Core Generator.
>Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben
>hat, und kann z.B. nicht einfach parallel das ganze RAM woanders
>hinkopieren.

Was? Gibts da kein memcpy() in VHDL?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Gibts da kein memcpy() in VHDL?
Doch schon, aber dann gibts kein RAM...  ;-)

von Christian R. (supachris)


Lesenswert?

Falk Brunner schrieb:
> Man nehme Dr. Oetker, oder schlicht einen RAM aus dem Core
> Generator.
> Dann muss die Synthese auch nicht raten. Wenn es nach 24h immer noch
> nicht fertig war, ist das ein Bug in der Software, die hätte eigentlich
> viel eher fertig sein müssen oder selber mit einem Fehler abbrechen
> sollen.

Naja, wenn ich die RAMs per VHDL beschreibe und mich an den XST User 
Guide halte, ist die Synthese viel schneller als wenn ich erst den IP 
Core erzeuge. Denn das dauert auch eine gefühlte Ewigkeit. Wenn man nur 
lokal arbeitet und den Core als Netzliste immer da hat, OK, aber wir 
bauen alle Designs aus den Quellen auf einem Server, da ist das ein 
deutlicher Unterschied.

von Falk B. (falk)


Lesenswert?

@ Christian R. (supachris)

>Naja, wenn ich die RAMs per VHDL beschreibe und mich an den XST User
>Guide halte, ist die Synthese viel schneller als wenn ich erst den IP
>Core erzeuge.

Jaja, Superchris ist superschnell. Mal sehen wie lange du brauchst, um 
Dual Port, Write enable Eingänge und Read before Write Eigenschaften 
etc. VHDL-gerecht zu beschreiben.

> Denn das dauert auch eine gefühlte Ewigkeit. Wenn man nur
>lokal arbeitet und den Core als Netzliste immer da hat, OK, aber wir
>bauen alle Designs aus den Quellen auf einem Server, da ist das ein
>deutlicher Unterschied.

Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?

Leute gibt . . .

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> Mal sehen wie lange du brauchst, um
> Dual Port, Write enable Eingänge und Read before Write Eigenschaften
> etc. VHDL-gerecht zu beschreiben.
>

und wenn jemand (ich z.B.) fast immer nur je einen dedizierten read und 
write Port braucht, das ganze voll synchron laeuft und mir 
read-before-write und Konsorten wurscht sind (weil ich z.B. in einem 1ms 
Testsystem arbeite und mir Jitter (neuer oder alter Wert) da egal sind 
oder ich es sogar ausschliessen kann)? Tja, dann kann ich dieses RAM in 
X, in A, und in L unveraendert verwenden...
Und viel schneller simulieren tuts auch noch.

>
> Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?
>

wenn ich die Plattform wechsle?
Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den 
Core-Generatoren rumzuschlagen...

von Christian R. (supachris)


Lesenswert?

Falk Brunner schrieb:
> Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?

Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.

Und das VHDL macht man ein mal mit ein paar Generics und dann muss man 
doch doch nicht immer tippen.

von Falk B. (falk)


Lesenswert?

@berndl (Gast)

>wenn ich die Plattform wechsle?

Täglich! Auf dem Bahnhof!

>Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den
>Core-Generatoren rumzuschlagen...

Dann geh angeln oder stricken. ;-)

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> @berndl (Gast)
>
>>wenn ich die Plattform wechsle?
>
> Täglich! Auf dem Bahnhof!
>
>>Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den
>>Core-Generatoren rumzuschlagen...
>
> Dann geh angeln oder stricken. ;-)

ist dir ne Laus ueber die Leber gelaufen?
(evtl. ein zickender Core-Generator? Duck und wech)

von Fpgakuechle K. (Gast)


Lesenswert?

Falk Brunner schrieb:

> Das ist was für die alten Haudegen und Könner!
>
>>> einen RAM aus dem Core Generator.
>>Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben
>>hat, und kann z.B. nicht einfach parallel das ganze RAM woanders
>>hinkopieren.
>
> Was? Gibts da kein memcpy() in VHDL?

O'Gott, memcpy() ist doch voll GOTO und voll unsicher. - Da gibt es 
besseres:
So ein FPGA besteht doch aus konfigurierbaren Silizium -> kann man das 
nicht zu ner passenden sandbox zusammenschieben ???

von berndl (Gast)


Lesenswert?

Christian R. schrieb:
> Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.

Und vor allem: Wie checkt man die Mausklicks die man machen muss ins SVN 
ein? Nee, lieber plain VHDL wenns geht...

von Fpgakuechle K. (Gast)


Lesenswert?

berndl schrieb:
> Christian R. schrieb:
>> Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.
>
> Und vor allem: Wie checkt man die Mausklicks die man machen muss ins SVN
> ein? Nee, lieber plain VHDL wenns geht...

Screenshoot von Coregen Masken sind gut für die Dokumentation von 
"Mouseclicks". Weniger selbsterklärend sind die log von coregen - tut 
aber auch seinen Zweck.

MfG,

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> Was? Gibts da kein memcpy() in VHDL?

Klar, funktioniert sogar genauso wie in einer CPU: Mittels einer 
State-Machine wird ein Eintrag eines RAMs X in ein anderes RAM Y 
kopiert. Geht halt schneller als in einer CPU. Und wo liegt jetzt dein 
Problem?

von Falk B. (falk)


Lesenswert?

@ berndl (Gast)

>> Was? Gibts da kein memcpy() in VHDL?

>Klar, funktioniert sogar genauso wie in einer CPU: Mittels einer
>State-Machine wird ein Eintrag eines RAMs X in ein anderes RAM Y
>kopiert. Geht halt schneller als in einer CPU. Und wo liegt jetzt dein
>Problem?

Nirgendwo. Allerdings hast du eins. Dein Ironiedetektor ist kaputt ;-)

von Christian R. (supachris)


Lesenswert?

berndl schrieb:
> Nee, lieber plain VHDL wenns geht...

Meien Rede. Klar, geht nicht immer, dann aber die Cores als xco Datei 
oder xci von Vivado. Nur dauert das Bauen dann halt länger.

von berndl (Gast)


Lesenswert?

Falk Brunner schrieb:
> Dein Ironiedetektor ist kaputt ;-)

ok, Entschuldigung, die Ironie hab' ich wirklich nicht gesehen. Ich 
dachte echt, du meinst das ernst...

von Fpgakuechle K. (Gast)


Lesenswert?

Christian R. schrieb:
> berndl schrieb:
>> Nee, lieber plain VHDL wenns geht...
>
> Meien Rede. Klar, geht nicht immer,


Vielleicht mal auflisten "wo es geht", "wo es geht aber nicht sinnvoll 
ist "und "wo Coregen/Instanzierung Makros die bessere Wahl sind":

Inference aus VHDL-Array:
-alle SinglePort (SP) RAM/ROMS, ausser man will die ROM/RAM's nicht über 
VHDL initialisieren (sondern aus *.ceo oder ähnlich)
--mgl. Ausnahme: SP-RAM mit BRAM Parity generierung

-alle DualPort (DP) RAM/ROMS mit gleicher datenbusbreite
--mgl. Ausnahme wie oben

Generierung aus Coregen:
-DP mit unterschiedlichen Datenbusbreiten
 (geht zwar auch als plain-VHDL ist aber dann Synthese-tool spezifisch)
-FIFO's und sonstiger krams mit pointer-handling,underun/overrun 
handling
-CIM

BTW: Bei Sicherheitskritischen Designs bspw Avionic ist inference nicht 
gern gesehen. Um die Stör-Komplexität "Optimimierende Tools" zu 
beherrschen, besteht man dort auf Instanzierte Makros.

MfG,

von Christian R. (supachris)


Lesenswert?

Da muss ich dir zustimmen, FIFOs und bus matching und/oder dual clock 
fifos tu ich mir auch nicht in VHDL an, das können die bei Xilinx 
besser. Aber single port und dual port mit gleicher Busbreite lässt sich 
ja sehr einfach und lesbar beschreiben.

von Andy (Gast)


Lesenswert?

Lothar Miller schrieb:
>> Gibt es Lösungsmöglichkeiten?
> Ja.
> 1. Simuliere das Design.
> 2. lies die Synthese-Warnungen und Meldungen. Wenn da was von
> "incomplete sensitivity list" steht, dann ist die Simulation falsch.
> Wenn da was von "latch" oder "combinatorial loop" steht, dann hast du
> Murks im Design.
> 3. verwende KEINE speichernden Variablen (die sind hier zwar nicht der
> Grund für den Fehler, aber sie verschleiern ihn zusätzlich).
> 4. mach die Fehler raus...  ;-)

Vielen Dank, ich habe das Modul entsprechend bearbeitet und es 
funktioniert auch. Das ganze Prozedere hab ich auch für das restliche 
Projekt durchgeführt und hab nun eine weitere Frage:

Code vorher:
1
manager : process (CLK, ND)
2
  
3
  variable i : integer := CHANNELS-1;
4
    
5
  begin 
6
7
8
    if RST='1' then
9
      ce_fft_net <= '1';
10
      i := CHANNELS-1;
11
    elsif ENABLE = '1' then
12
      if CLK='0' and ND='1' and ce_fft_net='1' then
13
        ce_fft_net <= '0';
14
        i := CHANNELS-1;
15
        re_in_net <= RE_IN(i);
16
        im_in_net <= IM_IN(i);    
17
      
18
19
      elsif i=1 and CLK='0' and ND='1' then
20
        ce_fft_net <= '1';
21
      end if;
22
      
23
24
      if CLK='0' AND ND='1' AND ce_fft_net='0' then
25
        i := i-1;
26
        re_in_net <= RE_IN(i);
27
        im_in_net <= IM_IN(i);
28
      end if;
29
    end if;
30
    
31
  end process manager;

Code nachher:
1
manager : process (CLK, ND, RST, ENABLE, ce_fft_net)
2
    
3
  begin 
4
  
5
    if RST='1' then
6
      ce_fft_net <= '1';
7
      i_manager <= to_unsigned(CHANNELS-1, 3);
8
    elsif CLK'event and CLK='0' and ENABLE = '1' then
9
      if ND='1' and ce_fft_net='1' then
10
        ce_fft_net <= '0';
11
        
12
        re_in_net <= RE_IN(to_integer(i_manager));
13
        im_in_net <= IM_IN(to_integer(i_manager));    
14
        i_manager <= i_manager-1;
15
        
16
      elsif i_manager=to_unsigned(0, 3) and ND='1' then
17
        ce_fft_net <= '1';
18
        i_manager <= to_unsigned(CHANNELS-1, 3);
19
      
20
      elsif ND='1' AND ce_fft_net='0' then
21
        re_in_net <= RE_IN(to_integer(i_manager));
22
        im_in_net <= IM_IN(to_integer(i_manager));
23
        i_manager <= i_manager-1;
24
        
25
      end if;
26
    end if;
27
    
28
  end process manager;
mit
1
 
2
signal i_manager            : unsigned(2 downto 0) := (others => '0');

Maximale Taktfrequenz vorher: 295 MHz
Maximale Taktfrequenz nachher: 167 MHz

Wie kann das sein? Wieso wird der Takt so stark verlangsamt?

von Klaus F. (kfalser)


Lesenswert?

Murks ist das immer noch.
Lies mal 
"http://www.xilinx.com/support/documentation/sw_manuals/xilinx13_1/xst_v6s6.pdf";

Sensitivity liste ist falsch, da gehört nur clock und reset hinein.
1
elsif CLK'event and CLK='0' and ENABLE = '1' then
ist auch nicht standard.
1
elsif falling_edge(CLK) then
2
   if ENABLE = '1' then
ist korrekter. Aber wenn's der XST frisst, wird er es schon korrekt 
umgesetzt haben.
Rein vom Übersichtlichkeit her würde ich die Adress-Generierung und den 
Zugriff auf das RAM trennen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Andy schrieb:
> Wieso wird der Takt so stark verlangsamt?
Vorher war wie gesagt nirgendwo im geposteten Codeabschnitt irgendein 
Takt involviert. Das war einfach ein Monsterlatch. Davon vermutlich die 
Hälfte wegoptimiert...

> Wieso wird der Takt so stark verlangsamt?
Evtl. weil jetzt richtige und korrekte Hardware implementiert wird. Und 
lass dich nicht täuschen: 170MHz sind schnell. Mach mal ein wenig was 
dazu und deine Taktfrequenz wird schnell nch unten gehen...

> Maximale Taktfrequenz vorher: 295 MHz
> Maximale Taktfrequenz nachher: 167 MHz
Wer sagt das? Besser gefragt: welcher Teil der Toolchain sagt das?

> Wieso wird der Takt so stark verlangsamt?
Der ungünstige und unnötige asynchrone Reset kann da seinen eigenen Teil 
dazu beitragen:
1
   if RST='1' then
2
       ce_fft_net <= '1';
3
       i_manager <= to_unsigned(CHANNELS-1, 3);
4
   elsif CLK'event and CLK='0' and ENABLE = '1' then
Siehe den Beitrag "Xilinx und die Resets" UND die darin 
enthaltenen Links!

Klaus Falser schrieb:
> Aber wenn's der XST frisst
Ja, der kann das (und mehr):
http://www.lothar-miller.de/s9y/categories/6-Clock-Enable

: Bearbeitet durch Moderator
von Andy (Gast)


Lesenswert?

Lothar Miller schrieb:
> Wer sagt das? Besser gefragt: welcher Teil der Toolchain sagt das?

Diese Werte habe ich dem "Timing Summary" entnommen.

Ich habe die Beiträge nun so verstanden man soll generell (für 
Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll 
nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so 
sagen?

Lothar Miller schrieb:
> unnötige asynchrone Reset
Wieso ist der Reset unnötig, das konnte ich nicht nachvollziehen?

Ich habe jetzt auch mit Hilfe von 
(https://www.mikrocontroller.net/articles/VHDL#Synthese) herausgefunden 
was mein Fehler ist, ich habe einmal einen CLK=1 und einmal CLK=0 
abgefragt... seit ich das geändert habe ist der Takt wieder bei max 295 
MHz.
Die Abfrage auf CLK=0 habe ich gemacht, da der verwendete IP-Core die 
Daten nicht synchron ausgibt, sie werden kurz nach der steigenden 
Taktflanke ausgegeben. Kann ich die Daten einfach mit 
(http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html)
1
signal ff1_out  : std_logic;
2
signal ff2_out  : std_logic;
3
:
4
process begin -- Einsynchronisieren
5
   wait until rising_edge(clk);
6
   ff1_out <= async_in;
7
   ff2_out <= ff1_out;
8
end process;
9
10
process begin 
11
   wait until rising_edge(clk);
12
   if (ff2_out = '1') then   -- Synchronisierten Eingang verwenden
13
   :   end if;   
14
end process;

synchronisieren?

Wieso gibt der IP-Core überhaupt die Daten asynchron raus?

von Olga (Gast)


Lesenswert?

Andy schrieb:
> Ich habe die Beiträge nun so verstanden man soll generell (für
> Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll
> nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so
> sagen?

Für Xillinx ja. Für Altera gilt (zumindest für Cyclone), dass 
asynchone Resets besser sind. Fazit: Du musst immer schauen, wie die 
Hardwareelemente des FPGAs aussehen, das du nutzen möchtest.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Andy schrieb:
> ich habe einmal einen CLK=1 und einmal CLK=0 abgefragt... seit ich das
> geändert habe ist der Takt wieder bei max 295 MHz.
Du hattest eigentlich immer die 300MHz. Nur, weil du mal die fallende 
und mal die steigende Flanke verwendet hast, hast du gleichzeitig die 
Taktfrequenz auch verdoppelt, weil die beteiligten Flipflops nur die 
halbe Periodendauer Ruhe haben.

Andy schrieb:
> da der verwendete IP-Core die Daten nicht synchron ausgibt, sie werden
> kurz nach der steigenden Taktflanke ausgegeben.
Das ist normal und die Grundlage jedes synchronen Design: es kommtnein 
Takt, daraufhin herrscht arge Unruhe im FPGA, bis die Kombinatorik die 
neuen Zustände ermittelt hat. Das muss rechtzeitig vor dem nächsten Takt 
fertig sein, denn dann werden die Zustände in die Flipflops übernommen 
und das Spiel beginnt von vorn.
Und genau so macht es der IP-Core: die Daten kommen ein paar ns nach dem 
Takt am Ausgang an.

Olga schrieb:
> Für Altera gilt (zumindest für Cyclone), dass asynchone Resets besser
> sind.
Sie sind nicht besser im Sinn von stabiler, sondern sie machen das 
Design schneller, weil Altera "nur" den asynchronen Modus der 
Flipflops kann. Für Lattice gilt dad auch...
Das darf man jetzt aber nicht so locker dahersagen. Auch Altera 
empfiehlt Sinnvollerweise, ein externes Resetsignal einzusynchonisieren. 
Denn der gefährliche Augenblick ist auch bei Altera der, bei dem der 
Reset inaktiv wird und das ganze Design loslaufen soll.
Und auf keinen Fall darf mit kombinatorischen Verknüpfungen auf den 
Reset losgegangen werden. Sonst sorgen Glitches und Spikes für seltsames 
Verhalten...

Fazit bleibt aber: für ein gutes Design muss man "seine" Hardware 
kennen.

: Bearbeitet durch Moderator
von Fpgakuechle K. (Gast)


Lesenswert?

Olga schrieb:
> Andy schrieb:
>> Ich habe die Beiträge nun so verstanden man soll generell (für
>> Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll
>> nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so
>> sagen?
>
> Für Xillinx ja. Für Altera gilt (zumindest für Cyclone), dass
> asynchone Resets besser sind. Fazit: Du musst immer schauen, wie die
> Hardwareelemente des FPGAs aussehen, das du nutzen möchtest.

Das Problem bei Xilinx ist das die beiden Setz/rücksetzeingänge der FF 
entweder asynchron oder synchron benutzt werden können, aber nicht 
beides gleichzeitig. Ein FF mit asynchronen Clear kann nur noch als D-FF 
(evtl. auch T-FF) konfiguriert werden das heisst synchrones 
Setzen/rücksetzen muß durch zusätzliche Logik vor dem D-Eingang 
nachgebaut werden. Das macht das design langsamer und größer.

Die entsprechende AN findet man by Xilinx mit den Such begriff "Dont't 
mix you drinks"
http://www.xilinx.com/support/documentation/white_papers/wp275.pdf S.5

Bei der Gelegenheit sollte man auch nachdenken, ob man den Reset an 
diesem FF wirklich braucht. manchmal kann man komplett darauf verzichten 
(Schieberegister) manchmal genügt der PowerUp Reset.

Die entsprechende AN findet man by Xilinx mit den Such begriff "Get 
smart about reset":
http://www.xilinx.com/support/documentation/white_papers/wp272.pdf

MfG,

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.