web-dev-qa-db-fra.com

VHDL: déterminez le nombre de lignes sélectionnées

J'essaie de créer un levier de vitesses réutilisable. il prend un tableau de bits en entrée et les décale d'un certain nombre de positions (déterminé par une autre entrée). Je veux paramétrer le module de sorte qu'il fonctionne pour tout n.

Le nombre de lignes de sélection requises est déterminé par n -> i.e., SHIFT_CNT = log2(NUMBITS-1)+1 dans le code ci-dessous. Il est considéré comme une mauvaise forme dans mon organisation (et dans l'ensemble, je pense) d'avoir des ports qui ne sont pas de std_logic_vector ou std_logic. J'ai donc utilisé un std_logic_vector pour le nombre de lignes sélectionnées. Je dois ajuster la longueur du std_logic_vector en fonction du générique d'entrée. Y a-t-il un moyen de faire cela sans utiliser un deuxième générique? J'ai vu ceci post, mais il ne traite pas des génériques. Ceci post élimine entièrement les génériques ou utilise la valeur de journal comme générique, ce qui n'est pas aussi intuitif pour les futurs utilisateurs (et pourrait causer des problèmes si la INPUT n'est pas une puissance de deux).

La déclaration de SHIFT_CNT ci-dessous est définitivement incorrecte; existe-t-il un moyen de générer automatiquement la longueur dans la déclaration d'entité sans utiliser un deuxième générique?

entity BarrelShifter is

generic ( NUMBITS : integer :=8);                                                   
Port    ( INPUT     : in   std_logic_vector (NUMBITS-1 downto 0);                
          OUTPUT    : out  std_logic_vector (NUMBITS-1 downto 0);                
          SHIFT_CNT : in   std_logic_vector ((NUMBITS-1)'length downto 0)                 
        );                                                               
end BarrelShifter;
10
NickD

Vous pouvez utiliser la bibliothèque mathématique pour calculer log2 et ceil du résultat logarit pour déclarer la taille de SHIFT_CNT.

use IEEE.math_real.all;

ou des fonctions spécifiques

use IEEE.math_real."ceil";
use IEEE.math_real."log2";

Par exemple, vous voulez calculer la valeur clog2 a

result := integer(ceil(log2(real(a))));

Si vous utilisez simplement cette fonction pour calculer le paramètre , votre code est synthétisable (je l'ai fait) .

Si vous ne voulez pas l'utiliser dans des entités, vous pouvez les déclarer dans une bibliothèque ou génériques avec ces fonctions.

14
Khanh N. Dang

Vous pouvez créer une fonction log2 dans une bibliothèque, comme ceci:

   function f_log2 (x : positive) return natural is
      variable i : natural;
   begin
      i := 0;  
      while (2**i < x) and i < 31 loop
         i := i + 1;
      end loop;
      return i;
   end function;

Si la bibliothèque est importée, vous pouvez alors spécifier le port comme suit:

shift_cnt : in std_logic_vector(f_log2(NUMBITS)-1 downto 0)

C'est une solution un peu laide, mais elle n'utilise aucune ressource (puisque la fonction est pure et que toutes les entrées sont connues au moment de la compilation).

Je fais généralement cela, mais vous préférerez peut-être spécifier la valeur du journal sous la forme générique, comme vous le mentionnez.

7
pc3e

Deux approches alternatives:

Vous pouvez le travailler à l'envers et avoir la generic sous la forme shift_bits - puis calculer la largeur des vecteurs d'entrée et de sortie à partir de celle-ci:

generic ( shift_bits: integer :=3);                                                   
Port    ( INPUT     : in   std_logic_vector ((2**shift_bits)-1 downto 0);                
          OUTPUT    : out  std_logic_vector ((2**shift_bits)-1 downto 0);                
          SHIFT_CNT : in   std_logic_vector (shift_bits-1 downto 0)                 
        ); 

Ou traitez le compte comme un nombre:

generic ( NUMBITS : integer :=8);                                                   
Port    ( INPUT     : in   std_logic_vector (NUMBITS-1 downto 0);                
          OUTPUT    : out  std_logic_vector (NUMBITS-1 downto 0);                
          SHIFT_CNT : in   integer range 0 to numbits-1                 
        );  

et laissez les outils le comprendre pour vous.

3
Martin Thompson

Vous pouvez au lieu de saisir la valeur NUMBITS en tant que 8, entrez-la en tant que 2 (log2 (8)), puis retapez-la comme ci-dessous pour résoudre le problème. Votre générique ne sera tout simplement pas aussi propre, mais il est évolutif.

entity BarrelShifter is

generic ( NUMBITS : integer :=2);                                                   
Port    ( INPUT     : in   std_logic_vector (((2**Nbits)-1) downto 0);                
          OUTPUT    : out  std_logic_vector (((2**Nbits)-1) downto 0);                
          SHIFT_CNT : in   std_logic_vector ((NUMBITS-1) downto 0)                 
        );                                                               
end BarrelShifter;
0
Ben Parkes

Lorsque j'utilisais la méthode mentionnée par Khan, j'ai rencontré des erreurs d'arrondi. J'ai donc écrit mes propres versions, insensibles aux erreurs d'arrondi et pouvant, en principe, prendre en charge plus de 32 bits. Vous pouvez remplacer le type de L par n’importe quel type ayant un opérateur de décalage logique gauche.

La plupart du temps, vous souhaitez utiliser log2ceil, qui correspond au nombre de bits requis pour stocker le nombre donné, tandis que log2floor peut être davantage décrit comme l'ensemble de bits le plus élevé.

Dans la plupart des cas, ces fonctions conviennent à la synthèse car elles sont utilisées pour générer des constantes. Donc, aucun matériel n'est déduit pour eux.

function log2ceil (L: POSITIVE) return NATURAL is
    variable i, bitCount : natural;
begin
    i := L-1;
    bitCount:=0;
    while (i > 0) loop
        bitCount := bitCount + 1;
        i:=srlInteger(i,1);
    end loop;
    return bitCount;
end log2ceil;

function log2floor (L: POSITIVE) return NATURAL is
    variable i, bitCount : natural;
begin
    i := L;
    bitCount:=0;
    while (i > 1) loop
        bitCount := bitCount + 1;
        i:=srlInteger(i,1);
    end loop;
    return bitCount;
end log2floor;

function srlInteger(arg: integer; s:natural) return integer is
begin
    return to_integer(SHIFT_RIGHT(to_UNSIGNED(ARG,32), s));
end srlInteger;
0
Karsten Becker