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:
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:
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:
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":
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);
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