Reputation: 489
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
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
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