Forum: FPGA, VHDL & Co. Speed Optimierung !!!


von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hi @ all

Ich möchte mein Programm auf Speed optimieren. Bis jetzt läuft die
Schaltung mit ca. 86MHz. Da es eine recht kleine logische SChaltung
ist, möchte ich gern 120 bis 150 MHz erreichen. Als FPGA benutze ich
eine Xilinx VirtexE 300.

Noch ein paar Hinweise zum Verstehen des Quellcodes:

Es wird ein AD-Wandler angesteuert. Die Daten, die der AD-Wandler
erzeugt, werden über den Input "DATA_ADC" an den FPGA seriell
übertragen und im Signal "S_SPEICHER_A" gespeichert. Da der
AD-Wandler 4 führende Nullen erzeugt, die mich nicht interessieren,
fange ich erst mit dem Schieben des Registers "S_SPEICHER_A" an, wenn
das Signal "S_SHIFT_SPEICHER_A" 1 ist. Damit die Logik bei der
Synthese nicht wegoptimiert wird, lege ich eine belibiege Speicherzelle
des Registers "S_Speicher_A" an den Ausgang "OUTPUT".

Das gesamte Timing habe ich über das Ringregister "S_REG_A" erzeugt.
In diesem Ringregister befindet sich eine "1" sonst nur Nullen. Die
"1" benutze ich als Enable-Leitung für viele meiner Prozesse. Somit
kann ich das Timing für die CS-Leitung des AD-Wandlers erzeugen und
Strukturen erzeugen die nacheinander abgearbeitet werden. (ich denke
mal dies ist eine gute Lösung, da ich nicht ständig eine Zähler
abfragen muss)

Das CLR und GATE-Signal wird über ein anderes Modul erzeugt (siehe
Schaltplan im Anhang)

Bis jetzt habe ich noch keine Constraint-Optimierung vorgenommen, da
ich mich damit noch nicht so auskenne.

Ich bin für jeden Verbesserungsvorschlag dankbar.

MfG

Michael

von ups (Gast)


Lesenswert?

Zumindest passt der schaltplan zum source :-)
aber die 2 FF sollten doch möglich sein oder ? :-))))

von Jörn (Gast)


Lesenswert?

Hallo Michael,

ich habe gesehen, dass du in deinem Design manche FF mit der steigenden
und andere FF mit der fallenden Flanke von clk betreibst. Probier mal
alle FF in deiner Schaltung nur mit der steigenden Flanke zu
betreiben.

Ich hab den AD_Converter für einen Spartan2 durch die ISE gejagt.

Deine Version: 113 Mhz
Alle FF mit steigender Flanke : 216 Mhz, allerdings ohne Gewähr, dass
die Schaltung noch richtig funktionert.

Gruß Jörn

von Hagen (Gast)


Lesenswert?

Ich gebe Jörn recht, immer Clock auf einer der beiden Flanken abfragen.
In den meisten Fällen in denen ich Clock's auf beiden Flanken abfragte
halbierte sich die max. Taktfrequenz des kompletten Designs.

Du fragts Clock auf beiden Flanken ab um das Design synchron zu halten.
Habe ich auch immer so gehalten bis mir ein Licht aufging das dies
absolut unnötig mit einem guten synchronen Design ist. Du mußt nur
immer schön "parallel" denken ;)

Die asynchronen Reset/Clear Signale sollten ebenfalls immer nur auf ein
und den selben Pegel abgefragt werden. Sprich Low-Active-Reset immer auf
'0' abfragen. Diese "Faustformel" ist aber nicht so strikt wie die
der Clocks da ein NOT Gatter ja nicht die Welt untergehen lässt, aber
denoch immer ein Delay haben wird ;)

Gruß Hagen

von ups (Gast)


Lesenswert?

hmmmm grübel,
also der anhang beinhaltet bei mir lediglich den source
synchroner_clr.vhd und sonst nichts.... kein schaltplan etc...

von Jörn (Gast)


Angehängte Dateien:

Lesenswert?

@ups:
Es sind drei Dateien drin.

von Michael (Gast)


Lesenswert?

Erst einmal Danke für Eure Mühe. Das mit der Clock-Flanke habe ich auch
schon überlegt. Ich wollte nur immer auf Sicherheit arbeiten, damit es
auch wirklich funktioniert.

Wenn ich das Ringregister mit der ansteigenden Clock-Flanke schiebe und
gleichzeitig mit der ansteigenden Clock-Flanke den Zustand der '1'
abfrage, dann habe ich das immer für sehr unsicher gehalten. Deshalb
benutze ich zwei unterschiedliche Flanken.

Kann es dabei zu Fehlern kommen?

Grüsse

Michael

von Sven Johannes (Gast)


Lesenswert?

Moin...

ohauerha.... warum machst du dir übernahupo die Mühe sensitivity Listen
zu schreiben? Dein Design ist ja zu 100% asynchron.

Die Software kann da nichts optimieren und vermutlich auch keinerlei
Ausagen übe die Geschwindigkeit machen. Alles Zeiten müssen gegen drei
mögliche "Takte" gesprüft werden und raus kommt der Worst-Case.

Baue das Ding mal komplett in ein synchrones Design um, das wird
automatisch schneller, wenn der Chip das kann.

--
 Sven Johannes

von Michael (Gast)


Lesenswert?

HAHAHA selten so gelacht.

Bevor man so einen Komentar schreibt sollte man besser erst mal den
Quellcode lesen. Ich benutze nur CLK-Flanken um Ereignisse
auszulösungen und das ist in meinen Augen ein synchrones Design oder
habe ich da was falsch verstanden? Der Reset wird auch synchron
ausgeführt (siehe Datei synchroner CLR)

Wenn Du meinst das es immer noch ein asynchrones Design, dann kannste
ja mal einen Vorschlag für ein synchrones Design machen.

Grüsse Michael

von Sven Johannes (Gast)


Lesenswert?

Moin...

Bitte leiser lachen.

Deine sens Listen beinhalten nicht nur CLK => die Software MUSS also
die anderen Signale berücksichtigen => wie hats du die Constraints
gesetzt?

process (CLR,CLK,GATE)

begin
   if (CLR = '1' or GATE = '0') then
      CS_ADC <= '1';
   elsif (CLK'event and CLK = '1') then
      CS_ADC <= S_REGA(0);
   end if;
end process;

Das ist der Reset in deinem Steurteil. Der ist nun 100%ig async. Warum
dröselst du DAVOR noch eine Instanz die das sysnchronisieren soll? Oder
interpretiere ich das jetzt nicht im Sinne des Erfinders?

Die Synthese Software weiß davon nichts und muss hier vom
"worst-Case" ausgehen. Ich bin sicher das da einiges an
Geschwindigkeit liegenbleibt.

Nebenbei: rising_edge(clk) ist eigentlich die Abfrage für die steigende
Flanke es Taktes wenn std_logic verarbeitet wird. Das Ding mit event und
=1 ist zwar verbreitet und funktioniert zu 99%, aber da schreibt Einer
vom Anderen ab.

--
 Sven Johannes

von Hagen (Gast)


Lesenswert?

@Sven:

>Nebenbei: rising_edge(clk) ist eigentlich die Abfrage für die
> steigende Flanke es Taktes wenn std_logic verarbeitet wird.
> Das Ding mit event und =1 ist zwar verbreitet und funktioniert
> zu 99%, aber da schreibt Einer vom Anderen ab.

Kannst du dies bitte genauer ausführen ? Nach meinen Informationen
sollte man rising_edge() eben nicht benutzen da das nur für die
Simulation taugen soll und eben nicht für die Synthese. Das liegt daran
das einige Bibliotheken innerhalb von rising_edge() zusätzlich noch
Clock'Last_Event abfragen und das ist nicht synthetisierbar.

Bitte um Aufklärung.

Gruß Hagen

von FPGA-User (Gast)


Lesenswert?

rising_edge(clk) / falling_edge(clk) funktioniert bei
mir immer für die Synthese, m.E. ist das VHDL-93,

clk'EVENT und clk='1' ist VHDL-87 - oder liege ich da falsch?

von Hagen (Gast)


Lesenswert?

es gibt aber Implementierungen die so lauten

clk'EVENT und clk='1' and clk'LAST_VALUE = '0'

siehe in PACKAGE std_logic_1164

   FUNCTION rising_edge  (SIGNAL s : std_ulogic) RETURN BOOLEAN IS
    BEGIN
        RETURN (s'EVENT AND (To_X01(s) = '1') AND
                            (To_X01(s'LAST_VALUE) = '0'));
    END;

und irgendwo habe ich gelesen das s'LAST_VALUE nicht synthetisierbar
sein soll.

Ich frage ja gerade deshalb weil sich anscheinend die Meinungen
unterscheiden ?

Gruß Hagen

von Sven Johannes (Gast)


Lesenswert?

Moin...

Hatte auch noch nie Probleme, die Definition von VHDL87 kenne ich
allerdings nicht genau.

Die Abfrage von clk_event und =1 produziert immer dann Murks wenn der
Wechsel zum Beispiel von X,U oder Z nach 1 erfolgt. Ok, bei Takten ist
das seltener aber viele Leute fragen ja auch Signale ab.

--
 Sven Johannes

von high_speed (Gast)


Lesenswert?

Hallo

Warum soll „’LAST_VALUE“ nicht synthesefähig sein?
Hier mal 3Versionen, die alle mit Quartus II synthetisiert worden
sind.
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.std_logic_unsigned.all;
4
5
entity Test_Con is
6
  port( CLK1, CLK2, CLK3 : in std_logic;
7
        RES1, RES2, RES3 : in std_logic;
8
      Q1: out std_logic_vector (15 downto 0);
9
      Q2: out std_logic_vector (15 downto 0);
10
      Q3: out std_logic_vector (15 downto 0));
11
end Test_Con;
12
13
architecture verhalten of Test_Con is
14
signal QINT1: std_logic_vector (15 downto 0);
15
signal QINT2: std_logic_vector (15 downto 0);
16
signal QINT3: std_logic_vector (15 downto 0);
17
begin
18
19
-- 1. Version:
20
process(CLK1, RES1)
21
begin
22
   if RES1 = '1' then
23
      QINT1 <= (others => '0');
24
   elsif CLK1'event and CLK1 = '1' then
25
      QINT1 <= QINT1 +1;
26
   end if;
27
end process;
28
29
-- 2. Version:
30
process(CLK2, RES2)
31
begin
32
   if RES2 = '1' then
33
      QINT2 <= (others => '0');
34
   elsif CLK2'event and CLK2'last_value = '0' then
35
      QINT2 <= QINT2 +1;
36
   end if;
37
end process;
38
39
-- 3. Version:
40
process(CLK3, RES3)
41
begin
42
   if RES3 = '1' then
43
      QINT3 <= (others => '0');
44
   elsif CLK3'event and CLK3 = '1' and CLK3'last_value = '0'
45
then
46
      QINT3 <= QINT3 +1;
47
   end if;
48
end process;
49
50
Q1 <= QINT1;
51
Q2 <= QINT2;
52
Q3 <= QINT3;
53
54
end verhalten;

MfG
Holger

von FPGA-User (Gast)


Lesenswert?

XST scheint Probleme mit 'LAST_VALUE zu haben, offenbar aber
nicht mit rising_edge(), falling_edge() :
(von der XILINX Web-Seite)

Problem Description:

Keywords: compile, constant

Urgency: Standard

General Description:
XST creates incorrect logic when using the 'last_value VHDL
attribute:
if H02'event and (H02='1') and (H02'LAST_VALUE = '0') then

The sample design is in the bugcases directory, which is an FF, but
compiled incorrectly as constant logic.

Solution 1:

The work around is to use the rising_edge function instead:

if rising_edge(H02) then

This problem has been fixed in the latest 7.1i Service Pack available
at:
http://support.xilinx.com/xlnx/xil_sw_updates_home.jsp
The first service pack containing the fix is 7.1i Service Pack 2.

von Hagen (Gast)


Lesenswert?

das Standard Package "std_logic_1164" von Altera und Xilinx benutzt
aber rising_edge() auf std_ulogic Datentypen so wie oben gepostet
'LAST_VALUE.

Ich kann mich nur dunkel errinnern das ich damit Probleme hatte und auf
der Suche nach dem Fehler stieß ich auf eine Bemerkung (glaube
OpenCores.org) das man rising_edge() nicht benutzen sollte.

Jetzt wissen wir's ja ganz genau, danke FPGA_User.

Gruß Hagen

von Michael (Gast)


Lesenswert?

Ich habe schon immer "CLK'event and CLK = '1'" benutzt und bis
jetzt noch keine Probleme damit gehabt. Die Funktion
"rising_edge(...)" macht doch auch nichts anderes als das Signal mit
dem CLK-Eingang des Logikelements zu verbinden.

Soll ich denn nun "rising_edge" benutzten und ist damit ein Riskio
verbunden?

Ich habe jetzt alles auf eine CLK-Flanke angepasst. Siehe da ich kann
198MHz als maximale Frequenz benutzen. Jetzt muss ich nur noch mal eine
Simulation mach und alles überprüfen.

Ich habe jetzt mal die sensitivity Listen abgeändert und
"rising_edge" verwendet.

Den Reset ist jetzt in jeden Prozess sync. Dies hat aber keinen
Geschwindigkeitsvorteil gebracht. Ich persönlich finde, dass der async.
Reset von der programmierweise und lesbarkeit wesentlich übersichtlicher
ist.


-- sync. Reset
process (CLR,CLK,GATE)

begin
   if(rising_edge(CLK))then
      if(CLR = '1' or GATE = '0')then
         S_SHIFT_SPEICHER_A <= '0';
      elsif(S_REGA(5) = '1' or S_REGA(17) = '1')then
         S_SHIFT_SPEICHER_A <= NOT S_SHIFT_SPEICHER_A;
      end if;
   end if;
end process;


-- async. Reset
process (CLR,CLK,GATE)

begin
   if(CLR = '1' or GATE = '0')then
      S_SHIFT_SPEICHER_A <= '0';
   elsif(rising_edge(CLK))then
      if(S_REGA(5) = '1' or S_REGA(17) = '1')then
         S_SHIFT_SPEICHER_A <= NOT S_SHIFT_SPEICHER_A;
      end if;
   end if;
end process;


Ist denn meine sync. Variante überhaupt richtig?

Grüsse Michael

von Sven Johannes (Gast)


Lesenswert?

Moin...

Na bitte. Ist die Geschwindigkeit nach P&R ermittelt oder irgendwo
davor. Die Angaben nach Synthese oder Map sind nur ANhaltspunkte.

Der synchrone Reset sollte so funktionieren, ich würde wohl noch die
anderen Signale aus der Sens. Liste nehmen

--
 Sven Johannes

von FPGA-User (Gast)


Lesenswert?

@Michael
kann sein, dass es mit dem async. Reset für Dich besser
lesbar ist, aber Fakt ist, es kommen unterschiedliche
Ergebnisse dabei raus .

Nehmen wir mal Dein Bespiel :
2 Signale GATE und CLR sind die Ausgänge von 2 FFs, die am
CLK hängen. Bis dahin ist alles synchron.

Die Signale GATE und CLR werden nun log. verknüpft und führen
zum async. Reset eine Registers von sagen wir mal 10 bit Breite.
Aufgrund des Routings wird dieses Reset-Signal an jedem der 10
Flip-Flops zu einem anderen Zeitpunkt ankommen (Differenz vielleicht
1 ns max.)
Ich würde bezweifeln, dass diese Pfade beim XST durch ein
einfaches Clock-Constraint abgedeckt sind. Möglicherweise
ist das Reset-Signal gerade aktiv, wenn der Registerinhalt
irgendwo anders gespeichert werden soll -> Datenmüll.

Wenn mit GATE und CLR ein sync. Reset realisiert wird, bist
Du auf der sicheren Seite, da die Signale jetzt auf den
Daten-Eingang des FFs wirken und nun ein simples Clock-Constraint
von z.B. 100 MHz sicherstellt, dass die Schaltung bei 100 MHz
eben immer funktioniert.

von Michael (Gast)


Lesenswert?

OK habe jetzt nur noch die CLK Leitung in der sensitivity Liste, da
jetzt ja nur noch die Clock-Leitung Einfluss auf den Prozess hat.

So jetzt habe ich mal eine härtere Nuss gepostet. Ziel des ganzen ist
es eine Übereinstimmung eines Musters in einem Register zu finden.
"S_MAX_ANZ_EINSEN_A" gibt an wie viele Übereinstimmungen zwischen den
gesuchten Muster und dem Register gefunden wurden.

Während Gate '1' wird die Analyse durchgeführt. Ist Gate = '0' dann
wird das Ergebnis über eine RS232-Interface an den PC übertragen.
Deshalb darf das Signal "Valid_Peak_A" nicht mit dem Gate
zurückgesetzt werden. Dadurch entsteht ein sehr unangenehme Situation.

1. Hat jemand einen Verbesserungsvorschlag wie das ganze vereinfacht
oder optimiert werden kann?

2. Wie kann ich die Enable-Leitung der Logikelemente "elsif(S_REGD(8)
= '1' and S_STOP_SEARCH_A = '0' and S_STOP ='0')then" weiter
optimieren?

process (CLK)

begin
   if(rising_edge(CLK))then
     if(CLR = '1' or GATE = '0')then
        if(CLR = '1')then
         S_MAX_ANZ_EINSEN_A <= "000011";
         FIRST_POS <= (others => '0');
         S_FIRST_PASS <= '0';
         VALID_PEAK_A <= '0';
         S_STOP <= '0';
      elsif(GATE = '0')then
         S_MAX_ANZ_EINSEN_A <= "000011";
         S_FIRST_PASS <= '0';
         S_STOP <= '0';
      end if;
   elsif(S_FIRST_PASS = '0')then
      VALID_PEAK_A <= '0';
      S_FIRST_PASS <= '1';
   end if;

   elsif(S_REGD(8) = '1' and S_STOP_SEARCH_A = '0' and S_STOP
='0')then
      if(S_EINSEN_GESAMT_A >= S_MAX_ANZ_EINSEN_A)then
         S_MAX_ANZ_EINSEN_A <= S_EINSEN_GESAMT_A;

         FIRST_POS <= POSITION - "000000010100";

         VALID_PEAK_A <= '1';

         S_STOP <= '1';
      end if;
   end if;
end process;


Grüsse Michael

von Hagen (Gast)


Lesenswert?

Verstehe ich dich richtig, Vektor A = "1011" und B = "0001",
rauskommen sollte 1 ? Dann ist BitCount(A and B) deine Antwort, hier im
Forum gibts eine BitCount() die mit 56 LE's kombinatorisch arbeitet,
ca. 10ns Delay. Thread "Eines im Vektor zählen".

Gruß Hagen

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.