Forum: FPGA, VHDL & Co. Multiplizierer einsparen


von Tom (Gast)


Lesenswert?

Guten Tag,
ich habe ein IIR-Filter programmiert und versuche jetzt Multiplikationen 
zusammenzufassen, um die Anzahl benötigter Multiplizierer zu reduzieren.
Der Code einer Stufe sieht folgendermaßen aus:
1
entity section_1 is
2
  generic
3
    (  PG:  integer :=  890;       
4
      PB0: integer :=    1;     
5
      PB1: integer :=  648;    
6
      PB2: integer :=    1;      
7
      PA0: integer :=    1;    
8
      PA1: integer :=  360;    
9
      PA2: integer := 1964);     
10
  port
11
    (  CLK: in std_logic;   
12
      RESET: in std_logic;
13
      XN1: in std_logic_vector(11 downto 0);   
14
      YN1: out std_logic_vector(17 downto 0));
15
end section_1;
16
17
architecture Behavioral of section_1 is
18
constant G : signed(11 downto 0) := to_signed(PG,12);
19
constant B1 : signed(11 downto 0) := to_signed(PB1,12);
20
constant A1 : signed(11 downto 0) := to_signed(PA1,12);
21
constant A2 : signed(11 downto 0) := to_signed(PA2,12);
22
23
signal X   : signed(17 downto 0)                   ;
24
signal XB0 : signed(29 downto 0) := (others => '0');
25
signal XB1 : signed(29 downto 0) := (others => '0');
26
signal XB2 : signed(29 downto 0) := (others => '0');
27
28
signal Y  : signed(29 downto 0) := (others => '0'); 
29
signal YA1: signed(29 downto 0) := (others => '0');
30
signal YA2: signed(29 downto 0) := (others => '0');
31
32
signal SUMB2A2    : signed(29 downto 0) := (others => '0');
33
signal SUMB2A2V   : signed(29 downto 0) := (others => '0');
34
signal SUMB2A2V_2 : signed(29 downto 0) := (others => '0');
35
signal SUMB2A2V_3 : signed(29 downto 0) := (others => '0');
36
signal SUMB2A2V2  : signed(29 downto 0) := (others => '0');
37
38
XB0 <= G * X;
39
XB1 <= B1 * XB0(28 downto 11);
40
XB2 <= XB0;
41
42
Y <= SUMB2A2V2 + XB0; 
43
YA1 <= A1 * Y(28 downto 11);
44
YA2 <= A2 * Y(28 downto 11);
45
46
SUMB2A2 <= XB2 - YA2;
47
SUMB2A2V_2 <= XB1 + SUMB2A2V;
48
SUMB2A2V_3 <= SUMB2A2V_2 - YA1;
49
50
Delay: process(CLK)
51
variable YHilf: signed(29 downto 0);
52
begin
53
  if CLK='1' and CLK'event then
54
    if RESET = '1' then
55
      SUMB2A2V <= (others => '0');
56
      SUMB2A2V2 <= (others => '0');
57
      YN1 <= (others => '0');
58
     else
59
      SUMB2A2V <= SUMB2A2;
60
      SUMB2A2V2 <= SUMB2A2V_3;
61
      if Y(29) = '1' then
62
        YHilf := not(Y - 1);
63
        YN1 <= std_logic_vector(not(YHilf(28 downto 11)-1));
64
      else
65
        YN1 <= std_logic_vector(Y(28 downto 11));
66
      end if;
67
    end if;
68
  end if;  
69
end process Delay;

Der CLK beträgt 80MHz und liefert mit jedem Takt einen neuen 
Eingangswert bzw. einen neuen Ausgangswert.
Gibt es eine Möglichkeit, die die Multiplikationen A1 * Y(28 downto 11) 
und A2 * Y(28 downto 11) so zusammenfasst, dass anstelle von zwei 
Multiplizierer nur einer verwendet wird. Habe mit Hilfe eines Prozesses 
versucht YA1 auf die steigende Flanke des CLKs zu berechnen und YA2 auf 
die fallende Flanke. Jedoch war dieser Versuch nicht von Erfolg gekrönt.
Ein weiterer Punkt ist, dass ich in dieser Stufe 4 Multiplikationen 
durchführe, jedoch laut Xilinx 5 Multiplizierer benötigt werden.  Meine 
Feststellung dazu ist, dass die Multiplikation XB1 <= B1 * XB0(28 downto 
11) zwei Multiplizierer benötigt, jedoch ist mir der Grund dafür nicht 
ersichtlich.

Grüße
Tom

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


Lesenswert?

Tom schrieb:
> Habe mit Hilfe eines Prozesses versucht YA1 auf die steigende Flanke
> des CLKs zu berechnen und YA2 auf die fallende Flanke. Jedoch war dieser
> Versuch nicht von Erfolg gekrönt.
Ja, überleg mal, warum. Du wirst fürs Leben lernen...
Als Tipp: wie ist so ein Multiplizierer aufgebaut? Woher kommen die 
Faktoren am Eingang und wohin geht das Ergebnis? Wie wird das 
umgeschaltet?

Denn es geht um das Umschalten (aka. Multiplexen): du willst 1 
Komponente mehrfach verwenden...

> Der CLK beträgt 80MHz und liefert mit jedem Takt einen neuen
> Eingangswert bzw. einen neuen Ausgangswert.
> Gibt es eine Möglichkeit, die die Multiplikationen A1 * Y(28 downto 11)
> und A2 * Y(28 downto 11) so zusammenfasst, dass anstelle von zwei
> Multiplizierer nur einer verwendet wird.
Du musst mit der doppelten Frequenz (das ist auch deine 
Zwei-Flankengeschichte) durch einen Multiplexer zwischen den vier 
Faktoren und den beiden Ergebnissen umschalten. Im Fall von YA1 und YA2 
wäre sogar nur 1 Faktor zu multiplexen...

Tom schrieb:
> Ein weiterer Punkt ist, dass ich in dieser Stufe 4 Multiplikationen
> durchführe, jedoch laut Xilinx 5 Multiplizierer benötigt werden.
Sieh doch einfach mal den RTL-Schaltplan an. Evtl. kannst du dann 
erkennen, was da passiert. Ich vermute sowas wie Register-Doubling (nur 
hier eben Multiplier-Doubling)...

BTW: bitte VHDL-Code in die Tags [ vhdl] und [ /vhdl] ohne Leerzeichen 
einschließen.

von Ralle (Gast)


Lesenswert?

Tom schrieb:
> YA1 <= A1 * Y(28 downto 11);
> YA2 <= A2 * Y(28 downto 11);

> SUMB2A2 <= XB2 - YA2;
> SUMB2A2V_2 <= XB1 + SUMB2A2V;
> SUMB2A2V_3 <= SUMB2A2V_2 - YA1;

Geht es um das hier?
Du solltest das mathematisch etwas umformulieren, dann fällt eine 
Multiplikation später an und es entsteht weiter vorne ein Addierer.

von Tom (Gast)


Lesenswert?

Danke für den Hinweis mit dem RTL Schaltplan. Der „Überschüssige“ 
Multiplizierer resultiert aus der doppelten Negation im Prozess Delay 
und kann somit nicht eingespart werden. Für die Signale YA1 und YA2 ist 
es mir mit Hilfe der case-Anweisung  gelungen einen Multiplizierer 
einzusparen.
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity section_1 is
6
  generic
7
    (  PG:  integer :=  890;            
8
                                           PB0: integer :=    1;     
9
      PB1: integer :=  648;    
10
      PB2: integer :=    1;    
11
      PA0: integer :=    1;    
12
      PA1: integer :=  360;    
13
      PA2: integer := 1964);     
14
  port
15
    (  CLK: in std_logic;   
16
       CLK160MHz: in std_logic;
17
      RESET: in std_logic;
18
      XN1: in std_logic_vector(11 downto 0);   
19
      YN1: out std_logic_vector(17 downto 0));
20
end section_1;
21
22
architecture Behavioral of section_1 is
23
constant G : signed(11 downto 0) := to_signed(PG,12);
24
constant B1 : signed(11 downto 0) := to_signed(PB1,12);
25
constant A1 : signed(11 downto 0) := to_signed(PA1,12);
26
constant A2 : signed(11 downto 0) := to_signed(PA2,12);
27
28
29
signal X   : signed(17 downto 0)                   ;
30
signal A: signed(11 downto 0);
31
signal XB0 : signed(29 downto 0) := (others => '0');
32
signal XB1 : signed(29 downto 0) := (others => '0');
33
signal XB2 : signed(29 downto 0) := (others => '0');
34
35
signal Y  : signed(29 downto 0) := (others => '0'); 
36
signal YA1: signed(29 downto 0) := (others => '0');
37
signal YA2: signed(29 downto 0) := (others => '0');
38
signal YA: signed(29 downto 0) := (others => '0');
39
40
signal SUMB2A2    : signed(29 downto 0) := (others => '0');
41
signal SUMB2A2V   : signed(29 downto 0) := (others => '0');
42
signal SUMB2A2V_2 : signed(29 downto 0) := (others => '0');
43
signal SUMB2A2V_3 : signed(29 downto 0) := (others => '0');
44
signal SUMB2A2V2  : signed(29 downto 0) := (others => '0');
45
46
47
48
begin
49
50
51
process(XN1)
52
begin
53
  if XN1(11) = '1' then
54
    X <= signed('1' & XN1 & "00000");
55
  else
56
    X <= signed('0' & XN1 & "00000");
57
  end if;
58
end process;
59
60
61
XB0 <= G * X;
62
XB1 <= B1 * XB0(28 downto 11);
63
XB2 <= XB0;
64
65
Y <= SUMB2A2V2 + XB0; 
66
YA <= A * Y(28 downto 11);
67
68
69
process(CLK160MHz,YA)
70
begin
71
  case CLK160MHz is
72
    when '0' => A <= A1 ;
73
    when others => A <= A2;
74
  end case;  
75
76
  case CLK160MHz is
77
    when '0' => YA1 <= YA ;
78
    when others => YA2 <= YA;
79
  end case;  
80
  
81
end process;
82
83
SUMB2A2 <= XB2 - YA2;
84
SUMB2A2V_2 <= XB1 + SUMB2A2V;
85
SUMB2A2V_3 <= SUMB2A2V_2 - YA1;
86
87
Delay: process(CLK)
88
variable YHilf: signed(29 downto 0);
89
begin
90
  if CLK='1' and CLK'event then
91
    if RESET = '1' then
92
      SUMB2A2V <= (others => '0');
93
      SUMB2A2V2 <= (others => '0');
94
      YN1 <= (others => '0');
95
     else
96
      SUMB2A2V <= SUMB2A2;
97
      SUMB2A2V2 <= SUMB2A2V_3;
98
      if Y(29) = '1' then
99
        YHilf := not(Y - 1);
100
        YN1 <= std_logic_vector(not(YHilf(28 downto 11)-1));
101
      else
102
        YN1 <= std_logic_vector(Y(28 downto 11));
103
      end if;
104
    end if;
105
  end if;  
106
end process Delay;
107
108
109
end Behavioral;


Jedoch bekomme ich jetzt immer folgende Warnung:
Found 1-bit latch for signal <YA1<28>>. Latches may be generated from 
incomplete case or if statements. We do not recommend the use of latches 
in FPGA/CPLD designs, as they may lead to timing problems
So wie ich das verstehe, stimmt irgendwas mit der case-Anweisung nicht?

von Tom (Gast)


Lesenswert?

@Ralle
Wie soll den die Umformulierung aussehen?

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


Lesenswert?

Tom schrieb:
> process(CLK160MHz,YA)
Die Sensitivliste ist unvollständig. Es fehlen A1 und A2.

> begin
>   case CLK160MHz is
>     when '0' => A <= A1 ;
>     when others => A <= A2;
>   end case;
>
>   case CLK160MHz is
>     when '0' => YA1 <= YA ;
>     when others => YA2 <= YA;
>   end case;
> end process;
Ein Takt ist ein Takt und keine Quelle für kombinatorisches 
Umschalten...

>     when '0' => YA1 <= YA ;
>     when others => YA2 <= YA;
Daher kommt die Latch-Warnung:
Was soll YA2 sein, wenn CLK160MHz mal '0' ist?
Und was Ya1, wenn der "Takt" '1' ist?


Wie hast du die 160MHz erzeugt?

von Ralle (Gast)


Lesenswert?

Lothar Miller schrieb:
> Tom schrieb:
>> process(CLK160MHz,YA)
> Die Sensitivliste ist unvollständig. Es fehlen A1 und A2.
>
>> begin
>>   case CLK160MHz is
>>     when '0' => A <= A1 ;
>>     when others => A <= A2;
>>   end case;
>>
>>   case CLK160MHz is
>>     when '0' => YA1 <= YA ;
>>     when others => YA2 <= YA;
>>   end case;
>> end process;
> Ein Takt ist ein Takt und keine Quelle für kombinatorisches
> Umschalten...

Ich finde die Klasse, darauf wäre ich nicht gekommen.


>Wie soll den die Umformulierung aussehen?
Du verwendest beide Terme in derselben Gleichung, nur über 
Zwischensignale. Die kannst du anders zusammenfassen.

von Tom (Gast)


Lesenswert?

Also ich habe jetzt eine Lösung, die statt 5 Multiplizierer noch 3 
verwendet. Jedoch funktioniert das Filter mit den 160 MHz nicht. Wird 
der Takt auf 320 MHz erhöht, läuft es ohne Probleme und ich erziele 
dieselben Ergenisse, wie mit 5 Multiplizierer.
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity section_1 is
6
  generic
7
    (  PG:  integer :=  890;       
8
      PB0: integer :=    1;    
9
      PB1: integer :=  648;    
10
      PB2: integer :=    1;    
11
      PA0: integer :=    1;    
12
      PA1: integer :=  360;    
13
      PA2: integer := 1964);     
14
  port
15
    (  CLK: in std_logic; 
16
      CLK160MHz: in std_logic;    
17
      RESET: in std_logic;
18
      XN1: in std_logic_vector(11 downto 0);   
19
      YN1: out std_logic_vector(17 downto 0));
20
end section_1;
21
22
architecture Behavioral of section_1 is
23
constant G : signed(11 downto 0) := to_signed(PG,12);
24
constant B1 : signed(11 downto 0) := to_signed(PB1,12);
25
constant A1 : signed(11 downto 0) := to_signed(PA1,12);
26
constant A2 : signed(11 downto 0) := to_signed(PA2,12);
27
28
signal A: signed(11 downto 0) := (others => '0');
29
signal K: signed(11 downto 0) := (others => '0');
30
31
signal X   : signed(17 downto 0)                   ;
32
signal Z   : signed(17 downto 0)                   ;
33
signal XB0 : signed(29 downto 0) := (others => '0');
34
signal XB1 : signed(29 downto 0) := (others => '0');
35
signal XB2 : signed(29 downto 0) := (others => '0');
36
signal XB : signed(29 downto 0) := (others => '0');
37
38
signal Y  : signed(29 downto 0) := (others => '0'); 
39
signal YA : signed(29 downto 0) := (others => '0');
40
signal YA1: signed(29 downto 0) := (others => '0');
41
signal YA2: signed(29 downto 0) := (others => '0');
42
43
signal SUMB2A2    : signed(29 downto 0) := (others => '0');
44
signal SUMB2A2V   : signed(29 downto 0) := (others => '0');
45
signal SUMB2A2V_2 : signed(29 downto 0) := (others => '0');
46
signal SUMB2A2V_3 : signed(29 downto 0) := (others => '0');
47
signal SUMB2A2V2  : signed(29 downto 0) := (others => '0');
48
49
signal SEL: std_logic := '0';
50
51
begin
52
53
54
process(XN1)
55
begin
56
  if XN1(11) = '1' then
57
    X <= signed('1' & XN1 & "00000");
58
  else
59
    X <= signed('0' & XN1 & "00000");
60
  end if;
61
end process;
62
63
XB <= K * Z;
64
XB2 <= XB0;
65
66
Y <= SUMB2A2V2 + XB0; 
67
YA <= A * Y(28 downto 11);
68
69
70
SUMB2A2 <= XB2 - YA2;
71
SUMB2A2V_2 <= XB1 + SUMB2A2V;
72
SUMB2A2V_3 <= SUMB2A2V_2 - YA1;
73
74
process(SEL,X,XB0)
75
begin
76
  case SEL is
77
    when '0' => A <= "000101101000";     -- A1
78
    when others => A <="011110101100";   -- A2
79
  end case;
80
  
81
  case SEL is
82
    when '0' => K <= "001101111010";     -- G
83
    when others => K <= "001010001000";  -- B1
84
  end case;
85
  
86
  case SEL is
87
    when '0' => Z <= X;
88
    when others => Z <=XB0(28 downto 11);
89
   end case;
90
end process;
91
92
process(CLK160MHz,YA)
93
begin
94
  if CLK160MHz = '1' and CLK160MHz'event then
95
    SEL <= not(SEL);
96
    if SEL = '0' then
97
      YA1 <= YA;
98
      XB0 <= XB;
99
    else
100
      YA2 <= YA;
101
      XB1 <= XB;
102
      end if;
103
  end if;
104
end process;
105
106
107
108
109
110
Delay: process(CLK)
111
variable YHilf: signed(29 downto 0);
112
begin
113
  if CLK='1' and CLK'event then
114
    if RESET = '1' then
115
      SUMB2A2V <= (others => '0');
116
      SUMB2A2V2 <= (others => '0');
117
      YN1 <= (others => '0');
118
     else
119
      SUMB2A2V <= SUMB2A2;
120
      SUMB2A2V2 <= SUMB2A2V_3;
121
      if Y(29) = '1' then
122
        YHilf := not(Y - 1);
123
        YN1 <= std_logic_vector(not(YHilf(28 downto 11)-1));
124
      else
125
        YN1 <= std_logic_vector(Y(28 downto 11));
126
      end if;
127
    end if;
128
  end if;  
129
end process Delay;
130
131
132
end Behavioral;
Hat jemand eine Idee, wie ich den Takt reduziert bekomme?

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


Lesenswert?

Tom schrieb:
> Jedoch funktioniert das Filter mit den 160 MHz nicht.
Wie stellst du das fest?
Was sagt die Simulation?
Hast du ein Constraint auf den Takt gesetzt?

von Tom (Gast)


Lesenswert?

Das Filter arbeitet bei einer Mittenfrequenz von 20 MHz und meine 
Abtastfrequenz liegt bei 80 MHz. Also lasse ich in der Simulation meine 
Eingangswerte so variieren, dass sie einem Sinussignal mit 20 MHz 
entsprechen. Funktioniert mein Programm, so muss mein Ausgangssignal 
ungefiltert vorliegen und mit der Simulation mit 5 Multiplizierer 
übereinstimmen. Dies tut sie aber nur, wenn ich die Frequenz auf 320 MHz 
einstelle.
Ich musste mich bisher noch gar nicht mit timing constraints 
beschäftigen, deswegen weiß ich nicht was du mit "Constraint auf den 
Takt setzen" meinst!

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


Lesenswert?

Wenn du bisher "nur" simulierst und da was nicht passt, dann kannst du 
ja recht komfortabel den Fehler suchen.

Tom schrieb:
> Dies tut sie aber nur, wenn ich die Frequenz auf 320 MHz einstelle.
In der Simulation? Machst du eine Timingsimulation?

> Ich musste mich bisher noch gar nicht mit timing constraints beschäftigen,
Das wird kommen, wenn du aufs FPGA gehst...

> weiß ich nicht was du mit "Constraint auf den Takt setzen" meinst!
Damit teilst du der Toolchain mit, wie schnell du das FPGA takten wirst. 
Und 320MHz sind schon sportlich...

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.