Search code examples
vhdlinteger-divisionquartusxilinx-ise

VHDL: Division with error coding but there are errors in compiling on Quartus II but not on Xilinx ISE


I'm very new to VHDL and I would like to get some help. You see, we were told by our instructor to code the division of binary (by converting the binary to integer first) and if the divisor is zero, then the output error waveform will be displayed in the simulation. Here is my code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity division_in is
    Port ( A : in  STD_LOGIC_VECTOR (7 downto 0);
           B : in  STD_LOGIC_VECTOR (7 downto 0);
           clk : in  STD_LOGIC;
           Y : out  STD_LOGIC_VECTOR (7 downto 0);
           err : out  STD_LOGIC);
end division_in;

architecture Behavioral of division_in is

begin

  process(clk)
  begin
    if clk='1' and clk'event then -- error here
      Y <= conv_std_logic_vector(conv_integer(A)/conv_integer(B),8);
      err <= '0';
    elsif B = 0 then
      err <= '1';
    end if;
  end process;

end Behavioral;

When I try to use the "check syntax" in the Xilinx ISE 9.1i (which was used by the university), there are no syntax errors that displayed on the transcript. I could even use the testbench waveform to simulate it with no problems. However, when I import this code to Quartus II, I got 5 errors in the message especially in this one:

Error (10818): Can't infer register for "err" at division_in.vhd(45) because it does not hold its value outside the clock edge

I don't know what I've done wrong in copying the exact code from the Xilinx to Quartus but a little help is much appreciated on why I got this error on Quartus II but not on Xilinx ISE 9.1i. Since Xilinx ISE is already not compatible to my laptop anymore, I just use Quartus II instead since it also has a simulation feature which is a "Vector Waveform File" simulation.


Solution

  • OK, first thing's first, do not use IEEE.STD_LOGIC_ARITH.ALL; or use IEEE.STD_LOGIC_UNSIGNED.ALL. You should use ieee.numeric_std.all, which gives you arithmetic using types signed and unsigned, along with casts and conversion functions for std_logic_vector and integer.

    Now let's look at your code:

    if clk='1' and clk'event then -- error here
      Y <= conv_std_logic_vector(conv_integer(A)/conv_integer(B),8);
      err <= '0';
    elsif B = 0 then
      err <= '1';
    end if;
    

    Looking at the err signal only, what this says is that on a rising clock edge, set err to '0', otherwise if B = 0, set err to '1'. You mentioned that this works in simulation, but for synthesis you need to think about what this means in real hardware. How do you imagine the case where there isn't a clock edge being detected? The answer is that it cannot.

    It's not clear exactly what you're trying to achieve, but two alternatives that would work, having made the package changes above, are:

    if rising_edge(clk) then -- Use rising_edge() function
      Y <= std_logic_vector(signed(A)/signed(B));
      err <= '0'; -- Synchronous clear of `err`
    end if;
    if signed(B) = 0 then -- Asynchronous set of `err`
      err <= '1';
    end if;
    

    or

    if rising_edge(clk) then
      Y <= std_logic_vector(signed(A)/signed(B));
      if signed(B) = 0 then
        err <= '1'; -- Synchronous control of `err`
      else
        err <= '0';
      end if;
    end if;
    

    The code would need less type casts if you gave the ports the types that they actually are, i.e. signed. The core of your process would then look like this:

    if rising_edge(clk) then
      Y <= A / B;
      if B = 0 then
        err <= '1'; -- Synchronous control of `err`
      else
        err <= '0';
      end if;
    end if;
    

    I hope you can see how much easier this is to read.