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


von Gast (Gast)


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

von D. I. (Gast)


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)

von Gast (Gast)


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?

von Gast (Gast)


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

von Der Besucher (Gast)


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

von dito (Gast)


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...

von Gast (Gast)


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

von Marc H. (Gast)


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.

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


Lesenswert?

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


Hier meine Erkenntnisse:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity SignalVsVariable is
6
    Port ( z1 : in  STD_LOGIC_VECTOR (7 downto 0);
7
           z2 : in  STD_LOGIC_VECTOR (7 downto 0);
8
           z3 : in  STD_LOGIC_VECTOR (7 downto 0);
9
           res : out STD_LOGIC_VECTOR (7 downto 0);
10
           s  : in  STD_LOGIC_VECTOR (1 downto 0));
11
end SignalVsVariable;
12
13
architecture Behavioral of SignalVsVariable is
14
signal zahl1 : integer range -128 to 127;
15
signal zahl2 : integer range -128 to 127;
16
signal zahl3 : integer range -128 to 127;
17
signal result : integer range -128 to 127;
18
signal i : integer range 1 to 3;
19
begin
20
   zahl1 <= to_integer(signed(z1));
21
   zahl2 <= to_integer(signed(z2));
22
   zahl3 <= to_integer(signed(z3));
23
   i     <= to_integer(unsigned(s));
24
   
25
   --  21 Slices, 37 Luts, Maximum combinational path delay: 15.656ns
26
   process (zahl1,zahl2,zahl3,i)
27
   variable tmp : integer range -256 to 255;
28
   begin
29
      case i is
30
      when 1      => tmp := (zahl1 + zahl2);
31
      when 2      => tmp := (zahl1 + zahl3);
32
      when others => tmp := (zahl2 + zahl3); -- Defaultzuweisung
33
      end case;
34
      result <= tmp/2;
35
   end process;
36
37
   -- 57 Slices, 103  Luts, Maximum combinational path delay:  16.236ns
38
   process (zahl1,zahl2,zahl3,i)
39
   begin
40
      case i is
41
      when 1      => result <= ((zahl1 + zahl2) / 2);
42
      when 2      => result <= ((zahl1 + zahl3) / 2);
43
      when others => result <= ((zahl2 + zahl3) / 2); -- Defaultzuweisung
44
      end case;
45
   end process;
46
   
47
   -- 62 Slices,  107 Luts
48
   process (zahl1,zahl2,zahl3,i)
49
   begin
50
      result <= ((zahl2 + zahl3) / 2); -- Defaultzuweisung
51
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
52
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
53
   end process;
54
55
   -- 62 Slices,  107 Luts
56
   process (zahl1,zahl2,zahl3,i) 
57
   begin
58
      if    i = 1 then  result <= ((zahl1 + zahl2) / 2);  
59
      elsif i = 2 then  result <= ((zahl1 + zahl3) / 2);  
60
      else              result <= ((zahl2 + zahl3) / 2);  
61
      end if;
62
   end process;
63
64
   -- 46 Slices,  81 Luts, Maximum combinational path delay: 16.187ns
65
   process (zahl1,zahl2,zahl3,i) 
66
   begin
67
      result <= 0; -- Defaultzuweisung gegen Latches
68
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
69
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
70
      if i = 3 then  result <= ((zahl2 + zahl3) / 2);  end if;
71
   end process;
72
73
   -- 46 Slices,  81 Luts, Latches!!!!
74
   process (zahl1,zahl2,zahl3,i) 
75
   begin
76
      if i = 1 then  result <= ((zahl1 + zahl2) / 2);  end if;
77
      if i = 2 then  result <= ((zahl1 + zahl3) / 2);  end if;
78
      if i = 3 then  result <= ((zahl2 + zahl3) / 2);  end if;
79
   end process;
80
81
   -- ohne Defaultzuweisung: 27 Slices, 47 Luts, Maximum combinational path delay: 18.129ns
82
   -- mit Defaultzuweisung:  19 Slices, 33 Luts, Maximum combinational path delay: 13.144ns
83
   process (zahl1,zahl2,zahl3,i)
84
   variable tmp : integer range -256 to 255;
85
   begin
86
      tmp := 0; -- Defaultzuweisung
87
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
88
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
89
      if i = 3 then  tmp := (zahl2 + zahl3);  end if;
90
      result <= tmp/2;
91
   end process;
92
   
93
   res <= std_logic_vector(to_signed(result,8));
94
   
95
end Behavioral;
Bitte selber bewerten ;-)

von Der Besucher (Gast)


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;

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


Lesenswert?

Das kommt dabei raus:
1
   -- 21 Slices,  37 Luts,  Maximum combinational path delay: 15.656ns
2
   process (zahl1,zahl2,zahl3,i)
3
   variable tmp : integer range -256 to 255;
4
   begin
5
      tmp := (zahl2 + zahl3); -- Defaultzuweisung
6
      if i = 1 then  tmp := (zahl1 + zahl2);  end if;
7
      if i = 2 then  tmp := (zahl1 + zahl3);  end if;
8
      result <= tmp/2;
9
   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.

von Der Besucher (Gast)


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;

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


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.

von Der Besucher (Gast)


Lesenswert?

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

Der Besucher

von dito (Gast)


Lesenswert?

@ Lothar:

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

Danke!

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


Lesenswert?

Klar, was dabei herauskommt:
1
    shift_right can not have such operands in this context.
Ok, also etwas hin- und herkonvertiert:
1
      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"

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


Lesenswert?

wie seht es mit der Taktrate aus?

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

von Der Besucher (Gast)


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

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


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.

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.