mikrocontroller.net

Forum: FPGA, VHDL & Co. Division mit verschiedenen Werten


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Arbeite gerade an einen Design in dem ich abhängig von einen Counterwert 
2 verschiedene Werte zusammenaddieren muss und diese dann durch 2 
Rechnen muss. Eigentlich wäre dafür ja eine shift operation perfekt 
allerdings ist der Wert ein signed. Daher mache ich eine normale 
division durch 2. Nun ist meine Frage ob es besser ist das ich die zwei 
werte zuerst zusammenzähle und in eine Variable schreibe die ich nacher 
dividiere oder kann ich für jeden fall einen mittels if abfrage 
unterscheiden und in jeden zweig eine Division machen? Was ist vorallem 
in Bezug auf synthese besser?

Fall 1:

if i = 1 then
  result <= ((zahl1 + zahl2) / 2)
if i = 2 then
  result <= ((zahl1 + zahl3) / 2)
if i = 2 then
  result <= ((zahl2 + zahl3) / 2)
end if

oder

Fall 2:

if i = 1 then
  tmp := ((zahl1 + zahl2) / 2)
if i = 2 then
  tmp := ((zahl1 + zahl3) / 2)
if i = 2 then
  tmp := ((zahl2 + zahl3) / 2)
end if
result <= (tmp / 2)

Vielleicht weiß jemand von euch welcher der beiden Fälle besser für die 
HW.

MFG Gast

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simulier und synthetisier es doch einfach mal und guck was hinterher 
rauskommt.

DAS könnte jedenfalls interessant werden ;) :

if *i = 2* then
  tmp := ((zahl1 + zahl3) / 2)
if *i = 2* then
  tmp := ((zahl2 + zahl3) / 2)

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das die if abfrage zweimal 2 abfragt ist natürlich ein tippfehler. Kommt 
durch copy and paste. Gibt es sonst eine Möglichkeit die Division in 
VHDL zu machen oder ist das eh der Standard weg um einen signed typ zu 
dividieren?

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Was ich vorher vergessen habe die Zahlen Zahl1, Zahl2 und Zahl3 sind 
std_logic_vector die mit Hilfe von signed fürs rechnen umgewandelt 
werden. Das Ergebnis ist wieder ein std_logic_vector. tmp ist eine 
Variable die ebenfalls std_logic_vector ist. Kann ich davon ausgehen das 
beide Varianten das Ergebnis innerhalb eines Taktzyklus haben oder kann 
es da auch unterschiede geben. Suche eigentlich die Variante die am 
wenigsten Logic braucht.
DANKE

Hatte noch einen Fehler in Fall 2

Fall 2:

if i = 1 then
  tmp := (zahl1 + zahl2)
if i = 2 then
  tmp := (zahl1 + zahl3)
if i = 3 then
  tmp := (zahl2 + zahl3)
end if
result <= (tmp / 2)


MFG Gast

Autor: Der Besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmmm...
tmp := (zahl1 + zahl2)

Pass auf, dass tmp breit genug ist, sonst bekommst du schnell einen 
Überlauf bei größeren Summanden.

Das beste Syntheseergebnis bekommst du meist nur durch testen raus.
Kannst gerne posten, was die Synthese dir als Resultat ausgibt und dann 
kann man ans optimieren denken. Jedes Synthesewerkzeug hat seine 
"Eigenheiten".
Probieren geht über studieren.

Der Besucher

Autor: dito (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn es sich um signed-Division handelt und du möchtest das 
syntethisieren, dann nimm lieber dann shifte lieber (arithmetisch 
natürlich - dann ist das kein Problem).

Siehe mein Posting von letzter Wochen:
Beitrag "right_shift und "/" liefern unterschiedliche Ergbnisse"

Synthesiere doch einfach mal beide Varianten (also Shift und Division) 
und stell deine Syntheseergebnisse hier rein. Würde mich mal 
interessieren...

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Habe das ganze nun mal getestet und folgende ergebnisse bekommen

Fall 1(division in jeden Zweig)

 Minimum period: 14.499ns (Maximum Frequency: 68.970MHz)

 Number of Slices:                      834  out of  20480     4%
 Number of Slice Flip Flops:            305  out of  40960     0%
 Number of 4 input LUTs:               1596  out of  40960     3%
 Number of IOs:                         175
 Number of bonded IOBs:                 132  out of    333    39%
 Number of GCLKs:                         1  out of      8    12%

Fall 2(einmalige Division am Ende)

 Minimum period: 16.059ns (Maximum Frequency: 62.272MHz)

 Number of Slices:                      820  out of  20480     4%
 Number of Slice Flip Flops:            343  out of  40960     0%
 Number of 4 input LUTs:               1576  out of  40960     3%
 Number of IOs:                         175
 Number of bonded IOBs:                 132  out of    333    39%
 Number of GCLKs:                         2  out of      8    25%

Fall 3 (shiften um 1 nach rechts und oberstes Bit setzen damit negative 
Werte richtig sind und kleinstes Bit setzen damit richtig abgerundet 
wird ei negativen Werten)

 Minimum period: 14.534ns (Maximum Frequency: 68.802MHz)

 Number of Slices:                      871  out of  20480     4%
 Number of Slice Flip Flops:            341  out of  40960     0%
 Number of 4 input LUTs:               1673  out of  40960     4%
 Number of IOs:                         175
 Number of bonded IOBs:                 132  out of    333    39%
 Number of GCLKs:                         2  out of      8    25%

Welches würdet ihr nun als beste Variante bezeichnen. Eigentlich doch 
die Variante mit der Division in jeden Zweig oder?

MFG Gast

Autor: Marc H. (maah)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wuerde die if statements noch durch ein switch/case ersetzen. Die if 
statements verursachen je nach Synthese einen Priority-Tree vor den 
Arithmetik-Einheiten, den Du nicht(?) brauchst. switch/case erzeugt 
einen Balanced-Tree und erlaubt einfacheres Ressource-Sharing von 
Addierern und Dividierern.

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

Bewertung
0 lesenswert
nicht lesenswert
 :
 Number of Slices:                      834  out of  20480     4%
 Number of Slice Flip Flops:            305  out of  40960     0%
 Number of 4 input LUTs:               1596  out of  40960     3%
 :
Da ist aber offenbar noch einiges mehr im Spiel...


Hier meine Erkenntnisse:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity SignalVsVariable is
    Port ( z1 : in  STD_LOGIC_VECTOR (7 downto 0);
           z2 : in  STD_LOGIC_VECTOR (7 downto 0);
           z3 : in  STD_LOGIC_VECTOR (7 downto 0);
           res : out STD_LOGIC_VECTOR (7 downto 0);
           s  : in  STD_LOGIC_VECTOR (1 downto 0));
end SignalVsVariable;

architecture Behavioral of SignalVsVariable is
signal zahl1 : integer range -128 to 127;
signal zahl2 : integer range -128 to 127;
signal zahl3 : integer range -128 to 127;
signal result : integer range -128 to 127;
signal i : integer range 1 to 3;
begin
   zahl1 <= to_integer(signed(z1));
   zahl2 <= to_integer(signed(z2));
   zahl3 <= to_integer(signed(z3));
   i     <= to_integer(unsigned(s));
   
   --  21 Slices, 37 Luts, Maximum combinational path delay: 15.656ns
   process (zahl1,zahl2,zahl3,i)
   variable tmp : integer range -256 to 255;
   begin
      case i is
      when 1      => tmp := (zahl1 + zahl2);
      when 2      => tmp := (zahl1 + zahl3);
      when others => tmp := (zahl2 + zahl3); -- Defaultzuweisung
      end case;
      result <= tmp/2;
   end process;

   -- 57 Slices, 103  Luts, Maximum combinational path delay:  16.236ns
   process (zahl1,zahl2,zahl3,i)
   begin
      case i is
      when 1      => result <= ((zahl1 + zahl2) / 2);
      when 2      => result <= ((zahl1 + zahl3) / 2);
      when others => result <= ((zahl2 + zahl3) / 2); -- Defaultzuweisung
      end case;
   end process;
   
   -- 62 Slices,  107 Luts
   process (zahl1,zahl2,zahl3,i)
   begin
      result <= ((zahl2 + zahl3) / 2); -- Defaultzuweisung
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
   end process;

   -- 62 Slices,  107 Luts
   process (zahl1,zahl2,zahl3,i) 
   begin
      if    i = 1 then  result <= ((zahl1 + zahl2) / 2);  
      elsif i = 2 then  result <= ((zahl1 + zahl3) / 2);  
      else              result <= ((zahl2 + zahl3) / 2);  
      end if;
   end process;

   -- 46 Slices,  81 Luts, Maximum combinational path delay: 16.187ns
   process (zahl1,zahl2,zahl3,i) 
   begin
      result <= 0; -- Defaultzuweisung gegen Latches
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
      if i = 3 then  result <= ((zahl2 + zahl3) / 2);  end if;
   end process;

   -- 46 Slices,  81 Luts, Latches!!!!
   process (zahl1,zahl2,zahl3,i) 
   begin
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
      if i = 3 then  result <= ((zahl2 + zahl3) / 2);  end if;
   end process;

   -- ohne Defaultzuweisung: 27 Slices, 47 Luts, Maximum combinational path delay: 18.129ns
   -- mit Defaultzuweisung:  19 Slices, 33 Luts, Maximum combinational path delay: 13.144ns
   process (zahl1,zahl2,zahl3,i)
   variable tmp : integer range -256 to 255;
   begin
      tmp := 0; -- Defaultzuweisung
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
      if i = 3 then  tmp := (zahl2 + zahl3);  end if;
      result <= tmp/2;
   end process;
   
   res <= std_logic_vector(to_signed(result,8));
   
end Behavioral;
Bitte selber bewerten ;-)

Autor: Der Besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar

Was sagt deine Synthese zu folgendem?
Hier ist der Fall i=0 und i=3 zusammengefasst.
Aber i ist auch nur im Bereich von 1 bis 3 definiert. Merkt das 
Sythesewerkzeug, das i=0 don't care ist?

Der Besucher


   process (zahl1,zahl2,zahl3,i)
   variable tmp : integer range -256 to 255;
   begin
      tmp := (zahl2 + zahl3); -- Defaultzuweisung
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
      result <= tmp/2;
   end process;

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

Bewertung
0 lesenswert
nicht lesenswert
Das kommt dabei raus:
   -- 21 Slices,  37 Luts,  Maximum combinational path delay: 15.656ns
   process (zahl1,zahl2,zahl3,i)
   variable tmp : integer range -256 to 255;
   begin
      tmp := (zahl2 + zahl3); -- Defaultzuweisung
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
      result <= tmp/2;
   end process;

Insgesamt scheint mir das Beispiel ziemlich vertrakt, u.a. auch wegen 
des Index, der erst bei 1 losgeht...
Und dann natürlich wegen der Latches, die es im Original-Post Fall 1 
gibt.

Autor: Der Besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und was ist hiervon zu halten? Hier werden die Eingänge gemultiplext.
Ausserdem wird ausserdem ausgenutzt, dass a+b=b+a ist.

   process (zahl1,zahl2,zahl3,i)
   variable summand1 : integer range -128 to 127;
   variable summand2 : integer range -128 to 127;
   begin
      summand1 := zahl2; -- Defaultzuweisung
      summand2 := zahl3; -- Defaultzuweisung
      if i = 1 then  summand2 := zahl1; end if;
      if i = 2 then  summand1 := zahl1; end if;
      result <= (summand1 + summand2)/2;
   end process;

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

Bewertung
0 lesenswert
nicht lesenswert
-- 22 Slices,  38 Luts, Maximum combinational path delay:   15.509ns

Das läuft dann auch vom Schematic her in die gleiche Richtung wie der 
vorher gepostete Fall. Denn auch dort werden die Eingänge auf den 
Addierer gemultiplext.

Autor: Der Besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke. Das war auch schon irgendwie meine Vermutung.
Schön, dass das Werkzeug das automatisch erkennt.

Der Besucher

Autor: dito (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Lothar:

Könntest du bitte noch mal prüfen, ob dieser Code (mit Shift anstelle 
Division) noch weniger verbraucht:
   process (zahl1,zahl2,zahl3,i)
   variable tmp : integer range -256 to 255;
   begin
      tmp := 0; -- Defaultzuweisung
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
      if i = 3 then  tmp := (zahl2 + zahl3);  end if;
      result <= shift_right(tmp,1);
   end process;

Danke!

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

Bewertung
0 lesenswert
nicht lesenswert
Klar, was dabei herauskommt:
    shift_right can not have such operands in this context.
Ok, also etwas hin- und herkonvertiert:
      result <= to_integer(shift_right(to_signed(tmp,9),1));
Und dann das Ergebnis
   -- 17 Slices,  30 Luts, Maximum combinational path delay:   12.988ns

Aber bei negativen Zahlen ist  /  nicht das selbe wie  shift_right
Beitrag "Re: right_shift und "/" liefern unterschiedliche Ergbnisse"

Autor: René D. (Firma: www.dossmatik.de) (dose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie seht es mit der Taktrate aus?

Du warst bei 68MHz, das ist mir viel zu langsam.

Autor: Der Besucher (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@dose
benötigst du wirklich jeden Takt ein Rechenergebnis?
Wenn nicht, ist es auch möglich eine Multicycle-Rechenoperation 
durchzuführen. Man muss den entsprechenden Pfad nur der Synthese 
mitteilen und der Rechenoperation soviele Takte zugestehen, wie sie 
benötigt. Alles ohne zusätzliche Register.
Und wenn jeden Takt ein Ergebnis benötigt wird, kann man immer noch 
mehrere Multicycle-Rechenwerke parallel aufbauen, die zeitversetzt 
arbeiten.

Der Besucher

Autor: René D. (Firma: www.dossmatik.de) (dose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mal mit Korrelationsalgorithmen zu tun gehabt, da wuchsen die 
Daten sehr schnell an.
Sicher geht mit Piplineed architktur eine ganze Menge es zu 
effektivieren.

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.