2017-02-01 4 views
0

Ich habe einen Booth modifizierten Multiplikator in VHDL implementiert. Ich muss eine Synthese mit Vivado machen, aber es ist wegen dieses Fehlers nicht möglich: "komplexe Zuweisung wird nicht unterstützt". Dies ist der Schalthebel-Code, der den Fehler verursacht:Vivado Synthese: komplexe Zuordnung nicht unterstützt

entity shift_register is 
generic (
N : integer := 6; 
M : integer := 6 
); 
port (
en_s   : in std_logic; 
cod_result  : in std_logic_vector (N+M-1 downto 0); 
position  : in integer; 
shift_result : out std_logic_vector(N+M-1 downto 0) 
);  
end shift_register; 

architecture shift_arch of shift_register is 
begin 
process(en_s) 

variable shift_aux : std_logic_vector(N+M-1 downto 0); 
variable i : integer := 0; --solo per comodità 
begin 
    if(en_s'event and en_s ='1') then 
     i := position; 
     shift_aux := (others => '0'); 
     shift_aux(N+M-1 downto i) := cod_result(N+M-1-i downto 0); --ERROR!! 
     shift_result <= shift_aux ; 
    end if; 
end process; 
end shift_arch; 

der Stand Multiplikator funktioniert mit jedem Operator Dimension. Also kann ich diesen generischen Code nicht mit einem bestimmten Code ändern. Bitte helfen Sie mir! Vielen Dank

Antwort

0

Sie versuchen, einen Bereich mit einem runtime variating Wert zu erstellen, und dies wird nicht vom Synthese-Tool unterstützt. cod_result(N+M-1 downto 0); würde unterstützt werden, da N, M und 1 alle zur Synthesedauer bekannt sind.

Wenn Sie versuchen, einen Multiplikator zu implementieren, erhalten Sie das beste Ergebnis mit x <= a * b, und lassen Sie das Synthese-Tool wählen Sie die beste Möglichkeit, es zu implementieren. Wenn Sie Operanden haben, die breiter sind als die Multiplikatorbreiten in Ihrem Gerät, dann müssen Sie in der Dokumentation nachsehen, um die beste Route zu finden, die normalerweise ein Pipelining irgendeiner Art beinhaltet.

Wenn Sie eine variable Laufzeitverschiebung benötigen, suchen Sie nach einem 'Barrel Shifter'. Es gibt bestehende Antworten auf diese, zum Beispiel this one.

+0

Ich weiß, warum nicht funktioniert, meine Aufgabe ist es, einen Booth-Multiplikator zu implementieren, so dass ich nicht x <= a * b verwenden kann. Jedenfalls danke –

+0

@DarioFigliuzzi so Ihre eigentliche Frage ist "Wie implementiere ich einen Barrel Shifter?". Vor diesem Hintergrund gibt es diesbezüglich Fragen. –

+0

Ich dachte mehr darüber nach, wie man das Problem umgehen könnte. Ein alternativer Weg –

1

Es gibt eine Möglichkeit, Ihren Index für die Synthese statisch zu machen.

Zuerst, basierend auf der Schleife können wir sagen, position muss einen Wert im Bereich von shift_aux haben, sonst würden Sie mit Null Scheiben (IEEE Std 1076-2008 8.5 Slice-Namen) enden.

Das kann in der Entity-Deklaration dargestellt werden:

library ieee; 
use ieee.std_logic_1164.all; 

entity shift_register is 
    generic (
     N: integer := 6; 
     M: integer := 6 
    ); 
    port (
     en_s:   in std_logic; 
     cod_result: in std_logic_vector (N + M - 1 downto 0); 
     position:  in integer range 0 to N + M - 1 ; -- range ADDED 
     shift_result: out std_logic_vector(N + M - 1 downto 0) 
    );  
end entity shift_register; 

Was sich geändert hat ist die Zugabe eines Bereichsbeschränkung in den Hafen Erklärung position. Die Idee besteht darin, eine Simulation zu unterstützen, bei der der Standardwert von integer integer'left sein kann. Das Simulieren Ihrer shift_register würde an der steigenden Flanke von en_s fehlschlagen, wenn position (der tatsächliche Treiber) einen Anfangswert in dem Indexbereich von shift_aux nicht bereitstellte.

Aus einer Syntheseperspektive erfordert eine unbegrenzte Ganzzahl, dass Sie sowohl positive als auch negative Ganzzahlwerte berücksichtigen. Ihre for-Schleife verwendet nur positive ganzzahlige Werte.

Problem
 variable i:   integer range 0 to N + M - 1 := 0; -- range ADDED 

Um das unmittelbare Synthese uns für Schleife bei der Suche:

Das gleiche kann in der Deklaration der Variablen i im Prozess erfolgen.

Xilinx-Support-Problem AR# 52302 teilt uns mit, dass das Problem dynamische Werte für Indizes verwendet.

Die Lösung ist, zu ändern, was die for-Schleife hat:

architecture shift_loop of shift_register is 

begin 

    process (en_s) 
     variable shift_aux: std_logic_vector(N + M - 1 downto 0); 
    -- variable i:   integer range 0 to N + M - 1 := 0; -- range ADDED 
    begin 
     if en_s'event and en_s = '1' then 
      -- i := position; 
      shift_aux := (others => '0'); 
      for i in 0 to N + M - 1 loop 
      -- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0); 
       if i = position then 
        shift_aux(N + M - 1 downto i) 
         := cod_result(N + M - 1 - i downto 0); 
       end if; 
      end loop; 
      shift_result <= shift_aux; 
     end if; 
    end process; 

end architecture shift_loop; 

i Wenn ein statischer Wert wird, wenn die Schleife in Synthese abgerollt wird, kann in der Berechnung der Indizes verwendet werden.

Hinweis: Dies gibt uns einen N + M-Eingangsmultiplexer, bei dem jeder Eingang ausgewählt wird, wenn i = position.

Dieses Konstrukt kann durch Optimierung tatsächlich zu einem Barrel-Shifter kollabiert werden, obwohl man erwarten könnte, dass die Anzahl der beteiligten Variablen für große Werte von N und M einen prohibitiven Syntheseaufwand erfordern oder einfach fehlschlagen.

Wenn die Synthese erfolgreich ist, werden Sie jedes Ausgabeelement in der Zuweisung in einen separaten Multiplexer zusammenfassen, der Patricks barrel shifter entspricht.

Für ausreichend große Werte von N und M können wir die Tiefe der Anzahl der Multiplexerschichten im Barrel-Shifter basierend auf der Anzahl der Bits in einem binären Ausdruck des ganzzahligen Abstandsbereichs definieren.

Das erfordert entweder einen deklarierten Integer-Typ oder Subtyp für position oder den Log2-Wert von N + M. Wir können den log2-Wert verwenden, weil er nur statisch verwendet würde. (XST unterstützt log2 (x) wobei x ein Real ist, um statische Werte zu bestimmen, die Funktion wird im IEEE-Paket math_real gefunden). Dies gibt uns die binäre Länge von position. (Wie viele Bits sind erforderlich, um die Verschiebungsstrecke, die Anzahl der Ebenen von Multiplexern zu beschreiben).

architecture barrel_shifter of shift_register is 
begin 
    process (en_s) 
     use ieee.math_real.all; -- log2 [real return real] 
     use ieee.numeric_std.all; -- to_unsigned, unsigned 
     constant DISTLEN: natural := integer(log2(real(N + M))); -- binary lengh 
     type muxv is array (0 to DISTLEN - 1) of 
         unsigned (N + M - 1 downto 0); 
     variable shft_aux:  muxv; 
     variable distance:  unsigned (DISTLEN - 1 downto 0); 
    begin 
     if en_s'event and en_s = '1' then 
      distance := to_unsigned(position, DISTLEN); -- position in binary 
      shft_aux := (others => (others =>'0')); 
      for i in 0 to DISTLEN - 1 loop 
       if i = 0 then 
        if distance(i) = '1' then 
         shft_aux(i) := SHIFT_LEFT(unsigned(cod_result), 2 ** i); 
        else 
         shft_aux(i) := unsigned(cod_result); 
        end if; 
       else 
        if distance(i) = '1' then 
         shft_aux(i) := SHIFT_LEFT(shft_aux(i - 1), 2 ** i); 
        else 
         shft_aux(i) := shft_aux(i - 1); 
        end if; 
       end if; 
      end loop; 
      shift_result <= std_logic_vector(shft_aux(DISTLEN - 1)); 
     end if; 
    end process; 
end architecture barrel_shifter; 

XST unterstützt auch ** wenn der linke Operand 2 und der Wert von i ist als eine Konstante in der Folge von Anweisungen in einer LOOP-Anweisung gefunden behandelt.

Dies könnte mit Signalen anstelle von Variablen oder strukturell in einer Generate-Anweisung statt einer Schleifenanweisung innerhalb eines Prozesses oder sogar als Unterprogramm implementiert werden.

Die Grundidee hier mit diesen beiden Architekturen abgeleitet von Ihnen ist es, etwas Synthese geeignet zu produzieren.

Der Vorteil der zweiten Architektur über die erste ist, zu einer Verringerung der Menge an Syntheseaufwand bei der Optimierung für größere Werte von N + M.

Keines dieser Architekturen überprüft wurde, um eine Testumgebung in den ursprünglichen fehlt. Sie analysieren und erarbeiten beide.

Schreiben eines einfachen Fall Prüfstand:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity shift_register_tb is 
end entity; 

architecture foo of shift_register_tb is 
    constant N:  integer := 6; 
    constant M:  integer := 6; 
    signal clk:  std_logic := '0'; 
    signal din:  std_logic_vector (N + M - 1 downto 0) 
           := (0 => '1', others => '0'); 
    signal dout:  std_logic_vector (N + M - 1 downto 0); 
    signal dist:  integer := 0; 
begin 
DUT: 
    entity work.shift_register 
     generic map (
      N => N, 
      M => M 
     ) 
     port map (
      en_s => clk, 
      cod_result => din, 
      position => dist, 
      shift_result => dout 
     ); 
CLOCK: 
    process 
    begin 
     wait for 10 ns; 
     clk <= not clk; 
     if now > (N + M + 2) * 20 ns then 
      wait; 
     end if; 
    end process; 
STIMULI: 
    process 
    begin 
     for i in 1 to N + M loop 
      wait for 20 ns; 
      dist <= i; 
      din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1)); 
     end loop; 
     wait; 
    end process; 
end architecture; 

und Simulieren zeigt, dass der Bereich der position und die Anzahl der Schleifendurchläufe nur die Anzahl der Bits im Multiplikator decken muss und nicht der Multiplikand. Wir brauchen keinen vollen Barrel Shifter.

Das kann in beiden shift_register-Architekturen leicht behoben werden und hat den Nebeneffekt, die shift_loop-Architektur viel attraktiver zu machen, es wäre einfacher, basierend auf der Multiplikator-Bitlänge (vermutlich M) und nicht der Produktbitlänge (N + M).

Und das würde Ihnen:

library ieee; 
use ieee.std_logic_1164.all; 

entity shift_register is 
    generic (
     N: integer := 6; 
     M: integer := 6 
    ); 
    port (
     en_s:   in std_logic; 
     cod_result: in std_logic_vector (N + M - 1 downto 0); 
     position:  in integer range 0 to M - 1 ; -- range ADDED 
     shift_result: out std_logic_vector(N + M - 1 downto 0) 
    );  
end entity shift_register; 

architecture shift_loop of shift_register is 
begin 
    process (en_s) 
     variable shift_aux: std_logic_vector(N + M - 1 downto 0); 
    -- variable i:   integer range 0 to M - 1 := 0; -- range ADDED 
    begin 
     if en_s'event and en_s = '1' then 
      -- i := position; 
      shift_aux := (others => '0'); 
      for i in 0 to M - 1 loop 
      -- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0); 
       if i = position then -- This creates an N + M - 1 input MUX 
        shift_aux(N + M - 1 downto i) 
         := cod_result(N + M - 1 - i downto 0); 
       end if; 
      end loop; -- The loop is unrolled in synthesis, i is CONSTANT 
      shift_result <= shift_aux; 
     end if; 
    end process;  
end architecture shift_loop; 

Ändern der Testumgebung:

STIMULI: 
    process 
    begin 
     for i in 1 to M loop -- WAS N + M loop 
      wait for 20 ns; 
      dist <= i; 
      din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1)); 
     end loop; 
     wait; 
    end process; 

gibt ein Ergebnis zeigt die Verschiebungen über den Bereich des Multiplikatorwert sind (angegeben durch M):

shift_register_tb_1.png

Also die Moral hier ist, Sie brauchen keine vollständige Barrel Shifter, nur einer, der über den Multiplikatorbereich und nicht über den Produktbereich arbeitet.

Das letzte Bit Code sollte Synthese zulässig sein.

Verwandte Themen