En mi curso introductorio de diseño de Sistemas Digitales. Nos pidieron simular un decodificador de 4 a 16 usando VHDL y modelSim. Todo compilado correctamente. Sin embargo, cuando trato de probar mi programa en el banco de pruebas, recibo un error extraño que indica que ni siquiera mi instructor pudo identificar el problema.
--Código para 4 a 16 decodificador
library ieee;
use ieee.std_logic_1164.all;
entity decoder4to16 is
port
(
X: in STD_LOGIC_VECTOR(3 downto 0);
EN: in STD_LOGIC;
Y: out STD_LOGIC_VECTOR (0 TO 15));
end decoder4to16;
architecture decoder4to16_arch of decoder4to16 is
signal Y_t: STD_LOGIC_VECTOR (0 TO 15);
begin
process(X,EN)
begin
case X is
when "0000" => Y_t<="0111111111111111";
when "0001" => Y_t<="1011111111111111";
when "0010" => Y_t<="1101111111111111";
when "0011" => Y_t<="1110111111111111";
when "0100" => Y_t<="1111011111111111";
when "0101" => Y_t<="1111101111111111";
when "0110" => Y_t<="1111110111111111";
when "0111" => Y_t<="1111111011111111";
when "1000" => Y_t<="1111111101111111";
when "1001" => Y_t<="1111111110111111";
when "1010" => Y_t<="1111111111011111";
when "1011" => Y_t<="1111111111101111";
when "1100" => Y_t<="1111111111110111";
when "1101" => Y_t<="1111111111111011";
when "1110" => Y_t<="1111111111111101";
when "1111" => Y_t<="1111111111111110";
when others => Y_t<="1111111111111111";
end case;
if(EN)='0' then Y<=Y_t;
else Y<="1111111111111111";
end if;
end process;
end decoder4to16_arch;
-- y aquí está el código de mi banco de pruebas
library ieee;
use ieee.std_logic_1164.all;
entity decoder4to16_tb is
end decoder4to16_tb;
architecture decoder4to16_tb of decoder4to16_tb is
component decoder4to16
port
(
X: in STD_LOGIC_VECTOR(3 downto 0);
EN: in STD_LOGIC;
Y: out STD_LOGIC_VECTOR (0 TO 15));
end component;
signal X: STD_LOGIC_VECTOR (3 downto 0):="0000";
signal E: STD_LOGIC:='0';
signal Y: STD_LOGIC_VECTOR (0 TO 15);
begin
U0: decoder4to16 port map (X,E,Y);
process
begin
E<='1'; X<="0000"; wait for 100 ns;
E<='0'; X<="0000"; wait for 100 ns;
X<="0001"; wait for 100 ns;
X<="0010"; wait for 100 ns;
X<="0011"; wait for 100 ns;
wait;
end process;
end decoder4to16_tb;
Ahora, la parte extraña, cuando trato de simular el banco de pruebas y mostrar las formas de onda, es como si hubiera un retraso para las entradas "0001" y superiores.
es como si hubiera algún tipo de retraso
Para asegurarse de que este "retraso" está ahí
Gracias.
Podría hacer un mejor trabajo en su pregunta describiendo lo que está mal con los resultados, en lugar de proporcionar una imagen.
Se vuelve evidente si miras el proceso:
process(X,EN)
begin
case X is
when "0000" => Y_t<="0111111111111111";
when "0001" => Y_t<="1011111111111111";
when "0010" => Y_t<="1101111111111111";
when "0011" => Y_t<="1110111111111111";
when "0100" => Y_t<="1111011111111111";
when "0101" => Y_t<="1111101111111111";
when "0110" => Y_t<="1111110111111111";
when "0111" => Y_t<="1111111011111111";
when "1000" => Y_t<="1111111101111111";
when "1001" => Y_t<="1111111110111111";
when "1010" => Y_t<="1111111111011111";
when "1011" => Y_t<="1111111111101111";
when "1100" => Y_t<="1111111111110111";
when "1101" => Y_t<="1111111111111011";
when "1110" => Y_t<="1111111111111101";
when "1111" => Y_t<="1111111111111110";
when others => Y_t<="1111111111111111";
end case;
if EN ='0' then
Y <= Y_t;
else
Y <= "1111111111111111";
end if;
end process;
Tiene un proceso que es sensible a X
y EN
pero (con razón) no Y_t
.
Las asignaciones de señales VHDL se ponen en cola en una forma de onda de salida proyectada .
Una asignación de señal puede tener la forma (IEEE Std 1076-2008, 10.5.2 Asignaciones de señales simples):
simple_waveform_assignment ::= target <= [ delay_mechanism ] waveform ;
Donde una forma de onda:
waveform ::=
waveform_element { , waveform_element }
| unaffected
puede ser un elemento de forma de onda que puede tener una expresión posterior al tiempo :
waveform_element ::=
value_expression [ after time_expression ]
| null [ after time_expression ]
que especifica cuándo está disponible la actualización en el tiempo de simulación relativo. (consulte 10.5.2.2 Ejecución de una declaración de asignación simple):
El tipo base de la expresión de tiempo en cada elemento de forma de onda será el tipo físico predefinido TIME como se define en el paquete STANDARD. Si la cláusula posterior de un elemento de forma de onda no está presente, entonces se supone un " después de 0 ns" implícito. Es un error si la expresión de tiempo en un elemento de forma de onda se evalúa como un valor negativo.
Un valor de señal nunca se actualiza cuando alguna declaración de proceso está pendiente de ejecución en el ciclo de simulación actual.
Una asignación sin una expresión de tiempo posterior , lo que significa que se garantiza que la asignación al tiempo de simulación actual incurrirá en un ciclo delta (un ciclo de simulación sin un cambio en el tiempo de simulación).
Y debido a que el valor del valor recién asignado de Y_t
no está disponible en el ciclo de simulación actual en el que Y
está asignado, obtendrá un retraso basado no en actualizar el valor de Y_t
pero esperando hasta el final del ciclo de simulación, suspendiendo y esperando un evento en una señal en la lista de sensibilidad del proceso.
Ciclo de simulación
El estándar VHDL puede ser difícil de entender para alguien que acaba de empezar, requiere, entre otras cosas, inculcar el vocabulario de VHDL y los planes de estudios no siempre hacen eso.
Hay un par de párrafos en el libro de Peter Ashenden The Designer's Guide to VHDL que pueden ayudar a comprender lo que hace VHDL en la simulación:
La simulación comienza con una fase de inicialización, seguida de la ejecución repetitiva de un ciclo de simulación. Durante la fase de inicialización, a cada señal se le asigna un valor inicial, dependiendo de su tipo. El tiempo de simulación se establece en cero, luego se activa cada instancia de proceso y se ejecutan sus sentencias secuenciales. Por lo general, un proceso incluirá una declaración de asignación de señal para programar una transacción en una señal en algún momento de simulación posterior. La ejecución de un proceso continúa hasta que llega a una declaración de espera, lo que hace que el proceso se suspenda.
Durante el ciclo de simulación, el tiempo de simulación se adelanta primero al siguiente tiempo en el que se ha programado una transacción en una señal. En segundo lugar, se realizan todas las transacciones programadas para ese momento. Esto puede causar que ocurran algunos eventos en algunas señales. Tercero, todos los procesos que son sensibles a esos eventos se reanudan y se les permite continuar hasta que llegan a una declaración de espera y se suspenden. Una vez más, los procesos suelen ejecutar asignaciones de señales para programar más transacciones en las señales. Cuando todos los procesos han vuelto a suspenderse, se repite el ciclo de simulación. Cuando la simulación llega a la etapa en la que no hay más transacciones programadas, se detiene, ya que la simulación se completa.
Elaboración
Todo en un diseño VHDL elaborado está impulsado por eventos de señal que están programados en la forma de onda de salida proyectada para cada señal.
Las sentencias concurrentes se delegan en procesos o sentencias de bloque que proporcionan jerarquía y procesos durante la elaboración. Las llamadas a funciones son expresiones y las llamadas a procedimientos secuenciales son declaraciones. (Las sentencias de llamadas a procedimientos concurrentes se convierten en procesos que contienen sentencias de llamadas a procedimientos secuenciales cuando se elaboran).
Entonces, ¿qué significa esto para su modelo?
Los eventos de señal impulsan la ejecución del modelo. A su modelo de diseño le falta un evento de señal para Y_t
hacer que un proceso reanude la ejecución.
Las listas de sensibilidad en un proceso evitan la inclusión de una declaración de espera explícita e implícitamente proporcionan:
wait on sensitivity_list ;
como la última declaración del proceso, lo que significa, entre otras cosas, que la ejecución se reanuda con la primera declaración.
Ahora, si simplemente agregamos Y_t
a la lista de sensibilidad, nuestro proceso tendría retroalimentación y ciclos delta potencialmente interminables porque actualizaríamos Y_t
qué programa y evento sería sensible al proceso.
Para solucionar esto, puede dejar la lista de sensibilidad en paz y mover la asignación Y
fuera de este proceso, o eliminar la señal Y_t
y asignarla Y
directamente en la declaración del caso que puede incrustar en la siguiente declaración if donde Y_t
ocurre la asignación del valor de.
Potencialmente, podría concatenar EN
con X
una variable nombrada y requerir la posición del elemento de la variable utilizada como una expresión de declaración de caso que representa EN
ser '0', la others
elección cubriría todos los casos cuando Y
deberían ser todos '1' y podría eliminar la declaración if.
Eso podría verse así:
process(X,EN)
variable case_exp: std_logic_vector (4 downto 0);
begin
case_exp := EN & X; -- EN is the leftmost position
case case_exp is
when "00000" => Y <= "0111111111111111";
when "00001" => Y <= "1011111111111111";
when "00010" => Y <= "1101111111111111";
when "00011" => Y <= "1110111111111111";
when "00100" => Y <= "1111011111111111";
when "00101" => Y <= "1111101111111111";
when "00110" => Y <= "1111110111111111";
when "00111" => Y <= "1111111011111111";
when "01000" => Y <= "1111111101111111";
when "01001" => Y <= "1111111110111111";
when "01010" => Y <= "1111111111011111";
when "01011" => Y <= "1111111111101111";
when "01100" => Y <= "1111111111110111";
when "01101" => Y <= "1111111111111011";
when "01110" => Y <= "1111111111111101";
when "01111" => Y <= "1111111111111110";
when others => Y <= "1111111111111111";
end case;
end process;
Cuando la posición más a la izquierda de case_exp
es un '1' EN
no es válida y Y
la posición de ningún elemento es un '0'.
Esto no pretende ser una respuesta completa, pero una forma alternativa de escribir este tipo de decodificador es:
entity decoder is
port (
sel : in std_logic_vector (3 downto 0);
enable : in std_logic;
y : out std_logic_vector(15 downto 0)
);
end decoder;
architecture Behavioral of decoder is
begin
process (sel, enable)
begin
for i in y'range loop
if (i = to_integer(unsigned(sel)) then
y(i) <= not enable;
else
y(i) <= '1';
end if;
end loop;
end process;
end Behavioral;
Tenga en cuenta que mi enable
señal es alta activa. Al agregar un genérico, este método le permite tener una entidad que puede funcionar como un decodificador 3:8, 4:16, 5:32, etc. También podría tener genéricos para controlar si la habilitación y la señal de salida están activas en nivel alto o activo en nivel bajo.