2014-05-30 2 views
1

J'écris un code pour une ALU 4 bits et j'ai un problème quand je veux écrire pour une opération de décalage vers la gauche. J'ai deux entrées (opérandeA et opérandeB). Je veux convertir l'opérande B en décimal (par exemple "0010" en "2") puis décaler l'opérande A 2 fois vers la gauche. mon code est compilé mais je ne suis pas sûr que ce soit vrai. Merci d'avance.4bit ALU VHDL code

entity ALU is 
    port(
    reset_n  : in std_logic; 
    clk   : in std_logic; 
    OperandA : in std_logic_vector(3 downto 0); 
    OperandB : in std_logic_vector(3 downto 0); 
    Operation : in std_logic_vector(2 downto 0); 
    Start  : in std_logic; 
    Result_Low : out std_logic_vector(3 downto 0); 
    Result_High : out std_logic_vector(3 downto 0); 
    Ready  : out std_logic; 
    Errorsig : out std_logic); 
end ALU; 

architecture behavior of ALU is 
    signal loop_nr : integer range 0 to 15; 
begin 
    process (reset_n, clk, operation) 
    variable tempHigh : std_logic_vector(4 downto 0); 
    begin 
    if (reset_n = '0') then 
     Result_Low <= (others => '0'); 
     Result_High <= (others => '0'); 
     Errorsig <= '0'; 
    elsif (clk'event and clk = '1') then 
     case operation is 
     when "001" => 
      for i in 0 to loop_nr loop 
      loop_nr  <= to_integer(unsigned(OperandB)); 
      Result_Low <= OperandA(2 downto 0)&'0'; 
      Result_High <= tempHigh(2 downto 0) & OperandA(3); 
      end loop; 
      Ready <= '1'; 
      Errorsig <= '0'; 
     when "010" => 
      Result_Low <= OperandB(0)& OperandA(3 downto 1); 
      Result_High <= OperandB(3 downto 1); 
      Ready  <= '1'; 
     when others => 
      Result_Low <= (others => '0'); 
      ready  <= '0'; 
      Errorsig <= '0'; 
     end case; 
    end if; 
    end process; 
end behavior; 

Répondre

2

pour décaler à gauche deux fois la syntaxe devrait être le suivant:

A = A < sll 2; - left shift logique 2 bits

Je ne comprends pas pourquoi il faut convertir l'opérande B en décimal. Il peut être utilisé comme une valeur binaire ou décimale ou d'ailleurs valeur hexadécimale à tout moment sans importance de la base dans laquelle il a été enregistré.

+0

merci mais je ne suis pas autorisé à utiliser des fonctions telles que SHL ou sll2 et je dois utiliser une boucle et décaler la première entrée par seconde étape d'entrée (décimale). ma sortie a 8 bits et l'entrée est de 4 bits. par exemple si la sortie B est (0101), la première sortie est décalée 5ème et ce qui reste est la version décalée de A et le bit dépassé (bit 5) dans la deuxième sortie. – user3690624

0

L'opérateur sll peut ne pas toujours fonctionner comme prévu avant VHDL-2008 (en savoir plus here), donc envisager au lieu d'utiliser des fonctions de ieee.numeric_std pour décaler, par exemple:

y <= std_logic_vector(shift_left(unsigned(OperandA), to_integer(unsigned(OperandB)))); 

on notera également que Result_High est déclaré dans le port comme std_logic_vector(3 downto 0), mais est affecté dans la ligne 41 comme Result_High <= OperandB(3 downto 1), avec assign ayant un bit moins que siz e.

L'hypothèse pour le code est que ieee.numeric_std est utilisé.

0

La raison pour laquelle vous avez été invité à utiliser les préférences de sll est que, en général, les outils de synthèse ne prennent pas en charge les instructions de boucle avec des limites non statiques (loop_nr). Les boucles sont dépliées ce qui nécessite une valeur statique pour déterminer comment de nombreuses itérations de boucle sont dépliées (quantité de matériel à générer). Comme Morten souligne que votre code n'analyse pas, contrairement à votre affirmation qu'il compile.

Après avoir inséré au début de votre code les quatre lignes suivantes, nous voyons une erreur à la ligne 41:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 
--(blank, a spacer that doesn't show up in the code highlighter) 

ghdl -a ALU.vhdl ALU.vhdl:41:26: length of value does not match length of target ghdl: compilation error

qui ressemble

 Result_High <= '0' & OperandB(3 downto 1); 

était destiné à la déclaration de cas, choix "010" (un équivalent srl dur codé à une distance de 1, vraisemblablement t o correspond au comportement correct de l'équivalent sll ). Après quoi votre description de conception analyse.

En outre, il existe d'autres erreurs de description d'algorithme non reflétées dans la syntaxe VHDL ou des erreurs sémantiques.

L'écriture d'un banc d'essai simple:

library ieee; 
use ieee.std_logic_1164.all; 

entity alu_tb is 
end entity; 

architecture foo of alu_tb is 

    signal reset_n:  std_logic := '0'; 
    signal clk:   std_logic := '0'; 
    signal OperandA:  std_logic_vector(3 downto 0) :="1100"; -- X"C" 
    signal OperandB:  std_logic_vector(3 downto 0) :="0010"; -- 2 
    signal Operation:  std_logic_vector(2 downto 0):= "001"; -- shft right 
    signal Start:   std_logic; -- Not currently used 
    signal Result_Low:  std_logic_vector(3 downto 0); 
    signal Result_High: std_logic_vector(3 downto 0); 
    signal Ready:   std_logic; 
    signal Errorsig:  std_logic; 

begin 

DUT: 
entity work.ALU 
    port map (
     reset_n => reset_n, 
     clk => clk, 
     OperandA => OperandA, 
     OperandB => OperandB, 
     Operation => Operation, 
     Start => Start, 
     Result_Low => Result_Low, 
     Result_High => Result_High, 
     Ready => Ready, 
     Errorsig => Errorsig 
    ); 

CLOCK: 
    process 
    begin 
     wait for 10 ns; 
     clk <= not clk; 
     if Now > 100 ns then 
      wait; 
     end if; 
    end process; 

STIMULUS: 
    process 
    begin 
     wait for 20 ns; 
     reset_n <= '1'; 
     wait; 
    end process; 

end architecture; 

nous donne une démonstration:

alu_tb png

La première chose qui colle est que Result_High obtient quelques « U de. Ceci est causé par tempHigh n'étant pas initialisé ou assigné. La remarque suivante est que le résultat du décalage est incorrect (Result_Low et Result_High). Je m'attendrais à ce que vous vouliez un "0011" dans Result_High et "0000" dans Result_Low.

Vous voyez le résultat d'exactement un décalage vers la gauche - ('U', 'U', 'U', '1') dans Result_High et "1000" dans Result_Low.

Ceci est dû à l'exécution d'une instruction de boucle en cycles delta (pas de passage temporel de simulation ). Dans une instruction de processus, il n'y a qu'un seul pilote pour chaque signal. L'effet net de cela est qu'il n'y a qu'une seule valeur future pour le temps de simulation actuel et la dernière valeur attribuée sera celle qui est programmée dans la forme d'onde de sortie projetée pour le temps de simulation actuel. (Essentiellement, l'affectation dans l'instruction de boucle à un signal se produit une fois, et comme les valeurs successives dépendent de l'affectation , il semble qu'il y ait eu une seule affectation).

Il existe deux façons de résoudre ce problème. La première consiste à utiliser les variables affectées à l'intérieur de la boucle et à affecter les signaux correspondants aux variables suivant l'instruction de boucle. Comme indiqué précédemment, la boucle liée n'est pas statique et vous ne pouvez pas synthétiser la boucle.

La deuxième méthode consiste à éliminer la boucle en exécutant les affectations de décalage de manière séquentielle. Essentiellement 1 décalage par horloge, signalisation Ready après le dernier changement se produit.

Il y a aussi loin à l'étape de côté la question des limites statiques pour les boucles en utilisant une déclaration de cas (ou en VHDL 2008 en utilisant une affectation signal de conditionnelle séquentielle d'affectation de signal séquentiel sélectionné si votre fournisseur d'outils de synthèse les soutenir). Cela a l'avantage de fonctionner dans une horloge. Notez que tout cela nécessite une variable entière contenant to_integer (unsigned (OperandB)).

Et tout cela peut être lDépaulement lorsque votre outil synthèse fournisseur prend en charge SLL (et srl pour l'autre cas) ou SHIFT_LEFT et SHIFT_RIGHT du paquet numeric_std, et vous êtes autorisé à les utiliser.

universel (avant VHDL 2008) fixe sans utiliser SLL ou SHIFT_LEFT pourrait être:

begin 
    process (reset_n, clk, operation) 
     variable tempHigh : std_logic_vector(4 downto 0); 
     variable loop_int: integer range 0 to 15; 
    begin 
     if (reset_n = '0') then 
     Result_Low <= (others => '0'); 
     Result_High <= (others => '0'); 
     Errorsig <= '0'; 
     elsif (clk'event and clk = '1') then 
     case operation is 
      when "001" => 
       loop_int := to_integer(unsigned(OperandB)); 
       case loop_int is 
        when 0 => 
         Result_Low <= OperandA; 
         Result_High <= (others => '0'); 
        when 1 => 
         Result_Low <= OperandA(2 downto 0) & '0'; 
         Result_High <= "000" & OperandA(3);     
        when 2 => 
         Result_Low <= OperandA(1 downto 0) & "00"; 
         Result_High <= "00" & OperandA(3 downto 2); 
        when 3 => 
         Result_Low <= OperandA(0) & "000"; 
         Result_High <= "0" & OperandA(3 downto 1); 
        when 4 => 
         Result_Low <= (others => '0'); 
         Result_High <= OperandA(3 downto 0); 
        when 5 => 
         Result_Low <= (others => '0'); 
         Result_High <= OperandA(2 downto 0) & '0'; 
        when 6 => 
         Result_Low <= (others => '0'); 
         Result_High <= OperandA(1 downto 0) & "00"; 
        when 7 => 
         Result_Low <= (others => '0'); 
         Result_High <= OperandA(0) & "000"; 
        when others => 
         Result_Low <= (others => '0'); 
         Result_High <= (others => '0'); 
       end case; 

      -- for i in 0 to loop_nr loop 
      -- loop_nr  <= to_integer(unsigned(OperandB)); 
      -- Result_Low <= OperandA(2 downto 0)&'0'; 
      -- Result_High <= tempHigh(2 downto 0) & OperandA(3); 
      -- end loop; 

      Ready <= '1'; 
      Errorsig <= '0'; 

Ce qui donne:

alu test bench with case statement

La bonne réponse (tout sans utiliser loop_nr du signal).

Notez que tous les choix dans l'instruction case ne sont pas couverts par le banc d'essai simple .

Et bien sûr, comme la plupart des choses, il y a plus de deux façons d'obtenir le résultat désiré.

Vous pouvez utiliser successive de 2 à 1 multiplexeurs à deux Result_High et Result_Low, chaque étage alimenté à partir de la sortie de l'étage précédent (ou operandA pour la première étape) comme une entrée de la sélection étant la appropriée » bit 'd'OperandB, et l'entrée B aux multiplexeurs l'étape précédente sortie décalée de 1 logiquement (' 0 'rempli).

Les multiplexeurs peuvent être des fonctions, des composants ou des instructions de procédure. Par en utilisant un multiplexeur trois à un, vous pouvez mettre en œuvre à la fois le décalage symétrique Opérations spécifiées d'opération (gauche et droite). Si vous souhaitez inclure des quarts de travail signés, au lieu des quarts de travail remplis à droite, vous pouvez remplir la valeur du bit de signe.

Vous devez également affecter la valeur Prêt < = '0' pour les cas où des valeurs d'opération successives peuvent être distribuées.

Et parce que votre commentaire sur l'une des réponses nécessite l'utilisation d'une boucle avec une valeur entière:

process (reset_n, clk, operation) 
     variable tempHigh : std_logic_vector(4 downto 0); 
     variable tempLow:  std_logic_vector(3 downto 0); --added 
     variable loop_int: integer range 0 to 15; --added 
    begin 
     if (reset_n = '0') then 
     Result_Low <= (others => '0'); 
     Result_High <= (others => '0'); 
     Errorsig <= '0'; 
     elsif (clk'event and clk = '1') then 
     case operation is 
      when "001" => 
       tempLow := OperandA; --added 
       tempHigh := (others => '0'); --added 
       loop_int := to_integer(unsigned(OperandB)); --added 

      -- for i in 0 to loop_nr loop 
      -- loop_nr  <= to_integer(unsigned(OperandB)); 
      -- Result_Low <= OperandA(2 downto 0)&'0'; 
      -- Result_High <= tempHigh(2 downto 0) & OperandA(3); 
      -- end loop; 

-- More added: 
     if loop_int /= 0 then 
      for i in 1 to loop_int loop 
       tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3); 
       -- 'read' tempLow(3) before it's updated 
       tempLow := tempLow(2 downto 0) & '0'; 
      end loop; 
      Result_Low <= tempLow; 
      Result_High <= tempHigh(3 downto 0); 
     else 
      Result_Low <= OperandA; 
      Result_High <= (others => '0'); 
     end if; 
     Ready <= '1'; 
     Errorsig <= '0'; 

Ce qui donne: alu_tb with loop variables

Et pour démontrer les deux moitiés de résultats sont de travail operandA pour valeur par défaut a été changé pour "0110":

alu_tb with loop variables OperandA is "0110"

Notez également que la boucle commence à 1 au lieu de 0 pour vous éviter d'avoir un décalage supplémentaire et qu'il y a une vérification de loop_int non nulle pour empêcher la boucle for de s'exécuter au moins une fois.

Et est-il possible de faire une boucle synthétisable dans ces circonstances?

Oui.

La boucle doit faire face à tous les changements possibles (la gamme de loop_int) et vérifier si oui ou non i tombe sous le seuil de changement:

process (reset_n, clk, operation) 
    variable tempHigh : std_logic_vector(4 downto 0); 
    variable tempLow:  std_logic_vector(3 downto 0); --added 
    subtype loop_range is integer range 0 to 15; 
    variable loop_int: integer range 0 to 15; --added 
    begin 
    if (reset_n = '0') then 
     Result_Low <= (others => '0'); 
     Result_High <= (others => '0'); 
     Errorsig <= '0'; 
    elsif (clk'event and clk = '1') then 
    case operation is 
     when "001" => 
      tempLow := OperandA; --added 
      tempHigh := (others => '0'); --added 
      loop_int := to_integer(unsigned(OperandB)); --added 
     for i in loop_range loop 
      if i < loop_int then 
       tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3); 
       -- 'read' tempLow(3) before it's updated 
       tempLow := tempLow(2 downto 0) & '0'; 
      end if; 
     end loop; 
      Result_Low <= tempLow; 
      Result_High <= tempHigh(3 downto 0); 
+0

Merci beaucoup. J'ai corrigé mon code de cette façon: – user3690624

+0

Vous avez de la chance de ne pas vous faire patauger dans l'implémentation séquentielle (shift par clock) aussi. Aurait eu si vous avez commencé à mettre en œuvre. – user1155120