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