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.
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.
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.
Related
I have this code in VHDL:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.NUMERIC_STD.all;
entity Div is
Port ( Ain : in STD_LOGIC_VECTOR (6 downto 0);
Bin : in STD_LOGIC_VECTOR (6 downto 0);
Q : out STD_LOGIC_VECTOR (6 downto 0);
R : out STD_LOGIC_VECTOR (6 downto 0)
Rez : out std_logic_vector(13 downto 0));
end Div;
architecture Behavioral of Div is
begin
Proc1 : process (Ain, Bin) is
variable cnt : std_logic_vector(6 downto 0);
variable Atemp : std_logic_vector(6 downto 0);
begin
if (Ain < Bin) then
cnt := "0000000";
Atemp := Ain;
elsif (Ain = Bin) then
cnt := "0000001";
Atemp := (others => '0');
elsif (Ain > Bin) then
cnt := "0000001";
Atemp := (Ain - Bin);
while (Atemp >= Bin) loop
Atemp := (Atemp - Bin);
cnt := cnt + "0000001";
end loop;
end if;
Q <= cnt;
R <= Atemp;
Rez <= "0000000" & cnt;
end process Proc1;
end Behavioral;
and when I synt in Xilinx, I have this error message
Non-static loop limit exceeded
at that while loop.
When VHDL is synthesised, the synth tool needs to unwrap your loop to create a circuit. Because it has no idea what the Atemp or Bin are, other than they are 7 bit integers, it has to assume that Atemp and Bin could be static forever, and hence the loop never unrolls.
The problem with your code is that you used a while loop. Your HDL needs to describe a circuit, and a while loop generally doesn't. Instead of using a while loop, consider using a clock in your process and incrementing the counter by 1 on each clock. Circuits have no knowledge of time without a clock.
I want to make 4kb byte addressable memory. sorry I'm new in VHDL
I wanted my code works first write 4byte number in adress 8 (rdwr=1, addr=1000, size=10(2^2byte), idata=10001100)
then wait 8 cycles to implement writing time(ivalid=0)
Second read 4byte number from adress 8(rdwr=0, addr=1000, size=10(2^2byte))
In my purpose, the "ready" signal should be '0' while waiting for writing time
but the signal is always 'U' in simulation. I tried to figure out what is the problem but i couldn't
Can anyone help me where did a make mistake?
Here is my code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Memory is
port (
clk: in std_logic;
ready: out std_logic; -- 0: busy, 1: ready
ivalid: in std_logic; -- 0: invalid, 1: valid
rdwr: in std_logic; -- 0: read, 1: write
addr: in unsigned(11 downto 0); -- byte address
size: in std_logic_vector(1 downto 0); -- 00/01/10/11: 1/2/4/8 bytes
idata: in std_logic_vector(63 downto 0);
ovalid: out std_logic; -- 0: invalid, 1: valid
odata: out std_logic_vector(63 downto 0)
);
end entity;
architecture Behavioral of Memory is
type ram_type is array (0 to (2**12)-1) of std_logic_vector(7 downto 0);
signal RAM : ram_type;
signal state : std_logic := '1'; --if ready '1'
signal queue : std_logic := '0'; --if something to do '1'
signal timer : integer := 0; --timer
signal curr_addr : unsigned(11 downto 0);
signal curr_size : std_logic_vector(1 downto 0);
signal curr_data : std_logic_vector(63 downto 0);
signal write : std_logic := '0';
signal read : std_logic := '0';
begin
process(clk)
variable vstate : std_logic := state;
variable vqueue : std_logic := queue; --if something to do '1'
variable vtimer : integer := timer; --timer
variable vcurr_addr : unsigned(11 downto 0) := curr_addr;
variable vcurr_size : std_logic_vector(1 downto 0) := curr_size;
variable vcurr_data : std_logic_vector(63 downto 0) := curr_data;
variable vwrite : std_logic := write;
variable vread : std_logic := read;
begin
--get input
if(rising_edge(clk)) then
ovalid <= '0';
if(vstate='1') then
if(ivalid='1') then
vcurr_addr := addr;
vcurr_size := size;
if(rdwr='0') then
--read
vread := '1';
else
vwrite := '1';
vcurr_data := idata;
end if;
vqueue := '1';
vtimer := 2**(to_integer(unsigned(vcurr_size)))-1;
end if;
end if;
--process
if(vqueue = '1') then
if(vtimer > 0) then
--wait for next cycle
ready <= '0';
vstate := '0';
vtimer := vtimer - 1;
else
--ok to go
if(vwrite = '1') then
--write
for x in 0 to 2**(to_integer(unsigned(vcurr_size)))-1 loop
for y in 0 to 7 loop
RAM(to_integer(vcurr_addr) + x)(y) <= vcurr_data(y + 8*x);
end loop;
end loop;
elsif(vread = '1') then
--read
for x in 0 to 7 loop
for y in 0 to 7 loop
if(x < 2**(to_integer(unsigned(vcurr_size)))) then
odata(y + 8*x) <= RAM(to_integer(vcurr_addr) + x)(y);
else
odata(y + 8*x) <= '0';
end if;
end loop;
end loop;
ovalid <= '1';
end if;
vqueue := '0';
vstate := '1';
ready <= '1';
end if;
end if;
--save variable to signals
state <= vstate;
queue <= vqueue;
timer <= vtimer;
curr_addr <=vcurr_addr;
curr_size <=vcurr_size;
curr_data<= vcurr_data;
write <= vwrite;
read <= vread;
end if;
end process;
end architecture;
I have a priority encoding function that returns a vector containing a 1 at the position where the first 1 is found in the input vector. The function works as expected, unless I try to negate the input vector. Here's an example that demonstrates the unexpected behavior:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity tb IS
end tb;
architecture run of tb is
constant N : natural := 5;
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'high downto vec_in'low);
begin
ret := (others => '0');
for i in vec_in'low to vec_in'high loop
if vec_in(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
signal a : std_logic_vector(N-1 downto 0);
signal abar : std_logic_vector(N-1 downto 0);
signal first_a : std_logic_vector(N-1 downto 0);
signal first_nota : std_logic_vector(N-1 downto 0);
signal first_abar : std_logic_vector(N-1 downto 0);
begin
process
begin
a <= "10100";
wait for 10 ns;
a <= "01011";
wait for 10 ns;
wait;
end process;
abar <= not(a);
first_a <= get_first_one_in_vec(a);
first_nota <= get_first_one_in_vec(not(a));
first_abar <= get_first_one_in_vec(abar);
end run;
To my understanding, first_nota should be the same as first_abar. However, my simulator (ModelSim - Intel FPGA Starter Edition 10.5b, rev. 2016.10) thinks otherwise, as you can see here:
What am I missing here?
This works OK:
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'length downto 1);
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
begin
ret := (others => '0');
for i in inp'right to inp'left loop
if inp(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
https://www.edaplayground.com/x/3zP_
Why does yours not work? Well, when you call your function with the not operator* as part of the expression:
first_nota <= get_first_one_in_vec(not a);
the numbering of the input to the function is changed to 1 to by the not operator. Why? Here is the code for the not operator and you can see why:
-------------------------------------------------------------------
-- not
-------------------------------------------------------------------
FUNCTION "not" ( l : std_logic_vector ) RETURN std_logic_vector IS
-- pragma built_in SYN_NOT
-- pragma subpgm_id 204
--synopsys synthesis_off
ALIAS lv : std_logic_vector ( 1 TO l'LENGTH ) IS l;
VARIABLE result : std_logic_vector ( 1 TO l'LENGTH ) := (OTHERS => 'X');
--synopsys synthesis_on
BEGIN
--synopsys synthesis_off
FOR i IN result'RANGE LOOP
result(i) := not_table( lv(i) );
END LOOP;
RETURN result;
--synopsys synthesis_on
END;
---------------------------------------------------------------------
Anyway, this breaks your code (which starts scanning from the other end of the word).
One way of making function agnostic to the ordering of the numbering of its input is to normalise the inputs like this:
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
Once you have done this, you're in control. So, instead of loops from 'high downto 'low, we can be more explicit and loop from 'right to 'left:
for i in inp'right to inp'left loop
not is an operator not a function. You don't need the brackets.
Output is always zeros (quotient and remainder) in the code shown below.
Even if I assign value of b to remainder,it is giving 0. I have checked for many times but I am not able to understand what the issue is. While compiling, it is showing 2 warnings:
- Initial value of "b" depends on value of signal "divisor".
What is the problem?
-- DIVIDER
library ieee;
use ieee.numeric_bit.all;
entity unsigned_divider is
port(
-- the two inputs
dividend: in bit_vector(15 downto 0);
divisor : in bit_vector(15 downto 0);
-- the two outputs
quotient : out bit_vector(15 downto 0);
remainder : out bit_vector(15 downto 0)
);
end entity unsigned_divider;
architecture behave of unsigned_divider is
begin
process
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
variable p : bit_vector(15 downto 0):= (others => '0');
variable i : integer:=0;
begin
for i in 0 to 15 loop
p(15 downto 1) := p(14 downto 0);
p(0) := a(15);
a(15 downto 1) := a(14 downto 0);
p := bit_vector(unsigned(p) - unsigned(b));
if(p(15) ='1') then
a(0) :='0';
p := bit_vector(unsigned(p) + unsigned(b));
else
a(0) :='1';
end if;
wait for 1 ns;
end loop;
quotient <= a after 1 ns;
remainder <= p after 1 ns;
end process;
end behave;
You should have explicit assignments to the variables a and b inside the process statement part (as sequential signal assignments). The declarations:
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
Should be:
variable a : bit_vector(15 downto 0);
variable b : bit_vector(15 downto 0);
And in the process statement part (following the begin in the process):
a := dividend;
b := divisor;
These overcome the issue natipar mentions, that the values are only assigned to a and b during initialization.
Further should you desire to have a 1 ns delay you should have an explicit wait statement as the last sequential statement of the process statement process statement part:
wait on dividend, divisor;
These make your process statement look something like this (with indentation added):
process
variable a : bit_vector(15 downto 0); -- := dividend;
variable b : bit_vector(15 downto 0); -- := divisor;
variable p : bit_vector(15 downto 0) := (others => '0');
variable i : integer := 0;
begin
a := dividend;
b := divisor;
for i in 0 to 15 loop
p(15 downto 1) := p(14 downto 0);
p(0) := a(15);
a(15 downto 1) := a(14 downto 0);
p := bit_vector(unsigned(p) - unsigned(b));
if p(15) = '1' then
a(0) :='0';
p := bit_vector(unsigned(p) + unsigned(b));
else
a(0) := '1';
end if;
wait for 1 ns;
end loop;
quotient <= a after 1 ns;
remainder <= p after 1 ns;
wait on dividend, divisor;
end process;
(Note the space between the numeric literal and the units, required by IEEE Std 1076-2008, 15.3 Lexical elements, separators and delimiters paragraph 4, the last sentence "At least one separator is required between an identifier or an abstract literal and an adjacent identifier or abstract literal.", despite Modelsim not requiring it).
Writing a simple testbench we find at least one error in your restoring division algorithm:
entity unsigned_divider_tb is
end entity;
architecture foo of unsigned_divider_tb is
signal dividend, divisor: bit_vector (15 downto 0) := (others => '0');
signal quotient, remainder: bit_vector (15 downto 0);
function to_string(inp: bit_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: bit_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(BIT'IMAGE(input_str(i)));
end loop;
return image_str;
end;
begin
DUT:
entity work.unsigned_divider
port map (
dividend,
divisor,
quotient,
remainder
);
MONITOR:
process (quotient, remainder)
begin
report "quotient = " & to_string (quotient) severity NOTE;
report "remainder = " & to_string (remainder) severity NOTE;
end process;
end architecture;
ghdl -a unsigned_divider.vhdl
ghdl -e unsigned_divider_tb
ghdl -r unsigned_divider_tb
unsigned_divider.vhdl:83:9:#0ms:(report note): quotient = 0000000000000000
unsigned_divider.vhdl:84:9:#0ms:(report note): remainder = 0000000000000000
unsigned_divider.vhdl:83:9:#17ns:(report note): quotient = 1111111111111111
unsigned_divider.vhdl:84:9:#17ns:(report note): remainder = 0000000000000000
(And a note on interpretation, the transactions reported at time 0 ms are the default assignments performed as a result of elaboration).
Your algorithm gives a wrong answer for division by 0.
Adding a stimulus process to the testbench:
STIMULUS:
process
begin
wait for 20 ns;
dividend <= x"ffff";
divisor <= x"000f";
end process;
Shows it can get the right answer too:
unsigned_divider.vhdl:83:9:#37ns:(report note): quotient = 0001000100010001
unsigned_divider.vhdl:84:9:#37ns:(report note): remainder = 0000000000000000
And with the testbench and added wait statements and assignments in the stimulus process you can explore further.
I've always been a fan of non-restoring division myself, because the adds or subtracts take a clock in a clocked divider.
Variable assignments take effect immediately; but the signal, at the moment of the creation of that variable, has no value, so you cannot expect the assignments
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
to work correctly. I'm a bit surprised that there are no complaints for the assignment to the variable a though. Perhaps it is your second warning. You should define the variables the way you do, but leave the assignment for later, in the begin segment of your process.
P.S. Also, you might want to change remainder <= p after 1ns; to remainder <= p after 1 ns;.
I am new to vhdl programming. I recently got a task to change value of std_logic_vector in a shift register sensitive to clock signal by pressing a button.
When I'm holding KEY(2) the value of shift register changes but it's not shifting unless I release the button. Is it possible to modify my code below so it would be sensitive to rising edge of KEY(2)? Or is there any other possibility to change a value of the vector by pressing the KEY(2) button and it would be shifting even if I'm holding the button?
Thank you for your answer. I would be really grateful and it would really help me a lot.
Sorry for my bad English. Have a nice time.
ENTITY hadvhdl IS PORT (
CLOCK_50 : IN STD_LOGIC;
KEY : IN STD_LOGIC_VECTOR (3 downto 0);
LEDR : OUT STD_LOGIC_VECTOR (15 downto 0)
);
END hadvhdl;
ARCHITECTURE rtl OF hadvhdl IS
shared variable register : std_logic_vector(15 downto 0) := (1 downto 0=>'1', others=>'0');
shared variable count : integer range 1 to 4 :=1;
BEGIN
changecount: process (KEY)
begin
if rising_edge(KEY(2)) then
if count<4 then
count := count + 1;
else
count := 1;
end if;
end if;
end process;
shift: process (CLOCK_50, KEY)
variable up : BOOLEAN := FALSE;
variable reg : std_logic_vector(15 downto 0) := (1 downto 0=>'1', others=>'0');
begin
if rising_edge(CLOCK_50) then
if (KEY(2)='1') then
case count is
when 1 => register := (1 downto 0=>'1', others=>'0');
when 2 => register := (2 downto 0=>'1', others=>'0');
when 3 => register := (3 downto 0=>'1', others=>'0');
when 4 => register := (4 downto 0=>'1', others=>'0');
end case;
end if;
reg := register;
LEDR <= reg;
if up then
reg := reg(0) & reg(15 downto 1);
else
reg := reg(14 downto 0) & reg(15);
end if;
register := reg;
end if;
end process;
END rtl;
Don't use variables! (at least as VHDL-beginner)
Don't use push buttons as clocks (e.g. in rising_edge)
Use only one clock in your design (seem o.k. in your case)
Keep in mind that a mechanical push button do bounces.
And here is a variant for an edge detection:
-- in entity
clk ; in std_logic;
sig_in : in std_logic;
...
signal sig_old : std_logic;
signal sig_rise : std_logic;
signal sig_fall : std_logic;
...
process
begin
wait until rising_edge( clk);
-- defaults
sig_rise <= '0';
sig_fall <= '0';
-- shift value in
sig_old <= sig_in;
-- do some real action
if sig_old = '0' and sig_in = '1' then
sig_rise <= '1';
end if;
if sig_old = '1' and sig_in = '0' then
sig_fall <= '1';
end if;
end process;