0
\$\begingroup\$
--  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;

--Someone please help me. Am a newbie and unable to figure it out on my own. Thanks

\$\endgroup\$
  • 2
    \$\begingroup\$ for i in 3 to 0 -> for i in 3 downto 0 \$\endgroup\$ – Eugene Sh. Jun 15 '15 at 19:36
  • 2
    \$\begingroup\$ Indeed, 3 (up)to 0 is a null range. \$\endgroup\$ – Brian Drummond Jun 15 '15 at 19:38
  • \$\begingroup\$ vcom Message # 1246: The specified range is a null range and therefore contains no values. This occurs when the direction is TO and LEFT > RIGHT, or when the direction is DOWNTO and LEFT < RIGHT. \$\endgroup\$ – user8352 Jun 15 '15 at 22:10
2
\$\begingroup\$

Besides the null range so ably pointed out by Brian and Eugene, your algorithm implementation won't work because it's depending on signal update values to occur in the same delta cycle. No signal is updated during the execution of a process, a new signal value assigned is available in subsequent simulation cycles, unlike variable assignment which takes effect immediately.

There are two ways to address this, introduce delay between each time a signal is assigned and when it is next used or use variables.

(There's actually a third way, evaluate before assign, but VHDL is specifically designed so you don't have to. Subsequent simulation cycles (Delta cycles) allow emulation of parallelism and are distinguished by not being preceded by the advancement of simulation time.)

This demonstrates how to use 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;

And when run even works:

div_tb.png (clickable)

Using a subroutine doing subtraction instead of an operator

We can look at the two involved functions in package numeric_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;

First we're going to call the function sub. We don't need resizing both operands are the same size. We do need copies of the parameters, and we can consolidate the bits we need:

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;

(And we did this as a block declarative item in the architecture declaration).

Then switch to the sub function:

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

And all without using wait statements or adding operators:

div_tb_sub.png (clickable)

And this gives the same answer as using the "-" operator. (Note the radix of OperandA has been changed to decimal).

You could note there's a bit more optimization that can be done with a local function sub. We could get rid of the numeric_std package use clause and convert anything that's unsigned to std_logic_vector. You'd need a TO_01 function (or for loops to perform the same thing) for std_logic_vector.

You could simply the sub function a bit more too. (Hint: it implies removing functionality, implied by the and_table, or_table and xor_table in the package std_logic_1164 body. Do we really need TO_01? The purpose in package numeric_std is to represent binary numbers in type unsigned.) In other words you could write your own subtract function.

If you turn in something with a similar function you're going to be required to explain how it works.

\$\endgroup\$
  • \$\begingroup\$ Thanks everyone :-) special thanks to David :-) now I understand the code a lot better :-) \$\endgroup\$ – Kiran Bayari Jun 16 '15 at 1:23
  • \$\begingroup\$ And one more thing, I am not supposed to use subtract sign (- sign). Anyway I can subtract D from R logically without using the sign? \$\endgroup\$ – Kiran Bayari Jun 16 '15 at 1:32
  • \$\begingroup\$ specifically the "-" operator, or any adding operator? Can you use a function? And is this going to be synthesized? \$\endgroup\$ – user8352 Jun 16 '15 at 6:08
  • \$\begingroup\$ Without using +,-,*,/. No wait cycles can be used. Yes I think we can use a function :-) And no just to be simulated :-) \$\endgroup\$ – Kiran Bayari Jun 16 '15 at 6:23
3
\$\begingroup\$

You should replace this line:

for i in 3 to 0 ....

with this:

for i in 3 downto 0 ....

The syntax for i in A to B you are using in your code, iterating from i=A to i=B incrementing the value at each iteration. It means, that if A > B it will not work, since you can't go from A to B by incrementing. The syntax for going from A to B when A>B is to use for i in A downto B. This way the value of i will decrement at each iteration starting from A and reaching B.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.