Resultados inesperados al multiplicar en VHDL

5

Estoy tratando de hacer un BCD simple - > Trabajo de operación de conversión binaria en una ALU Estoy codificando. Todas las demás operaciones funcionan perfectamente bien, solo que esta última operación no funciona por alguna razón.

He intentado numerosos enfoques y nada parece tener sentido.

Mis entradas son A y B , que son vectores de 8 bits. Las salidas son X y Y .

Entonces la fórmula va Y:X = BCD2BIN(B:A) .

En mi caso, en mi banco de pruebas tengo B = 0x40 y A = 0x46 , por lo que la salida que estoy esperando es 0xFCE , que es 4046.

Solo para aquellos que no lo saben, la forma más sencilla de realizar esto es dividir cada byte en 2 nibbles, y multiplicar por una constante y sumar los términos.

Entonces:

B:A = 0x4046 = (4 * 1000) + (0 * 100) + (4 * 10) * (6 * 1)

Señales que estoy usando

B = 0x40  --These are the inputs of the ALU, so it isn't actually coded this way.
A = 0x46  --However these are the values.

signal sig1000 : STD_LOGIC_VECTOR(15 downto 0) := x"03E8"; --1000
signal sig100 : STD_LOGIC_VECTOR(15 downto 0) := x"0064";  --100
signal sig10 : STD_LOGIC_VECTOR(15 downto 0) := x"000A";  --10

signal dig1 : STD_LOGIC_VECTOR(3 downto 0);
signal dig2 : STD_LOGIC_VECTOR(3 downto 0);
signal dig3 : STD_LOGIC_VECTOR(3 downto 0);
signal dig4 : STD_LOGIC_VECTOR(3 downto 0);

Después de COMENZAR

dig1 <= B(7 downto 4);
dig2 <= B(3 downto 0);
dig3 <= A(7 downto 4);
dig4 <= A(3 downto 0);

Operación real

opF <= STD_LOGIC_VECTOR((unsigned(dig1) * unsigned(sig1000)) + (unsigned(dig2) * unsigned(sig100)) + (unsigned(dig3) * unsigned(sig10)) + (unsigned(dig4)));

Y luego el opF se divide en Y y X.

Así que incluso verificando las señales en la simulación, son correctas, pero la salida no lo es.

Los valores correctos son sig10001 , sig100 y sig10 , y dig1 = 4 , dig2 = 0 , dig3 = 4 y dig4 = 6 con una raíz decimal sin signo.

Sin embargo, el resultado es 252

Incluso he intentado esto utilizando constantes, en lugar de vectores, con menos éxito.

Por ejemplo

opF <= STD_LOGIC_VECTOR((unsigned(dig1) * 10#1000#) + (unsigned(dig2) * 10#100#) + (unsigned(dig3) * 10#10#) + (unsigned(dig4)));

Archivo completo , como han solicitado algunos.

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

entity ALU is
Port ( A : in  STD_LOGIC_VECTOR (7 downto 0);
       B : in  STD_LOGIC_VECTOR (7 downto 0);
       Cin : in  STD_LOGIC;
       OPCODE : in  STD_LOGIC_VECTOR (3 downto 0);
       Y : out  STD_LOGIC_VECTOR (7 downto 0);
       X : out  STD_LOGIC_VECTOR (7 downto 0);
       Z : out  STD_LOGIC;
       Cout : out  STD_LOGIC;
       V : out  STD_LOGIC;
       F_active : out  STD_LOGIC;
       X_bin_pal : out  STD_LOGIC;
       X_prime : out  STD_LOGIC;
       N : out  STD_LOGIC);
end ALU;

architecture Behavioral of ALU is

    signal resultSignal : STD_LOGIC_VECTOR(15 downto 0);

    signal cin_vector : STD_LOGIC_VECTOR(0 downto 0);

    signal op0 : STD_LOGIC_VECTOR(15 downto 0);
    signal op1 : STD_LOGIC_VECTOR(15 downto 0);
    signal op2 : STD_LOGIC_VECTOR(15 downto 0);
    signal op3 : STD_LOGIC_VECTOR(15 downto 0);
    signal op4 : STD_LOGIC_VECTOR(15 downto 0);
    signal op5 : STD_LOGIC_VECTOR(15 downto 0);
    signal op6 : STD_LOGIC_VECTOR(15 downto 0);
    signal op7 : STD_LOGIC_VECTOR(15 downto 0);
    signal op8 : STD_LOGIC_VECTOR(15 downto 0);
    signal op9 : STD_LOGIC_VECTOR(15 downto 0);
    signal opA : STD_LOGIC_VECTOR(15 downto 0);
    signal opB : STD_LOGIC_VECTOR(15 downto 0);
    signal opC : STD_LOGIC_VECTOR(15 downto 0);
    signal opD : STD_LOGIC_VECTOR(15 downto 0);
    signal opE : STD_LOGIC_VECTOR(15 downto 0);
    signal opF : STD_LOGIC_VECTOR(15 downto 0);

    signal dig1 : STD_LOGIC_VECTOR(3 downto 0);
    signal dig2 : STD_LOGIC_VECTOR(3 downto 0);
    signal dig3 : STD_LOGIC_VECTOR(3 downto 0);
    signal dig4 : STD_LOGIC_VECTOR(3 downto 0);

    signal Xsig : STD_LOGIC_VECTOR(7 downto 0) := x"00";
    signal Xsig_reverse : STD_LOGIC_VECTOR(7 downto 0) := x"00";

    signal Ysig : STD_LOGIC_VECTOR(7 downto 0) := x"00";

    signal Zsig : STD_LOGIC := '0';
    signal Coutsig : STD_LOGIC := '0';
    signal Vsig : STD_LOGIC := '0';
    signal Nsig : STD_LOGIC := '0';

    signal sig1000 : STD_LOGIC_VECTOR(15 downto 0) := x"03E8";
    signal sig100 : STD_LOGIC_VECTOR(15 downto 0) := x"0064";
    signal sig10 : STD_LOGIC_VECTOR(15 downto 0) := x"000A";



begin

cin_vector(0) <= Cin;

dig1 <= B(7 downto 4);
dig2 <= B(3 downto 0);
dig3 <= A(7 downto 4);
dig4 <= A(3 downto 0);

op0 <= x"00" & (A AND B);
op1 <= x"00" & (A OR B);
op2 <= x"00" & (A XOR B);
op3 <= x"00" & (A XNOR B);
op4 <= STD_LOGIC_VECTOR(unsigned(x"00" & A) + unsigned(x"00" & B));
op5 <= x"00" & STD_LOGIC_VECTOR(signed(A) + signed(B));
op6 <= STD_LOGIC_VECTOR(unsigned(x"00" & A) + unsigned(x"00" & B) + unsigned(x"000" & "000" & cin_vector));
op7 <= STD_LOGIC_VECTOR(signed(A) * signed(B));
op8 <= STD_LOGIC_VECTOR(unsigned(A) * unsigned(B));
op9 <= STD_LOGIC_VECTOR(unsigned(x"00" & A) - unsigned(x"00" & B));
opA <= STD_LOGIC_VECTOR(ROTATE_LEFT(unsigned(A & x"00"), 1));
opB <= STD_LOGIC_VECTOR(ROTATE_LEFT(unsigned(Cin & A & "0000000"), 1));
opC <= STD_LOGIC_VECTOR(SHIFT_RIGHT(unsigned(A & x"00"), 1));
opD <= STD_LOGIC_VECTOR(SHIFT_RIGHT(signed(A & x"00"), 1));
opE <= STD_LOGIC_VECTOR(SHIFT_LEFT(unsigned(A & x"00"), 1));
opF <= STD_LOGIC_VECTOR((unsigned(dig1) * unsigned(sig1000)) + (unsigned(dig2) * unsigned(sig100)) + (unsigned(dig3) * unsigned(sig10)) + (unsigned(dig4)));

with OPCODE select resultSignal <=
     op0 when x"0",
     op1 when x"1",
     op2 when x"2",
     op3 when x"3",
     op4 when x"4",
     op5 when x"5",
     op6 when x"6",
     op7 when x"7",
     op8 when x"8",
     op9 when x"9",
     opA when x"A",
     opB when x"B",
     opC when x"C",
     opD when x"D",
     opE when x"E",
     opF when x"F";


Ysig <= resultSignal(15 downto 8) when OPCODE = "0111" or OPCODE = "1000" or OPCODE = "1111" else
        x"00";

Y <= Ysig;

Xsig <=     resultSignal(15 downto 8) when OPCODE = "1100" or OPCODE = "1101" or OPCODE = "1110" else
            resultSignal(15 downto 9) & resultSignal(0) when OPCODE = "1010" else
            resultSignal(14 downto 8) & resultSignal(0) when OPCODE = "1011" else
            resultSignal(7 downto 0);

Xsig_reverse <= Xsig(0) & Xsig(1) & Xsig(2) & Xsig(3) & Xsig(4) & Xsig(5) & Xsig(6) & Xsig(7);

X <= Xsig;

Zsig <=     '1' when resultSignal = x"0000" else
        '0';

Z <= Zsig;

Coutsig <=  resultSignal(8) when OPCODE = "0100" or OPCODE = "0110" or OPCODE = "1001"  or OPCODE = "1110" else
            resultSignal(15) when OPCODE = "1011" else
            resultSignal(7) when OPCODE = "1100" or OPCODE  = "1101" else
            '1' when OPCODE = "1111" and  Ysig /= x"00" else
            '0';

Cout <= Coutsig;


Vsig <=     '1' when OPCODE = "0101" and resultSignal(7) = '0' and A(7) = '1' and B(7) = '1' else
            '1' when OPCODE = "0101" and resultSignal(7) = '1' and A(7) = '0' and B(7) = '0' else
            '1' when OPCODE = "1110" and resultSignal(15) /= A(7) else
            '0';

V <= Vsig;

F_active <= Zsig OR Coutsig OR Vsig;

X_bin_pal <=    '1' when Xsig = Xsig_reverse else
                    '0';

X_prime <=  '1' when Xsig = x"02" or Xsig = x"03" or Xsig = x"05" or Xsig = x"07" or Xsig = x"0B" or Xsig = x"0D" or Xsig = x"11" or Xsig = x"13" else
                '1' when Xsig = x"17" or Xsig = x"1D" or Xsig = x"1F" or Xsig = x"25" or Xsig = x"29" or Xsig = x"2B" or Xsig = x"2F" or Xsig = x"35" else
                '1' when Xsig = x"3B" or Xsig = x"3D" or Xsig = x"43" or Xsig = x"47" or Xsig = x"49" or Xsig = x"4F" or Xsig = x"53" or Xsig = x"59" else
                '1' when Xsig = x"61" or Xsig = x"65" or Xsig = x"67" or Xsig = x"6B" or Xsig = x"6D" or Xsig = x"71" or Xsig = x"7F" or (Xsig = x"83" and Nsig = '0') else
                '1' when (Xsig = x"89" or Xsig = x"8B" or Xsig = x"95" or Xsig = x"97" or Xsig = x"9D" or Xsig = x"A3" or Xsig = x"A7" or Xsig = x"AD") and Nsig = '0' else
                '1' when (Xsig = x"B3" or Xsig = x"B5" or Xsig = x"BF" or Xsig = x"C1" or Xsig = x"C5" or Xsig = x"C7" or Xsig = x"D3" or Xsig = x"DF") and Nsig = '0' else
                '1' when (Xsig = x"E3" or Xsig = x"E5" or Xsig = x"E9" or Xsig = x"EF" or Xsig = x"F1" or Xsig = x"FB") and Nsig = '0' else
                '0';

Nsig <= '1' when OPCODE = "0101" and Xsig(7) = '1' else
        '1' when OPCODE = "0111" and Ysig(7) = '1' else
        '1' when OPCODE = "1101" and Xsig(7) = '1' else
        '1' when OPCODE = "1110" and Xsig(7) = '1' else
        '0';

N <= Nsig;



end Behavioral;
    
pregunta krb686

2 respuestas

10

16 bits multiplicados por 4 bits pueden convertirse, a lo sumo, en un número de 20 bits, este es aparentemente el tamaño creado implícitamente por VHDL para almacenar el resultado intermedio de la multiplicación. Cuando este número implícito de 20 bits se asigna a una matriz de 16 bits, los últimos 4 bits se pierden. Y es por eso que el simulador VHDL de Brian Drummonds se quejó de un error de matriz enlazada.

Debido a que su resultado final encaja realmente en un número de 16 bits, la mejor solución es reducir el número de bits de sig1000, sig100, sig10 a una matriz de 12 bits.

    
respondido por el Roger C.
8

Lo primero que hay que hacer, como siempre, es escribir un banco de pruebas. Aquí hay una mínima (abajo). Tenga en cuenta que usé una llamada "to_string" de VHDL-2008 para simplificarla.

Ahora, analiza, elabora y simula ...

ghdl -a --std=08 alu.vhd
ghdl -a --std=08 alu_tb.vhd
ghdl -e --std=08 ALU_TB
./alu_tb
./alu_tb:error: bound check failure at alu.vhd:89
./alu_tb:error: simulation failed

Entonces, el problema es una violación de la matriz en la línea 89 ... que es, por supuesto, opF <= ...

¿Qué simulador no puede diagnosticar una simple violación de límites? Olvídalo y consigue uno mejor. O descubra cómo activar los controles vinculados. (Si se trata de Xilinx ISIM, hay una opción que nunca debería haber estado desactivada en primer lugar).

Pero ahora que sabe que es un simple error de enlace de matriz, debería ser muy fácil de encontrar y corregir. Comience ejecutando solo un dígito a la vez a través de ese gran cálculo.

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

entity ALU_TB is
end ALU_TB;

architecture TB of ALU_TB is

constant A : STD_LOGIC_VECTOR (7 downto 0) := X"46";
constant B : STD_LOGIC_VECTOR (7 downto 0) := X"40";
constant Cin : STD_LOGIC := '0';
constant OPCODE : STD_LOGIC_VECTOR (3 downto 0) := X"F";
signal Y : STD_LOGIC_VECTOR (7 downto 0);
signal X : STD_LOGIC_VECTOR (7 downto 0);

begin

DUT : entity Work.ALU
Port Map( 
       A         => A,
       B         => B,
       Cin       => Cin,
       OPCODE    => OPCODE,
       Y         => Y,
       X         => X,
       Z         => open,
       Cout      => open,
       V         => open,
       F_active  => open,
       X_bin_pal => open,
       X_prime   => open,
       N         => open);

check : process is
begin
   wait for 1 us;
   report "X = " & to_string(X) severity NOTE;
   report "Y = " & to_string(Y) severity NOTE;
end process check;

end TB;
    
respondido por el Brian Drummond

Lea otras preguntas en las etiquetas