VHDL code for 4 bit binary division without using the division sign. Getting a warning that DIV.vhd(39): (vcom-1246) Range 3 to 0 is null

--  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

• for i in 3 to 0 -> for i in 3 downto 0 – Eugene Sh. Jun 15 '15 at 19:36
• Indeed, 3 (up)to 0 is a null range. – Brian Drummond Jun 15 '15 at 19:38
• 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. – user8352 Jun 15 '15 at 22:10

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:

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;

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:

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.

• Thanks everyone :-) special thanks to David :-) now I understand the code a lot better :-) – Kiran Bayari Jun 16 '15 at 1:23
• 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? – Kiran Bayari Jun 16 '15 at 1:32
• specifically the "-" operator, or any adding operator? Can you use a function? And is this going to be synthesized? – user8352 Jun 16 '15 at 6:08
• Without using +,-,*,/. No wait cycles can be used. Yes I think we can use a function :-) And no just to be simulated :-) – Kiran Bayari Jun 16 '15 at 6:23

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.