library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity RaccinCarreSequentielle is
generic(
N: natural:= 16
);
port(
X: unsigned(2*N-1 downto 0);
reset : in std_logic; --clear signal
clk : in std_logic;
state_done : in std_logic; --start
result_done : out std_logic;
result : out unsigned(2*N-1 downto 0)
);
end entity;
architecture state_machine_raccincarre_arc of RaccinCarreSequentielle is
type state is (s0_wait,s1_init,s2_calcul,s3_fini);
signal pre_state,next_state: state;
begin
state_register:process(reset,clk)
begin
if reset = '1' then
pre_state <= s0_wait;
elsif rising_edge(clk) then
pre_state <= next_state;
end if;
end process state_register;
state_machine: process(pre_state,state_done)
variable rx,rz,rv : unsigned(2*N-1 downto 0);
variable ri: unsigned(N-1 downto 0);
begin
case pre_state is
when s0_wait =>
if state_done = '1' then
next_state <= s1_init;
else
next_state <= s0_wait;
end if;
when s1_init =>
next_state <= s2_calcul;
rx := x;
rz := (others => '0');
rv := (2*N-2 => '1', others => '0');
ri := to_unsigned(N-1,N);
when s2_calcul =>
if ri > 0 then
ri := ri - 1;
rz := rz + rv;
if rx > rz then
rx := rx - rz;
rz := rz + rv;
else
rz := rz - rv;
end if;
rz := '0' & rz(2*N-1 downto 1);
rv := "00" & rv(2*N-1 downto 2);
next_state <= s2_calcul;
else
next_state <= s3_fini;
end if;
when s3_fini =>
result <= rz;
if state_done = '0' then
next_state <= s0_wait;
else
next_state <= s3_fini;
end if;
when others =>
null;
end case;
end process state_machine;
result_proc: process(pre_state)
begin
if pre_state = s3_fini then
result_done <= '1';
else
result_done <= '0';
end if;
end process result_proc;
end architecture;
When i use the for loop inside state2, my code will run correctly and my result is good. For example when i want to find the square root of 255, i will have 15. But when I dont want to use For loop in state2_calcul as you see. So i did a if statement to reduce the variable RI each time i go to state2 like below. I did a simulation but the state always stops at state2, it can not go through like my link.
when s2_calcul =>
if ri > 0 then
ri := ri - 1;
rz := rz + rv;
if rx > rz then
rx := rx - rz;
rz := rz + rv;
else
rz := rz - rv;
end if;
rz := '0' & rz(2*N-1 downto 1);
rv := "00" & rv(2*N-1 downto 2);
next_state <= s2_calcul;
else
next_state <= s3_fini;
end if;
I think that problem is the nested IF, but when i change that, nothing change. Could someone helps me explain that problem and how can i solve it. thanks
You cannot memorize anything in a combinatorial part of your design. So you need registers for ri
, rx
, rv
and rz
. These registers are somehow part of your global state which is indeed a combination of them, and of the pre_state
register.
Let's continue with the style you already use: one synchronous process for the registers, another for the combinatorial part, and a next_xxx
signal for the input of each xxx
register.
architecture state_machine_raccincarre_arc of RaccinCarreSequentielle is
type state is (s0_wait, s1_init, s2_calcul, s3_fini);
signal pre_state, next_state: state;
signal rx, rz, rv, next_rx, next_rz, next_rv: unsigned(2*N-1 downto 0);
signal ri, next_ri: unsigned(N-1 downto 0);
begin
state_register:process(reset,clk)
begin
if reset = '1' then
pre_state <= s0_wait;
rx <= (others => '0');
rz <= (others => '0');
ri <= (others => '0');
rv <= (others => '0');
elsif rising_edge(clk) then
pre_state <= next_state;
rx <= next_rx;
rz <= next_rz;
ri <= next_ri;
rv <= next_rv;
end if;
end process state_register;
state_machine: process(pre_state, state_done, x, rx, rz, rv, ri)
variable tmpz : unsigned(2*N-1 downto 0);
begin
next_state <= pre_state;
next_rx <= rx;
next_rz <= rz;
next_rv <= rv;
next_ri <= ri;
tmpz := (others => '0');
case pre_state is
when s0_wait =>
if state_done = '1' then
next_state <= s1_init;
end if;
when s1_init =>
next_state <= s2_calcul;
next_rx <= x;
next_rz <= (others => '0');
next_rv <= (others => '0');
next_rv(2*N-2) <= '1';
next_ri <= to_unsigned(N-1,N);
when s2_calcul =>
if ri > 0 then
next_ri <= ri - 1;
tmpz := rz + rv;
if rx > tmpz then
next_rx <= rx - tmpz;
tmpz := tmpz + rv;
else
tmpz := tmpz - rv;
end if;
next_rz <= '0' & tmpz(2*N-1 downto 1);
next_rv <= "00" & rv(2*N-1 downto 2);
else
next_state <= s3_fini;
end if;
when s3_fini =>
if state_done = '0' then
next_state <= s0_wait;
end if;
end case;
end process state_machine;
result <= rz;
result_done <= '1' when pre_state = s3_fini else '0';
end architecture;
See? The sensitivity list of the combinatorial process contains all signals that the process reads, the signals it assigns are always assigned (thanks to the default assignments at the very beginning), and the only variable is always assigned before it is used (thanks also to the default assignment at the very beginning).
Note that, thanks to the default assignments at the very beginning, there is no risk to get latches at synthesis. By default these:
next_xxx <= xxx;
assignments say that by default the xxx
register shall not change. An interesting side effect is that you do not need any more some of your else
statements. You can replace:
when s0_wait =>
if state_done = '1' then
next_state <= s1_init;
else
next_state <= s0_wait;
end if;
by:
when s0_wait =>
if state_done = '1' then
next_state <= s1_init;
end if;
because the else
clause is already what happens by default.
Of course, it could be that it does not work exactly as you would like because the structure is totally different. But at least this should be a good starting point for your debugging. Just remember the main principles of combinatorial processes for synthesis:
all
keyword of the VHDL 2008 standard is helpful, if your tools support it),Be careful, these 3 golden rules are not that easy to check, especially in complicated nested if
and case
statements. This is why I always suggest to beginners to use the trick of default assignments at the very beginning. Rules #2 and #3 become trivial. For rule #1, if your tools support the all
keyword of the VHDL 2008 standard, use it for all combinatorial processes (not for synchronous processes):
state_machine: process(all)