¿Por qué falla mi simulación VHDL después de una entrada para este dispositivo?

EDITAR: Encontré una solución. Ver la parte inferior de la publicación.

Me pregunto por qué mi simulación de la siguiente entidad no se ejecuta para más de una entrada. Cuando cambio las entradas, el sistema falla y no entiendo por qué.

Tengo la siguiente entidad:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity subtraction is
    port (
        signal clk : in std_logic;
        signal minuend : in std_logic_vector(15 downto 0);
        signal subtrahend : in std_logic_vector(15 downto 0);
        signal difference : out std_logic_vector(15 downto 0)
    );
end subtraction;

architecture datapath of subtraction is

type ROM_ARRAY is array (0 to 9) of std_logic_vector(3 downto 0);
constant ROM: ROM_ARRAY := 
    (
    x"0",
    x"1",
    x"2",
    x"3",
    x"4",
    x"5",
    x"6",
    x"7",
    x"8",
    x"9"
    );

constant thousand : unsigned(11 downto 0) := x"3E8";
constant hundred : unsigned(7 downto 0) := x"64";
constant ten : unsigned(3 downto 0) := x"A";

signal m, s, d: unsigned(14 downto 0);
signal d0, d1, d2, d3 : unsigned(14 downto 0);

begin

m <=    resize(unsigned(minuend(15 downto 12)) * thousand, m'length) + 
        resize(unsigned(minuend(11 downto 8)) * hundred, m'length) +
        resize(unsigned(minuend(7 downto 4)) * ten, m'length) +
        resize(unsigned(minuend(3 downto 0)), m'length);
        
s <=    resize(unsigned(subtrahend(15 downto 12)) * thousand, s'length) + 
        resize(unsigned(subtrahend(11 downto 8)) * hundred, s'length) +
        resize(unsigned(subtrahend(7 downto 4)) * ten, s'length) +
        resize(unsigned(subtrahend(3 downto 0)), s'length);

--d <=  m - s;

d0 <= ((m-s) mod 10); -- (m-s) can be replaced with d if uncommented above
d1 <= ((((m-s) mod 100) - ((m-s) mod 10)) / 10);
d2 <= ((((m-s) mod 1000) - ((m-s) mod 100) - ((m-s) mod 10)) / 100);
d3 <= ((((m-s) mod 10000) - ((m-s) mod 1000) - ((m-s) mod 100) - ((m-s) mod 10)) / 1000);

--difference <= ROM(to_integer(d3))&ROM(to_integer(d2))&ROM(to_integer(d1))&ROM(to_integer(d0));

process(clk)
begin
    difference <= ROM(to_integer(d3))&ROM(to_integer(d2))&ROM(to_integer(d1))&ROM(to_integer(d0));
end process;   

end datapath;

El código puede parecer un poco complicado, pero en realidad es bastante simple. Solo estoy tomando una entrada decimal codificada en binario (de hasta 4 dígitos) y restando otra entrada BCD del mismo tamaño, y luego emitiendo la diferencia en BCD (que es para lo que sirve la matriz vectorial).

Algo de esto es solo para practicar el uso de ciertas cosas que estoy aprendiendo sobre VHDL. Así que, por favor, perdone mi falta de elegancia.

En cualquier caso, el código funciona perfectamente para una entrada. Pero luego falla en el momento en que cambio las entradas. Esto es cierto ya sea que use un proceso para manejar la asignación de un valor final a la diferencia, o si uso el enfoque de lógica puramente combinacional (que actualmente está comentado).

El banco de pruebas es simple y muestra que solo estoy mirando la salida de tres entradas de muestra. Eliminar la asignación de diferencia y las asignaciones d0 a d3 permite que el código continúe a través del banco de pruebas (y esto es verificable si agrega una señal interna de solo prueba al banco de pruebas, o expone los valores en m, s y (opcionalmente) d ).

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity subtraction_tb is
--  Port ( );
end subtraction_tb;

architecture Behavioral of subtraction_tb is

signal clktb : std_logic;
signal mtb, stb, dtb : std_logic_vector(15 downto 0);
signal moutb, soutb,doutb : std_logic_vector(14 downto 0);
--signal m0tb, m1tb, m2tb, m3tb : std_logic_vector(14 downto 0);

begin

uut : entity work.subtraction
    port map (
    clk => clktb,
    minuend => mtb,
    subtrahend => stb,
    difference => dtb
    );

clock : process
begin
    clktb <= '1';
    wait for 5 ns;
    clktb <= '0';
    wait for 5 ns;
end process;

testing : process
begin
    mtb <= x"1430";
    stb <= x"0430";
    wait for 10 ns;
    mtb <= x"9450";
    stb <= x"9320";
    wait for 10 ns;
    mtb <= x"9000";
    stb <= x"8111";
    wait for 10 ns;
wait;
end process;

end Behavioral;

Estoy francamente confundido por qué las asignaciones "d" crean esta travesura en mi entidad. En términos puramente combinatorios, y en comparación con otros proyectos que he hecho, todo se ve arriba a bordo.

Cualquier idea sería muy apreciada.

EDITAR PARA AGREGAR DETALLES DEL ERROR :

Como algunas personas han pedido detalles del simulador y del error. El simulador es Xilinx Vivado, no hay error. Más bien, la simulación se ejecuta y muestra el resultado de la primera entrada. Pero solo muestra la salida para esa entrada. Es como si el banco de pruebas solo tuviera hasta la primera declaración de espera de 10 ns, y luego se detuviera, sin mostrar nada después de 10 ns.

Va automáticamente de la forma de onda al código, y aparece una flecha que apunta a la línea donde asigno la diferencia; sin embargo, esa flecha, la consola y el registro elaborado no contienen ningún mensaje que indique lo que podría estar sucediendo. Simplemente hace esto que he descrito.

Si esto no es lo suficientemente claro, encontraré tiempo para publicar la forma de onda más tarde, para demostrar lo que quiero decir.

Aquí están las formas de onda :

forma de onda

Flecha a línea

Más adiciones :

He estado tratando de tener en cuenta la posibilidad de que al simulador no le guste la adición que estoy haciendo, lo que podría resultar en un valor mayor que el tamaño del vector que probé. Con ese fin, aquí hay un ejemplo de un intento de solución que resulta en una completa tontería en la salida.

Código:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity bdc_subtraction is
    port (
        --Internal Testing Signals
        signal mout, sout: out std_logic_vector(18 downto 0);
        signal dout : out std_logic_vector(18 downto 0);
        --signal m0t, m1t, m2t, m3t, s0t, s1t, s2t, s3t : out std_logic_vector(14 downto 0);
        signal m0t : out std_logic_vector(15 downto 0);
        signal m1t : out std_logic_vector(15 downto 0);
        signal m2t : out std_logic_vector(15 downto 0);
        signal m3t : out std_logic_vector(15 downto 0);
        signal s0t : out std_logic_vector(15 downto 0);
        signal s1t : out std_logic_vector(15 downto 0);
        signal s2t : out std_logic_vector(15 downto 0);
        signal s3t : out std_logic_vector(15 downto 0);
        --Inputs and outputs
        signal clk : in std_logic;
        signal minuend : in std_logic_vector(15 downto 0);
        signal subtrahend : in std_logic_vector(15 downto 0);
        signal difference : out std_logic_vector(15 downto 0)
    );
end bdc_subtraction;

architecture datapath of bdc_subtraction is

type ROM_ARRAY is array (0 to 9) of std_logic_vector(3 downto 0);
constant ROM: ROM_ARRAY := 
    (
    x"0",
    x"1",
    x"2",
    x"3",
    x"4",
    x"5",
    x"6",
    x"7",
    x"8",
    x"9"
    );

constant thousand : unsigned(11 downto 0) := x"3E8";
constant hundred : unsigned(7 downto 0) := x"64";
constant ten : unsigned(3 downto 0) := x"A";

signal m, s: unsigned(18 downto 0);

signal m0 : unsigned(15 downto 0);
signal m1 : unsigned(15 downto 0);
signal m2 : unsigned(15 downto 0);
signal m3 : unsigned(15 downto 0);

signal s0 : unsigned(15 downto 0);
signal s1 : unsigned(15 downto 0);
signal s2 : unsigned(15 downto 0);
signal s3 : unsigned(15 downto 0);

signal d0, d1, d2, d3 : unsigned(14 downto 0);
signal d : unsigned(18 downto 0) := (others => '0');

begin
--Testing Signals
mout <= std_logic_vector(m);
sout <= std_logic_vector(s);
dout <= std_logic_vector(d);
m0t <= std_logic_vector(m0);
m1t <= std_logic_vector(m1);
m2t <= std_logic_vector(m2);
m3t <= std_logic_vector(m3);
s0t <= std_logic_vector(s0);
s1t <= std_logic_vector(s1);
s2t <= std_logic_vector(s2);
s3t <= std_logic_vector(s3);

-- COMBINATIONAL LOGIC

m3 <=   resize(unsigned(minuend(15 downto 12)) * 1000, m3'length);
m2 <=   resize(unsigned(minuend(11 downto 8)) * 100, m2'length);
m1 <=   resize(unsigned(minuend(7 downto 4)) * 10, m1'length);
m0 <=   resize(unsigned(minuend(3 downto 0)), m0'length);

s3 <=   resize(unsigned(subtrahend(15 downto 12)) * 1000, s3'length);
s2 <=   resize(unsigned(subtrahend(11 downto 8)) * 100, s2'length);
s1 <=   resize(unsigned(subtrahend(7 downto 4)) * 10, s1'length);
s0 <=   resize(unsigned(subtrahend(3 downto 0)), s0'length);

m <=    resize(m3+m2+m1+m0, m'length);
s <=    resize(s3+s2+s1+s0, s'length);

d <=    (m-s);

--d0 <= (d mod 10);
--d1 <= (((d mod 100) - (d mod 10)) / 10);
--d2 <= (((d mod 1000) - (d mod 100) - (d mod 10)) / 100);
--d3 <= (((d mod 10000) - (d mod 1000) - (d mod 100) - (d mod 10)) / 1000);

--difference <= ROM(to_integer(d3))&ROM(to_integer(d2))&ROM(to_integer(d1))&ROM(to_integer(d0));


end datapath;

Y aquí está el banco de pruebas ligeramente modificado:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity bcd_subtraction_tb is
--  Port ( );
end bcd_subtraction_tb;

architecture Behavioral of bcd_subtraction_tb is

signal clktb : std_logic;
signal mtb, stb, dtb : std_logic_vector(15 downto 0);
signal moutb, soutb : std_logic_vector(18 downto 0);
signal doutb : std_logic_vector(18 downto 0);
signal m0tb : std_logic_vector(15 downto 0);
signal m1tb : std_logic_vector(15 downto 0);
signal m2tb : std_logic_vector(15 downto 0);
signal m3tb : std_logic_vector(15 downto 0);
signal s0tb : std_logic_vector(15 downto 0);
signal s1tb : std_logic_vector(15 downto 0);
signal s2tb : std_logic_vector(15 downto 0);
signal s3tb : std_logic_vector(15 downto 0);




begin

uut: entity work.bdc_subtraction
    port map (
    --Internal Testings
    mout => moutb,
    sout => soutb,
    dout => doutb,
    m0t => m0tb,
    m1t => m1tb,
    m2t => m2tb,
    m3t => m3tb,
    s0t => s0tb,
    s1t => s1tb,
    s2t => s2tb,
    s3t => s3tb,
    --Standards
    clk => clktb,
    minuend => mtb,
    subtrahend => stb,
    difference => dtb
    );

clock : process
begin
    clktb <= '1';
    wait for 5 ns;
    clktb <= '0';
    wait for 5 ns;
end process;

testing : process
begin
    mtb <= x"1430";
    stb <= x"0430";
    wait for 10 ns;
    mtb <= x"9450";
    stb <= x"9320";
    wait for 10 ns;
    mtb <= x"9000";
    stb <= x"8111";
    wait for 10 ns;
    --std.env.stop(0);
wait;
end process;

end Behavioral;

Mientras que la versión anterior daba la salida correcta para una sola entrada, esta versión no da nada correcto como salida y, en cambio, proporciona valores bastante interesantes para m2, m3 y s2 y s3. No estoy seguro de por qué, todavía.

ingrese la descripción de la imagen aquí

También quiero agregar, también he intentado hacer esto (y modificar las otras señales en consecuencia):

signal m0t : out std_logic_vector(3 downto 0);
signal m1t : out std_logic_vector(7 downto 0);
signal m2t : out std_logic_vector(11 downto 0);
signal m3t : out std_logic_vector(15 downto 0);
signal s0t : out std_logic_vector(3 downto 0);
signal s1t : out std_logic_vector(7 downto 0);
signal s2t : out std_logic_vector(11 downto 0);
signal s3t : out std_logic_vector(15 downto 0);

Esto se basa en la idea de que para dos vectores, de n y m bits respectivamente, el producto no tendrá una longitud mayor que n+m bits. Los resultados se identifican exactamente con el uso de todos los vectores de 16 bits, como en el código inmediatamente superior a este segmento.

Me pregunto si resize() se comporta un poco diferente de lo esperado, o si la adición de vectores de diferentes tamaños está causando algún tipo de error de desbordamiento en alguna parte. Por ejemplo, si X es mayor que Y en longitud de bits, X+Y podría ser mayor que X, por lo que tal vez una pequeña concatonación podría funcionar como una solución.

Lo intentaré, pero cualquier otro pensamiento sigue siendo bienvenido.

SOLUCIÓN

Hubo dos problemas con este código. Primero, la adición utilizada para asignar valores a "m" y "s" causó problemas porque vivado no podía estar seguro de los tamaños de los vectores, ya que no tenía forma de saber que tenía una entrada limitada para evitar situaciones ilegales. Después de arreglar eso, obtuve resultados bastante extraños. Para arreglar eso, simplemente tuve que usar los vectores constantes de mil, cien y diez que no había estado usando previamente. Por alguna razón, parece que Vivado estaba interpretando las líneas así:

s3 <=   resize(unsigned(subtrahend(15 downto 12)) * 1000, s3'length);

como un vector sin signo multiplicado por un vector, y no como un número natural. Entonces esto se tradujo como * 8 en lugar de * 1000. Por otro lado, lo siguiente funciona bien:

constant thousand : unsigned(11 downto 0) := x"3E8";
[...]
s3 <=   resize(unsigned(subtrahend(15 downto 12)) * thousand, s3'length);

No sé por qué hace esto, ya que 1000 no estaba entre comillas para indicar un valor binario o hexadecimal. Numeric_std admite {unsigned * natural}, por lo que mi mejor suposición es que la función de cambio de tamaño está haciendo algo inesperado. Pero no lo sé con certeza, porque no he desenterrado el código para cambiar el tamaño. Si tengo tiempo para investigarlo, veré si puedo resolver este comportamiento y actualizaré esta publicación.

¿Qué simulador estás usando?
¿Cuál es el error real: por "el sistema falla" te refieres a una pantalla azul de Windows o qué? Publique el error real en la pregunta.
Si elimina el UUT, ¿simulará los 30 ns completos?
He agregado las formas de onda y una descripción del error. Como se indica en la publicación, vhdl.log, elabora.log, la consola TCL y la consola de mensajes, etc., no contienen ninguna indicación de lo que indica esta flecha. Pasar el mouse sobre la línea resaltada solo muestra "1000", que es el valor asignado de diferencia dadas las dos entradas iniciales. @po.pe No estoy seguro de lo que quieres decir? ¿Si elimino "uut:" y dejo el mapa del puerto de la entidad, o si elimino toda la entidad?
Eliminar toda la entidad
@po.po: Sí, si elimino la entidad, superará cada una de las tres condiciones de prueba. Por supuesto, los resultados se vuelven desconocidos, pero eso es de esperar.
Una cosa que debe verificar es la longitud resultante de su minuendy subtrahendsuma. No se pueden sumar dos números de tamaño ny esperar que encajen en otra señal de tamaño n.
@po.pe: En este caso, puedo garantizar que el minuendo es mayor que el sustraendo según la entrada, por lo que no debería ser posible que el vector de diferencia sea demasiado pequeño ya que minuendo-sustraendo <minuendo en todos los casos. Pero supongo que vivado podría no saber eso, y por lo tanto puede experimentar un problema. Puedo intentar hacer que los vectores de diferencia sean uno más largos para ver qué sucede, ya que eso debería encajar incluso en una adición hipotética. Te dejaré saber si funciona.

Respuestas (1)

Según el consejo de algunas personas aquí, he informado la interpretación errónea de 1000 como 8

SOLUCIÓN (publicando aquí para que pueda marcar este problema como 'resuelto' mañana)

Hubo dos problemas con este código. Primero, la adición utilizada para asignar valores a "m" y "s" causó problemas porque vivado no podía estar seguro de los tamaños de los vectores, ya que no tenía forma de saber que tenía una entrada limitada para evitar situaciones ilegales. Después de arreglar eso, obtuve resultados bastante extraños. Para arreglar eso, simplemente tuve que usar los vectores constantes de mil, cien y diez que no había estado usando previamente. Por alguna razón, parece que Vivado estaba interpretando las líneas así:

s3 <=   resize(unsigned(subtrahend(15 downto 12)) * 1000, s3'length);

como un vector sin signo multiplicado por un vector, y no como un número natural. Entonces esto se tradujo como * 8 en lugar de * 1000. Por otro lado, lo siguiente funciona bien:

constant thousand : unsigned(11 downto 0) := x"3E8";
[...]
s3 <=   resize(unsigned(subtrahend(15 downto 12)) * thousand, s3'length);

No sé por qué hace esto, ya que 1000 no estaba entre comillas para indicar un valor binario o hexadecimal. Numeric_std admite {unsigned * natural}, por lo que mi mejor suposición es que la función de cambio de tamaño está haciendo algo inesperado. Pero no lo sé con certeza, porque no he desenterrado el código para cambiar el tamaño. Si tengo tiempo para investigarlo, veré si puedo resolver este comportamiento y actualizaré esta publicación.

Tal vez puedas publicar esto en los foros de Xilinx, para que puedan solucionarlo si se trata de un error.
Eso (malinterpretando 1000) tiene que ser un error de Vivado. Reportalo.