www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Kombinatorische Signale über mehrere Entities routen nicht möglich?


Autor: Steffen Hausinger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe mir folgendes Programm geschrieben: In Entity 1 werden in einem 
Prozess die Signale A_OE und A_CE und-verknüpft. Das Ergebnis 
A_Request wird an einen Prozess in Entity 2 geleitet. Dort wird es 
ausgewertet und, je nach Ergebnis, der Vektor X_Routing zu "00" oder 
"11" gesetzt und zurück an Entity 1 gesendet.

Dort findet nun in einem dritten Prozess die Auswertung statt: Ändert 
sich der Vektor von "00" auf "11" oder umgekehrt, soll im späteren 
Design eine Reaktion erfolgen. Für's Debugging befülle ich damit aber 
ersteinmal nur meine Testvektoren.

Hier meine Beschreibung:
-- ####################################################
-- ##################### Entity 1 #####################
-- ####################################################

  -- Kombinatorischer Prozess
  -- Nimmt das Eingangssignal A_OE und A_CE und verknüpft es.
  Check_Request : process(A_OE, A_CE)
  begin
    A_Request <= '0';                    -- Pauschal keine Anforderung annehmen
    if A_OE = '0' and A_CE = '0' then    -- Liegt doch eine Anforderung vor, ...
      A_Request <= '1';                  -- ...dies signalisieren und Routing anfordern
    end if;                              --
    
  end process;


  
  -- Getakteter Prozess
  -- Nimmt das Zielsignal und wertet es aus.
  debug : process(CLK_16MHz)
    variable Last_State : STD_LOGIC_VECTOR(1 downto 0);
  begin
    if rising_edge(CLK_16MHz) then
      
      TestVec(0) <= '0';
      TestVec(1) <= '0';
      TestVec(2) <= '0';
      
      if X_Routing = "00" then          -- Wird aktuell Routing "00" angefordert, ...
        TestVec(0) <= '1';              -- ...Kanal 0 setzen
      end if;
      if Last_State = "00" then         -- Wurde bei der letzten Flanke Routing "00" angefordert, ...
        TestVec(1) <= '1';              -- ...Kanal 1 setzen
      end if;
      if X_Routing /= Last_State then   -- Wurde das Routing geändert, ...
        TestVec(2) <= '1';              -- ...Kanal 2 setzen
      end if;
      
      Last_State := X_Routing;          -- Aktuelles Routing für nächste Flanke merken
      
    end if;
  end process;

und
-- ####################################################
-- ##################### Entity 2 #####################
-- ####################################################

  -- Kombinatorischer Prozess
  -- Wertet das Signal aus.
  Review_Request : process(A_Request)
  begin
    if A_Request = '1' then
      X_Routing <= "00";
    else
      X_Routing <= "11";
    end if;
  end process;


Nur leider funktioniert das Design so nicht. Offenbar hat er Probleme, 
über die Grenzen einer Entity hinweg ein kombinatorische Signal zu 
leiten. Das Bild im Anhang habe ich mit einem Logikanalysator 
aufgenommen. Obwohl der Vektor an den rot markierten Stellen 
zweifelsohne von "11" auf "00" wechselt, wird dies nicht erkannt. Die 
Abtastfrequenz ist natürlich lang genug (ca. 3x T_Signal)

Warum ist das so? Kann man das über die Entity-Grenzen hinweg kein 
kombinatorisches Signal senden? Wenn nein, warum nicht? Sporadisch 
funktioniert es ja. Aber warum denn nicht permanent?!

Grüße
Steffen

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Hausinger schrieb:
> Kann man das über die Entity-Grenzen hinweg kein
> kombinatorisches Signal senden?
Doch, das geht problemlos.

> Warum ist das so?
Sind die beiden Signale A_OE und A_CE asynchron zum FPGA-Takt?
(es sieht so aus, aber leider ist genau der nicht mit im Screenshot)
Dann wundert mich das nicht, du hast ganz einfach ein asynchrones 
externes (und dazu noch kombinatorisch verknüpftes) Signal nicht 
einsynchronisiert. Und dann wird u.U. der Vergleicher (if X_Routing /= 
Last_State then) nicht mehr rechtzeitig fertig. Blöderweise bekommen die 
beiden FFs bei der Zuweisung (Last_State := X_Routing) den neuen Zustand 
aber offenbar schon mit... :-/
Fazit: du solltest aus diesem Kombinatorikpfad einen Takt komplett 
heraushalten, oder aber die Signale standesgemäß einsynchronisieren.
Zum Hintergrund das hier:
http://www.lothar-miller.de/s9y/archives/64-State-...
Dieses Beispiel passt hier wie die Faust aufs Auge, denn du hast 
eigentlich eine Statemachine (Last_State), die nicht richtig reagiert...

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Sind die beiden Signale A_OE und A_CE asynchron zum FPGA-Takt?

Ja, das sind sie. Ich war mir über die Problematik gar nicht bewusst: 
Bisher ging ich davon aus, dass die Synchronisation eben in meinem 
ersten getakteten Prozess stattfindet. Nur eben nicht über die 
Eingangssignale A_OE und A_CE, sondern über X_Routing. Das 
kombinatorische Signale X_Routing bleibt aber konstant, so dachte ich.

Was muss ich jetzt machen? A_OE und A_CE über einen getakteten 
Prozess einsynchronisieren und zu A_OE_sync und A_CE_sync wandeln? 
Es gibt in FPGAs doch diese speziellen(?) "Ausgangs-FF" für synchrone 
Ausgangssignale. Gibt es die auch für Eingänge? Wenn ja, wie muss ich es 
beschreiben, damit sie verwendet werden? Es geht um einen Spartan 3E.

Grüße
Steffen

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Hausinger schrieb:
> Bisher ging ich davon aus, dass die Synchronisation eben in meinem
> ersten getakteten Prozess stattfindet.
Da hast du dir selber Sand in die Augen gestreut. Für den Synthesizer 
gibt es das Signal "X_Routing" eigentlich gar nicht. Der optimiert sich 
da aus seiner internen Wahrheitstabelle selber was zusammen.

> Es gibt in FPGAs doch diese speziellen(?) "Ausgangs-FF" für synchrone
> Ausgangssignale. Gibt es die auch für Eingänge?
Nein.
Aber das ist gar nicht dein Problem...

> Was muss ich jetzt machen?
Du mußt
1. die Beschreibung so ändern, dass die Signale eingetaktet werden:
  -- Getakteter Prozess
  -- Nimmt das Zielsignal und wertet es aus.
  debug : process(CLK_16MHz)
    variable Very_Last_State : STD_LOGIC_VECTOR(1 downto 0);
    variable Last_State : STD_LOGIC_VECTOR(1 downto 0);
  begin
    if rising_edge(CLK_16MHz) then
      
      TestVec(0) <= '0';
      TestVec(1) <= '0';
      TestVec(2) <= '0';
      
      if X_Routing = "00" then          -- Wird aktuell Routing "00" angefordert, ...
        TestVec(0) <= '1';              -- ...Kanal 0 setzen
      end if;
      if Last_State = "00" then         -- Wurde bei der letzten Flanke Routing "00" angefordert, ...
        TestVec(1) <= '1';              -- ...Kanal 1 setzen
      end if;
      if Very_Last_State /= Last_State then   -- Wurde das Routing geändert, ...
        TestVec(2) <= '1';              -- ...Kanal 2 setzen
      end if;
      
      Last_State := X_Routing;          -- Aktuelles Routing für nächste Flanke merken
      Very_Last_State := Last_State;
      
    end if;
  end process;

2. und dann bewerten, ob damit dein Design überhaupt klarkommt.
Denn mit dem Eintakten bekommst du automatisch Latency. Dein TestVec(2) 
kommt jetzt einen Takt später.

BTW: Ein Output Enable OE Signal dient idR. zur Umschaltung einer 
Busrichtung (Lesen). Das sollte daher direkt auf die Tristatetreiber des 
FPGAs gelegt werden. Sonst könntest du dir durch die erwähnte Latency 
einen Buskonflikt einhandeln...  :-o

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Hausinger schrieb:
> Sporadisch
> funktioniert es ja. Aber warum denn nicht permanent?!

Solche Aussagen kommen sehr häufig, wenn asynchrone Sachen nicht richtig 
behandelt werden :-) (BTDT)

Duke

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar

Würde es sich denn nicht anbieten einfach A_CE und A_OE 
einzusynchronisieren. Der Rest der komb. Logik ist dann ja auch 
synchron.

Also einfach ein :

signal a_oe_s : std_logic;
signal a_ce_s : std_logic;

process (clk, res)
begin
  if rising_edge(clk) then
    if res = '1' then
      a_oe_s <= '0';
      a_ce_s <= '0';
    else
      a_oe_s <= a_oe;
      a_ce_s <= a_ce;
    end if;
  end if;
end process;

Evtl. noch mit einem weiteren Einsynch-FF pro Leitung.
Müsste doch auch funktionieren oder nicht ?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rene Böllhoff schrieb:
> Müsste doch auch funktionieren oder nicht ?
Ja, das wird es auch tun.
Allerdings würde ich den Reset hier rauslassen, damit nicht unnötig 
Routingressourcen verbraucht werden. Und wehe, wenn dieser scheinbar 
synchrone Reset hier wieder an einen asynchronen Resettasterpin 
angeschlossen ist... ;-)

Autor: Steffen Hausinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, Reset habe ich völlig aus meiner Schaltung verbannt. Obwohl ich 
eine zeitlang nicht wusste, wie ich dann der Schaltung mitteilen soll, 
ab wann der DCM einen sauberen Takt liefert. Ich habe es schließlich mit 
der Einstellung "wait until lock goes high" (oder so ähnlich) gelöst.


Ich werde mich dann auch dafür entscheiden, A_OE und A_CE zu 
synchronisieren. Dann komme ich auch in anderen Prozessen gar nicht erst 
auf die Idee, die unsynchronisierten Varianten zu nehmen.


Lothar Miller schrieb:
> BTW: Ein Output Enable OE Signal dient idR. zur Umschaltung einer
> Busrichtung (Lesen). Das sollte daher direkt auf die Tristatetreiber des
> FPGAs gelegt werden. Sonst könntest du dir durch die erwähnte Latency
> einen Buskonflikt einhandeln...  :-o

Ich habe das zwar in einer StateMachine gelöst, weil auch noch weitere 
(externe) Treiber umgeschaltet werden müssen, aber das interessiert mich 
jetzt doch: wie lege ich das Signal direkt auf den Tristatetreiber des 
IOB? Macht die Synthese das automatisch, wenn ich etwas schreibe wie
if A_OE = '0' then
    Data_out <= (others=>'Z');
end if;

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen Hausinger schrieb:
> Macht die Synthese das automatisch, wenn ich etwas schreibe wie...
Ja. Aber du mußt hier sinnvollerweise noch ein wenig weiter vorn 
anfangen:
Bereits in der Top-Level-Entity muß dieser Bus, der ja ein 
bidirektionaler Datenbus vom und zum uC ist, als inout deklariert 
werden.

Und dann geht das so (mal von einem low-aktiven OE-Signal ausgegangen):
process (A_OE, FPGADataOut) begin
  if A_OE = '1' then  
    Datenbus_uC <= (others=>'Z');
  else 
    Datenbus_uC <= FPGADataOut;
  end if;
end process;

FPGADataIn <= Datenbus_uC;

Ich selber schreibe das lieber concurrent (ohne Prozess):
Datenbus_uC <= FPGADataOut when A_OE = '0' else (others=>'Z');
FPGADataIn <= Datenbus_uC;

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Und wehe, wenn dieser scheinbar synchrone Reset hier wieder an einen
>asynchronen Resettasterpin angeschlossen ist... ;-)

Mist. Ich sollte mich nicht immer angesprochen fühlen bei sowas. Ja ja. 
Ich änder meine 500 Prozesse ja schon ab um den Reset ebenfalls synchron 
zu machen :-)))

Aber da mal eben eine Offtopic frage zu dem Thema.
Und zwar du meintest das ein Asynchroner Reset u.u auch Probleme mit dem 
Routen des Designs geben kann. Ich habe bei meinem Audio-Projekt das 
Problem gehabt das ich einen 32x32bit Multiplier in einem Takt verwendet 
habe. Das braucht natürlich sehr viele Interconnects. Da die 32Bit sowie 
die 64Bit Pfade an mehreren stellen benötigt werden und durch Register 
dargestellt werden habe ich auch ein asynchronen Reset. Nun habe ich das 
Problem das der Router stellenweise nicht fertig wird weil er 2-6 
Leitungen nicht immer Routen kann (congestion on net xyz). Kann ein 
Synchroner Reset da vllt auch helfen das Routingproblem zu lösen ? Ich 
bin mir da nicht ganz sicher obwohl ich eher denke das das Design durch 
den 32x32Bit-Multiplizierer einfach zu vollgestopft ist und der Router 
daher nicht fertig wird.
Aber generell würde mich mal interessieren wieviele Ressourcen durch 
einen asynchronen Reset mehr verbraten werden als bei einem synchronen. 
Gibt es da erfahrungen ? Ist das abhängig von der Anzahl der FF's die 
asynchron resettet werden, grob nach dem Motto : pro async FF wird ein 
Slice zusätzlich "verschwendet" ?
Ich gebe dir recht das der asynchrone Reset eigentlich Mist ist, aber 
bei mir hats soweit immer funktioniert. Was nicht heißt das es gut war, 
das weiß ich selbst :)). Aber wieviele Ressourcen weniger würden durch 
einen synchronen Reset benötigt werden ? Ich meine das endet dann ja 
auch irgendwo in Laufzeit und benutzten Slices/Logik die dann für andere 
Dinge wieder frei werden würde/könnte.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rene Böllhoff schrieb:
> Aber generell würde mich mal interessieren wieviele Ressourcen durch
> einen asynchronen Reset mehr verbraten werden als bei einem synchronen.
Das beginnt schon ziemlich früh im Chip: direkt an den FFs...  :-o
Siehe den Beitrag "Re: Hardware mit VHDL "richtig" beschreiben."

Und sehr überaus lesenswert die beiden Xilinx Whitepaper
WP275 "Get your priorities right"
http://www.xilinx.com/support/documentation/white_...
WP272 "Get Smart About Reset: Think Local, Not Global"
http://www.xilinx.com/support/documentation/white_...

> Da die 32Bit sowie die 64Bit Pfade an mehreren stellen benötigt werden
> und durch Register dargestellt werden habe ich auch ein asynchronen Reset.
Wozu?

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rene Böllhoff schrieb:
> Aber generell würde mich mal interessieren wieviele Ressourcen durch
> einen asynchronen Reset mehr verbraten werden als bei einem synchronen.
> Gibt es da erfahrungen ?

Ich hatte mal die XST-Option async_to_sync ausprobiert. Bei manchen 
Designs wurden ein paar Slices eingespaart, bei anderen waren es ein 
paar Slices mehr. Das es sich signifikant auf timing/routing ausgewirkt 
hätte, kann ich nicht behaupten.

Aber das kann bei anderen Designs natürlich anders aussehen...

Duke

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Duke Scarring schrieb:
> Das es sich signifikant auf timing/routing ausgewirkt hätte, kann ich
> nicht behaupten.
Das hätte eigentlich ich auch erwartet. In einem "normalen" Design 
mitteln sich die Vorteile heraus. Es geht eher darum, darüber 
nachzudenken, ob überhaupt ein Reset nötig ist...

Autor: Rene B. (themason) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar

Die betrachtung in welchen Prozessen ich einen Reset brauche oder nicht 
müsste ich auch nochmal für die Designs machen. Ist einfach eine Art 
Mechanismus erstmal einen Reset vorzusehen. Meist "rüste" ich den Reset 
nach wenn ich in der Simulation sehe das Signale undefiniert sind. Das 
ich aber in z.b. einem Multiplizierer mit nachgeschaltetem Register 
meist keinen Reset brauche da beim nächsten Takt ja ohnehin ein gültiges 
Datenwort (gültige Eingangsworte vorausgesetzt) anliegt, es sei denn ich 
hab bei dem Multiplizierer ein Enable, dann könnte (bzw wird) das 
Ausgangswort ja undefiniert sein, solange wie nicht einmal ein Enable 
gekommen ist. (Hoffe ich konnte das nun richtig erklären :-))

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.