Mojo Jojo
Mojo Jojo

Reputation: 489

fatal error in modelsim during simulation

This is my main code in VHDL:

library ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;

  entity pid is
    port( error ,Kp, Ti, Td ,dt: in std_logic_vector(7 downto 0);
      reset : in std_logic;
      output :out std_logic_vector(31 downto 0) );
    end pid;

    architecture pid_arch of pid is
    -------------------------------- functions
    function add_vec(num1,num2,num3: in std_logic_vector(15 downto 0)) return std_logic_vector is
    variable v_TEST_VARIABLE1: integer;
    variable v_TEST_VARIABLE2: integer;
    variable v_TEST_VARIABLE3: integer;
    variable n_times1: integer;
    variable n_times2: integer;
variable sum: integer;    
    begin
        v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ; 
       v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
       v_TEST_VARIABLE3 := to_integer(unsigned(num3 )); 

       --for n_times1 in 1 to v_TEST_VARIABLE2 loop
      --   v_TEST_VARIABLE1: = v_TEST_VARIABLE1 + '1';
     --  end loop;
     --  for n_times2 in 1 to v_TEST_VARIABLE3 loop
     --    v_TEST_VARIABLE1:= v_TEST_VARIABLE1 + '1';
      -- end loop;
      sum:= v_TEST_VARIABLE1+ v_TEST_VARIABLE2 + v_TEST_VARIABLE3;
       return std_logic_vector(to_unsigned(sum,32));
     end add_vec;
    -----------------------------------
    function sub(num1, num2: in std_logic_vector(7 downto 0)) return std_logic_vector is
    variable v_TEST_VARIABLE1: integer;
    variable v_TEST_VARIABLE2: integer;
    variable difference: integer;
    begin
       v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ; 
       v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
       difference := v_TEST_VARIABLE1 - v_TEST_VARIABLE2;
       return std_logic_vector(to_unsigned(difference,8));
     end sub;
    ------------------------------------
    function mul(num1,num2 : in std_logic_vector(7 DOWNTO 0)) return std_logic_vector is
    variable v_TEST_VARIABLE1 : integer;
    variable v_TEST_VARIABLE2 : integer;
    variable n_times: integer:=1;
    variable product: integer:=0;
    begin 
       v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ; 
       v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
      for n_times in 1 to v_TEST_VARIABLE2 loop
        product:=product + v_TEST_VARIABLE1;
      end loop;
    return std_logic_vector(to_unsigned(product,16));
  end mul;
  --------------------------------
    function div(num1, num2 : in std_logic_vector(7 DOWNTO 0)) return std_logic_vector is
             variable v_TEST_VARIABLE1 : integer;
             variable v_TEST_VARIABLE2 : integer;
             variable quotient :integer;
        --           begin 
      --P3: PROCESS(num1, num2)
       variable n_times: integer:=1;
     begin     
        if num1>num2 then
       v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ; 
       v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
       L1:loop
         n_times := n_times + 1;
        exit when ((v_TEST_VARIABLE2 -  v_TEST_VARIABLE1)>0);
        v_TEST_VARIABLE1 := v_TEST_VARIABLE1 - v_TEST_VARIABLE2;
       end loop L1;

    quotient := n_times-1;
   elsif num2>num1 then
      v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;  
       v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
       L2:loop
        n_times:=n_times+1;
       exit when ((v_TEST_VARIABLE1 -  v_TEST_VARIABLE2)>0);
       v_TEST_VARIABLE2 := v_TEST_VARIABLE2 - v_TEST_VARIABLE1;

   quotient := n_times-1;

end loop L2;
    else
      quotient := 1;
    end if;
    return std_logic_vector(to_unsigned(quotient,16));
 -- end PROCESS P3;
      end div;

  ---------------------------------
  function derivative(error, previous_error, dt :in std_logic_vector(7 downto 0)) return std_logic_vector is
  variable derivative_val: std_logic_vector(15 downto 0);
  begin
      derivative_val := div(sub(error,previous_error),dt);
      return derivative_val;
  end derivative;
  --------------------------------------------

function integration(error,dt:in std_logic_vector(7 downto 0);current_integration :in std_logic_vector(15 downto 0);reset : in std_logic) return std_logic_vector is
       begin  
         if (reset='1') then
           return "0000000000000000";
      else  
         --current_integration := add_vec(current_integration, mul(error,dt),x"0000");
        -- return current_integration;
        return add_vec(current_integration, mul(error,dt),x"0000");
       end if;
end integration;
    -------------------------
     begin 
        P1:PROCESS (reset ,error , Kp, Ti, Td)
        variable proportional_term : std_logic_vector(15 downto 0):=x"0000";
        variable derivative1: std_logic_vector(15 downto 0) := x"0000";
       variable derivative_term: std_logic_vector(31 downto 0) ; 
       variable integration1: std_logic_vector(15 downto 0) :=x"0000";
       variable integration_term : std_logic_vector(15 downto 0) := x"0000";
       variable current_integration: std_logic_vector(15 downto 0) ;
       variable previous_error: std_logic_vector(7 downto 0) := "00000000";
       variable v1: std_logic_vector( 15 downto 0);
       variable v2 : std_logic_vector( 23 downto 0);
       variable v3 : std_logic_vector (7 downto 0);
       ------------------checked till here

        begin 
        if (reset='1') then
          --  output <= x"00000000";
            previous_error :="00000000";
            current_integration := x"0000";
      else  

         --output <= Kp*(error + integration/Ti + derivative*Td);
         current_integration := integration1;
         end if;
        -- proportional_term := mul(Kp,error);
           proportional_term := std_logic_vector(unsigned(Kp) * unsigned(error));
        -- derivative_term := mul(mul(Kp,Td), derivative(error, previous_error,dt));
        v1 :=std_logic_vector(unsigned(Kp)*unsigned(Td));
        derivative1 := derivative(error, previous_error,dt);
        derivative_term := std_logic_vector(unsigned(v1)*unsigned(derivative1));
        integration1 :=integration(error,dt,current_integration,reset);
        v2 :=std_logic_vector((unsigned(Kp)*unsigned(integration1)));
        v3 := std_logic_vector(resize(unsigned(v2),8));
         integration_term := div( v3, Ti);
               --   integration_term := div(mul(Kp, integration(error,dt,current_integration,reset)) , Ti);
         previous_error :=error;
      output <= add_vec(std_logic_vector(resize(unsigned(proportional_term),16)) , std_logic_vector(resize(unsigned(derivative_term),16)), std_logic_vector(resize(unsigned(integration_term),16)));
        --output <= x"0000";
        --Kp*(error + integration/Ti + derivative*Td);
      END PROCESS P1;
      end pid_arch;

And this is the testbench:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.numeric_std.all;

   ENTITY pid_2_tb IS 
END pid_2_tb;

ARCHITECTURE behavior OF pid_2_tb IS

    COMPONENT pid  --'test' is the name of the module needed to be tested.

    port(error ,Kp, Ti, Td ,dt: in std_logic_vector(7 downto 0);
      reset : in std_logic;
      output :out std_logic_vector(31 downto 0) );

    END COMPONENT;
   signal error : std_logic_vector(7 downto 0) := "00000000";
   signal Kp : std_logic_vector(7 downto 0) := "00001000";
   signal Ti : std_logic_vector(7 downto 0) := "00000001";
   signal Td : std_logic_vector(7 downto 0) := "00000001";
   signal dt : std_logic_vector(7 downto 0) := "00000001";
  signal reset : std_logic := '1';

   signal output : std_logic_vector(31 downto 0);

   constant clk_period : time := 1 ns;
BEGIN
   uut: pid PORT MAP (
         error => error,
          Kp => Kp,
          Ti => Ti,
          Td => Td,
          dt => dt,
          reset => reset,
          output => output
        );       

   clk_process :process
   begin
        error <= "00000001";
        reset <= '1';
        wait for clk_period/2;  
        error <= "00000010";
        reset <= '0';
        wait for clk_period/2;  --for next 0.5 ns signal is '1'.
   end process;
   -- Stimulus process
  stim_proc: process
   begin         

        wait for 17 ns;
        error <= "00000011";
        reset <= '0';
        wait for 1 ns;
        error <= "00000010";
        reset <= '0';
        wait;
  end process;

END;

The two show no error on compilation. I have tried simulating for smaller programs using the same functions, and that worked well. But on simulation it gives Fatal error. What can be the reasons for the same? I am a newbie in vhdl. Please help me out. Thanks in advance.

Upvotes: 0

Views: 3940

Answers (2)

user1155120
user1155120

Reputation:

Your process P1 in entity pid loops continuously. I would imagine Modelsim uses a guard timer to cause an exception when something spins continuously.

I found this by divide and conquer:

ghdl -a pid.vhdl # analyze, also contains pid_2_tb entity/architecture ghdl -e pid_2_tb # elaborates ghdl -r pid_2_tb --stop-time=100ns # run the simulation (batch mode) guard time to stop)

Ran forever so: ghdl -e pid # elaborate just the component ghdl -r pid --stop-time=30ns # run just the component ../../../src/ieee/numeric_std-body.v93:2098:7:@0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0 ../../../src/ieee/numeric_std-body.v93:2098:7:@0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0

(And it was at least doing something - while still running forever).

So knew which part of your design (entity/architecture pid) to focus on. Looked immediately at the process and found no wait nor a sensitivity statement.

Commented out the sensitivity list in P1 and put a wait statement before the first function call (derivative). That finished.

Moved the wait statement before the next function call in P1 (to div). Never finished.

So your derivative function doesn't complete. And horror of horrors the derivative function contains calls to to div and sub.

Looking in the first function call (to div) in function derivative and we find not one but two loop unbounded loop statements:

function div(num1, num2 : in std_logic_vector(7 downto 0)) 
        return std_logic_vector is

    variable v_test_variable1: integer;
    variable v_test_variable2: integer;
    variable quotient:  integer;
    variable n_times:   integer:= 1;

begin     
    if num1 > num2 then
        v_test_variable1 := to_integer(unsigned(num1)) ; 
        v_test_variable2 := to_integer(unsigned(num2)) ;
    l1:
        loop
            n_times := n_times + 1;
            exit when ((v_test_variable2 -  v_test_variable1) > 0);
            v_test_variable1 := v_test_variable1 - v_test_variable2;
        end loop l1;

        quotient := n_times - 1;
    elsif num2 > num1 then
        v_test_variable1 := to_integer(unsigned(num1));  
        v_test_variable2 := to_integer(unsigned(num2));
    l2:
        loop
            n_times := n_times + 1;
            exit when ((v_test_variable1 -  v_test_variable2) > 0);
            v_test_variable2 := v_test_variable2 - v_test_variable1;
            quotient := n_times - 1;
        end loop l2;
    else
        quotient := 1;
    end if;
    return std_logic_vector(to_unsigned(quotient,16));
  end div;

I'm not inclined to independently test your algorithm (say in C or use report statements) but I'd guess the difference between v_test_variable1 and v_test_variable2 doesn't go positive in one of the two loops, or one of them should compare Less Than instead of Greater Than. Another possibility is that you zero something out.

Your code doesn't look synthesis eligible, either. You don't have loops that are unbounded. Loops are unrolled in synthesis and required to have a static number of iterations.

And of course you could have an additional problem somewhere else.

Upvotes: 1

Morten Zilmer
Morten Zilmer

Reputation: 15924

The div function uses a loop where the exit condition never becomes true, whereby the div function will never return, thus the simulation time will never advance.

One relevant part of the div code is in:

elsif num2 > num1 then
  v_TEST_VARIABLE1 := to_integer(unsigned(num1));
  v_TEST_VARIABLE2 := to_integer(unsigned(num2));
  L2 : loop
    n_times          := n_times+1;
    exit when ((v_TEST_VARIABLE1 - v_TEST_VARIABLE2) > 0);
    v_TEST_VARIABLE2 := v_TEST_VARIABLE2 - v_TEST_VARIABLE1;
    quotient := n_times-1;
  end loop L2;

But if num1 is 0 (zero) then v_TEST_VARIABLE2 is never decremented in the loop, thus ((v_TEST_VARIABLE1 - v_TEST_VARIABLE2) > 0) never becomes true.

The div function must be updated to handle this case also, or arguments must be guaranteed never to result in the case.

Upvotes: 0

Related Questions