Código VHDL para división binaria de 4 bits sin utilizar el signo de división. Obteniendo una advertencia de que DIV.vhd (39): (vcom-1246) El rango 3 a 0 es nulo

0
--  logic taken from https://en.wikipedia.org/wiki/Division_algorithm
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;


ENTITY Div IS
  PORT(
    OperandA    : in std_logic_vector(3 downto 0);
    OperandB    : in std_logic_vector(3 downto 0);
    Errorsig    : out STD_LOGIC := '0';
    Result_Low  : out std_logic_vector(3 downto 0);
    Result_High : out std_logic_vector(3 downto 0));
END Div;

ARCHITECTURE behavioral OF Div IS
signal Q,R : std_logic_vector (3 downto 0) := "0000";
signal i : integer := 3;
signal diff,borr : std_logic_vector (3 downto 0) := "0000";
signal er,err : std_logic := '0';

COMPONENT SUB IS
  PORT(
    OperandA    : in std_logic_vector(3 downto 0);
    OperandB    : in std_logic_vector(3 downto 0);
    Result_Low  : out std_logic_vector(3 downto 0);
    Result_High : out std_logic_vector(3 downto 0);
    Errorsig    : out std_Logic);
END component;

begin
Sub1 : SUB
     PORT MAP(
      R,OperandB,diff,borr,err); 

  process(OperandA,OperandB)
    begin  
    if OperandB = "0000" then i<=0; else                     
       for i in 3 to 0 loop     -- where n is number of bits in N
        R <= R(2 downto 0) & '0';          -- left-shift R by 1 bit
        R(0) <= OperandA(i);         -- set the least-significant bit of R equal to bit i of the numerator
         if R >= OperandB then
            -- Sub1(R,OperandB,diff,borr,err);
         R <= diff;
             Q(i) <= '1';
         end if;
        end loop; 
    end if;

  end process;

END behavioral;

- Alguien por favor ayúdame. Soy un novato y no puedo resolverlo por mi cuenta. Gracias

    
pregunta Kiran Bayari

2 respuestas

2

Además del rango nulo señalado por Brian y Eugene, la implementación de su algoritmo no funcionará porque depende de que los valores de actualización de la señal ocurran en el mismo ciclo delta. No se actualiza ninguna señal durante la ejecución de un proceso, un nuevo valor de señal asignado está disponible en ciclos de simulación subsiguientes, a diferencia de la asignación de variables que surte efecto inmediatamente.

Hay dos formas de abordar esto: introducir el retraso entre cada vez que se asigna una señal y cuándo se usa o utiliza las variables a continuación.

(En realidad, hay una tercera forma, evaluar antes de asignar, pero VHDL está diseñado específicamente para que no tenga que hacerlo. Los ciclos de simulación subsiguientes (ciclos delta) permiten la emulación del paralelismo y se distinguen por no estar precedidos por el avance de la simulación tiempo.)

Esto demuestra cómo usar las variables:

--  logic taken from https://en.wikipedia.org/wiki/division_algorithm
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity div is
    port(
        operanda:     in std_logic_vector(3 downto 0);
        operandb:     in std_logic_vector(3 downto 0);
        errorsig:     out std_logic := '0';
        result_low:   out std_logic_vector(3 downto 0);
        result_high:  out std_logic_vector(3 downto 0)
    );
end div;

architecture foo of div is

begin

UNLABELED:
    process(operanda,operandb)
        variable quotient:  unsigned (3 downto 0);
        variable remainder: unsigned (3 downto 0);
    begin  
    -- if D == 0 then error(DivisionByZeroException) end
    -- Q := 0                 -- initialize quotient and remainder to zero
    -- R := 0
    -- for i = n-1...0 do     -- where n is number of bits in N
    --   R := R << 1          -- left-shift R by 1 bit
    --   R(0) := N(i)         -- set the least-significant bit of R equal to bit i of the numerator
    --   if R >= D then
    --     R := R - D
    --     Q(i) := 1
    --   end
    -- end

    -- We
        errorsig <= '0';      -- allows successive operations
        if operandb = "0000" then
        --     i<= 0;
            assert  operandb /= "0000"
                report "Division by Zero Exception"
                severity ERROR;
            errorsig <= '1';
        else 
            quotient := (others => '0'); -- "0000"
            remainder := (others => '0');
           for i in 3 downto 0 loop  
               remainder := remainder (2 downto 0) & '0';   -- r << 1
               remainder(0) := operanda(i);       -- operanda is numerator
               if remainder >= unsigned(operandb) then  -- operandb denominator
                    remainder := remainder - unsigned(operandb);
                    quotient(i) := '1';
               end if;
            end loop;
            result_high <= std_logic_vector(quotient); -- for error keeps
            result_low  <= std_logic_vector(remainder); -- last value (invalid)
        end if;
    end process;

end architecture foo;

library ieee;
use ieee.std_logic_1164.all;

entity div_tb is
end entity;

architecture foo of div_tb is
    signal operanda:    std_logic_vector (3 downto 0) := (others => '0');
    signal operandb:    std_logic_vector (3 downto 0) := (others => '1');
    signal errorsig:    std_logic;
    signal result_low:  std_logic_vector (3 downto 0);  -- remainder
    signal result_high: std_logic_vector (3 downto 0);  -- quotient
begin
DUT:
    entity work.div
        port map (
            operanda => operanda,
            operandb => operandb,
            errorsig => errorsig,
            result_low => result_low,
            result_high => result_high
        );
STIMULUS:
    process
    begin
        operanda <= "1000";  -- 8
        operandb <= "0010";  -- 2
        wait for 20 ns;
        operandb <= "0100";  -- 4
        wait for 20 ns;    
        operandb <= "1000";  -- 8
        wait for 20 ns;
        operanda <= "1111";  -- 15
        operandb <= "0011";  -- 3
        wait for 20 ns;
        operandb <= (others => '0');
        wait for 20 ns;
        operanda <= "1101";  -- 13
        operandb <= "0111";  -- 7
        wait for 20 ns;
        wait;
    end process;
end architecture;

Y cuando se ejecuta incluso funciona:

(clickable)

Usarunasubrutinahaciendounarestaenlugardeunoperador

Podemosverlasdosfuncionesinvolucradasenelpaquetenumeric_std:

function"-" (L, R: UNSIGNED) return UNSIGNED is
  constant SIZE: NATURAL := MAX(L'LENGTH, R'LENGTH);
  variable L01 : UNSIGNED(SIZE-1 downto 0);
  variable R01 : UNSIGNED(SIZE-1 downto 0);
begin
  if ((L'LENGTH < 1) or (R'LENGTH < 1)) then return NAU;
  end if;
  L01 := TO_01(RESIZE(L, SIZE), 'X');
  if (L01(L01'LEFT)='X') then return L01;
  end if;
  R01 := TO_01(RESIZE(R, SIZE), 'X');
  if (R01(R01'LEFT)='X') then return R01;
  end if;
  return ADD_UNSIGNED(L01, not(R01), '1');
end "-";

function ADD_UNSIGNED (L, R: UNSIGNED; C: STD_LOGIC) return UNSIGNED is
  constant L_LEFT: INTEGER := L'LENGTH-1;
  alias XL: UNSIGNED(L_LEFT downto 0) is L;
  alias XR: UNSIGNED(L_LEFT downto 0) is R;
  variable RESULT: UNSIGNED(L_LEFT downto 0);
  variable CBIT: STD_LOGIC := C;
begin
  for I in 0 to L_LEFT loop
    RESULT(I) := CBIT xor XL(I) xor XR(I);
    CBIT := (CBIT and XL(I)) or (CBIT and XR(I)) or (XL(I) and XR(I));
  end loop;
  return RESULT;
end ADD_UNSIGNED;

Primero vamos a llamar a la función sub . No necesitamos redimensionar ambos operandos son del mismo tamaño. Necesitamos copias de los parámetros y podemos consolidar los bits que necesitamos:

architecture foo of div is
    function sub (L, R: unsigned) return unsigned is
        variable L01:       unsigned(L'LENGTH - 1 downto 0);
        variable R01:       unsigned(R'LENGTH - 1 downto 0);
        variable CBIT:      std_logic := '1';  -- carry in '1'
        variable RESULT:    unsigned(L01'RANGE);
    begin
        L01 :=     TO_01(L,'X');
        R01 := not TO_01(R,'X');

        for i in 0 to integer(L01'LENGTH) - 1 loop
            RESULT(i) := CBIT xor L01(i) xor R01(i);
            CBIT := (CBIT and L01(i)) or (CBIT and R01(i)) or (L01(i) and R01(i));        
        end loop;
        return RESULT;
    end function;

(Y lo hicimos como un elemento declarativo de bloque en la declaración de arquitectura).

Luego cambie a la función sub :

                -- remainder := remainder - unsigned(operandb);
                remainder := sub(remainder, unsigned(operandb));

Y todo sin usar declaraciones de espera o agregar operadores:

(clickable)

Yestodalamismarespuestaqueusareloperador"-" . (Tenga en cuenta que la raíz de OperandA se ha cambiado a decimal).

Podría notar que hay un poco más de optimización que se puede hacer con una función local sub . Podríamos deshacernos de la cláusula de uso del paquete numeric_std y convertir cualquier cosa que sea unsigned a std_logic_vector . Necesitaría una función TO_01 (o para que los bucles realicen lo mismo) para std_logic_vector .

También podría simplemente funcionar un poco más la función sub . (Sugerencia: implica eliminar la funcionalidad, implícita en and_table , or_table y xor_table en el paquete std_logic_1164 body. ¿Realmente necesitamos TO_01 ? El propósito del paquete numeric_std es representar números binarios en el tipo unsigned .) En otras palabras, podría escribir su propia función de resta.

Si activa algo con una función similar, se le pedirá que explique cómo funciona.

    
respondido por el user8352
3

Debes reemplazar esta línea:

for i in 3 to 0 ....

con esto:

for i in 3 downto 0 ....

La sintaxis for i in A to B que está utilizando en su código, iterando de i=A a i=B incrementando el valor en cada iteración. Esto significa que si A > B no funcionará, ya que no puedes ir de A a B incrementando. La sintaxis para pasar de A a B cuando A>B es usar for i in A downto B . De esta manera, el valor de i disminuirá en cada iteración comenzando desde A y alcanzando B .

    
respondido por el Eugene Sh.

Lea otras preguntas en las etiquetas