if statement not working as expected in vhdl - vhdl

Below is the a part of a code describing a FSM.
clk_process : process
begin
wait until clk'event ;
if(clk ='0') then
if( state = s2) then
state <= nextstate;
end if;
elsif clk='1' then
state <= nextstate;
end if;
end process clk_process;
state <= nextstate statement is not being executed even when clk='0' , state=s2 and clk event has occurred.
Can anyone reason why this weird behavior is should. What can I do no to do what i intent to do.
Thanx
Edit 1:
library ieee;
use ieee.std_logic_1164.all;
entity machine is
port(clk : in std_logic; out1,out2 : out std_logic);
end entity;
architecture behave of machine is
type statetype is (s0,s1,s2,s3,s4);
signal state,nextstate : statetype :=s0;
begin
-- nextstate<=s0;
comb_process: process(state)
begin
case state is
when s0 =>
nextstate <= s1;
when s1 =>
nextstate <=s2;
out1 <= '1';
out2 <= '1';
when s2 =>
if(clk ='0') then
nextstate <= s3;
out2 <='1';
else
nextstate <=s2;
out1<='0';
out2<='0';
end if;
when s3 =>
nextstate <= s4;
when s4=>
nextstate <= s1;
end case;
end process comb_process;
clk_process : process
begin
wait until clk'event ;
if(clk ='0') then
if( state = s2) then
state <= nextstate;
end if;
elsif clk='1' then
state <= nextstate;
end if;
end process clk_process;
end behave;
This is my full code. What i am trying to do is when state is S2 it should be both positive and negative edge triggered

The problem with your code seems to be that your state machine will get stuck when state = s1 and nextstate = s2. When it gets to this point, the next rising clock edge will cause the clk_process block to change state <= s2. This will cause your comb_process block to trigger while clk = '1', thus causing nextstate <= s2. Once state is equal to nextstate, comb_process will never trigger again.
If you don't care about the number of states bits used for you FSM, you could simply create a state for each clock transition event.

Related

Understanding interferring latch in state machine

Please take a look at this example code of a simple state machine:
entity Top is
Port ( Clock : in STD_LOGIC;
Reset : in STD_LOGIC;
TREADY : out STD_LOGIC
);
end Top;
architecture Behavioral of Top is
type STATE_t is (S0, S1, S2);
signal CurrentState : STATE_t := S0;
signal TREADY_Int : STD_LOGIC := '0';
begin
-- Transit network
process(Clock, Reset, CurrentState)
variable NextState : STATE_t;
begin
if(rising_edge(Clock)) then
case CurrentState is
when S0 =>
if(Reset = '1') then
NextState := S0;
else
NextState := S1;
end if;
when S1 =>
NextState := S2;
when S2 =>
NextState := S1;
end case;
end if;
CurrentState <= NextState;
end process;
-- Output network
process(CurrentState)
begin
if(CurrentState = S0) then
TREADY_Int <= '0';
elsif(CurrentState = S1) then
TREADY_Int <= '1';
elsif(CurrentState = S2) then
TREADY_Int <= '0';
end if;
end process;
TREADY <= TREADY_Int;
end Behavioral;
The synthesis shows me the following warning:
[Synth 8-327] inferring latch for variable 'TREADY_Int_reg'
The warning disappears when I change the last condition of the output network to
else
TREADY_Int <= '0';
end if;
and also the latch is gone
So why does the last condition of the output state machine in the first version result in a latch? Why is else something other than elsif()? In my opinion, the two expressions are equal, because the state machine has only three states, so else and elsif(<ThirdState>) should be the same when all other states are handled. But it seems that my understanding is wrong here.
It's usually best not to assume that a synthesiser is as clever as you are. Using else is safer as you have discovered.
Here's another example. This is better:
process (A, B)
begin
if (A < B)
F <= ...
else
F <= ...
end if;
end process;
than this:
process (A, B)
begin
if (A < B)
F <= ...
end if;
if (A >= B)
F <= ...
end if;
end process;

Finite state machine VHDL reset

I am new to VHDL and I have a question about the implementation of a FSM.
I would like the behaviour shown in the picture (where I implemented the same FSM with AHDL). When I implement it in VHDL I have a different behaviour of the reset : if it detects reset=1 and at the same time there is a rising edge the FSM does not go on but it keeps on putting PS at S0.
I know the problem is that if... elsif (it detects right the 1st condition and does not enter in the 2nd I suppose).
I have tried in many different ways but still is not working and the output stays at 00 also after the 1st rising edge.
Waveforms of AHDL implementation:
Waveforms of VHDL implementation:
LIBRARY ieee; -- Bibliotheksvereinbarung
USE ieee.std_logic_1164.all;
ENTITY sumconvol IS -- Schaltungssymbol
PORT
(
x : IN STD_LOGIC; --input of 1st FF
clk : IN STD_LOGIC; --clock of all the 3 FFs
clrn : IN STD_LOGIC;
y : OUT STD_LOGIC_VECTOR (1 downto 0) --vector of output data
);
END sumconvol;
ARCHITECTURE a OF sumconvol IS -- Creation of architecture
--SIGNAL output_tmp : STD_LOGIC_VECTOR (1 downto 0); -- temporary variables (e.g. input/output between FFs)7
TYPE state_type IS (S0,S1,S2,S3);
SIGNAL NS,PS : state_type;
SIGNAL stato : STD_LOGIC;
BEGIN
sync_proc: PROCESS (clk,clrn)
BEGIN
if ((clrn='1')) THEN
PS<=S0;
y <= "00";
elsif (rising_edge(clk)) then
PS <= NS;
CASE PS IS
when S0 =>
if ((x='0'))then
NS <= S0;
y <= "00";
else
NS <= S1;
y <= "11";
end if;
when S1 =>
if (x='0') then
NS <= S2;
y<="10";
else
NS <= S3;
y <= "01";
end if;
when S2 =>
if (x='0') then
NS <= S0;
y <="11";
else
NS <= S1;
y <= "00";
end if;
when S3 =>
if (x='0') then
NS <= S2;
y <="01";
else
NS <= S3;
y <= "10";
end if;
end case;
end if;
end process sync_proc;
END a;
One thing you might not noticed, is that you put both PS (previous state) and NS (next state) in a clocked process. That means registers are inferred for both signals. Thus, NS will be set to PS one clock later that you would probably expect. This can be solved two ways:
1) remove the PS->NS part, and just use state.
sync_proc: PROCESS (clk, clr)
BEGIN
if clr = '1' THEN
state <= S0;
y <= "00";
elsif rising_edge(clk) then
CASE state IS
when S0 =>
if x = '0' then
state <= S0;
y <= "00";
else
state <= S1;
y <= "11";
end if;
when S1 =>
if x = '0' then
state <= S2;
y<="10";
else
state <= S3;
y <= "01";
end if;
when S2 =>
if x = '0' then
state <= S0;
y <="11";
else
state <= S1;
y <= "00";
end if;
when S3 =>
if (x='0') then
state <= S2;
y <="01";
else
state <= S3;
y <= "10";
end if;
end case;
end if;
end process sync_proc;
2) separate the process into a clocked and a combinatorial process.
clk_proc: PROCESS (clk, clr)
BEGIN
if clr = '1' THEN
PS <= S0;
y <= "00";
elsif rising_edge(clk) then
PS <= NS;
y <= next_y;
end if;
end process;
comb_proc : process(PS, x)
begin
CASE PS IS
when S0 =>
if x = '0' then
NS <= S0;
next_y <= "00";
else
NS <= S1;
next_y <= "11";
end if;
when S1 =>
if x = '0' then
NS <= S2;
next_y <= "10";
else
NS <= S3;
next_y <= "01";
end if;
when S2 =>
if x = '0' then
NS <= S0;
next_y <="11";
else
NS <= S1;
next_y <= "00";
end if;
when S3 =>
if x = '0' then
NS <= S2;
next_y <="01";
else
NS <= S3;
next_y <= "10";
end if;
end case;
end process;
Next, I don't understand what you want with reset. The VHDL code is doing exactly what it should do. This is the proper way to use a reset: as long as the reset is asserted, y should display "00". Then, once it is deasserted, y should change on the next clock edge. That is proper design. What the first (AHDL) picture shows is not good: activity of y during reset.
But anyhow, if you are really stubborn, you can get the behavior that is in the first image using some tricks.
sync_proc: PROCESS (clk)
BEGIN
if (rising_edge(clk)) then
if clr = '1' THEN
state <= S0;
y <= "11";
else
case state is
[...]
p.s. you are calling the process sync_proc, as in "synchronous process". But this is not true, as the reset in your code is asynchronous...
p.s.2: give your signals some proper names, instead of e.g. x...

VHDL Traffic Light

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Traffic_Light is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
input : in STD_LOGIC;
output : out STD_LOGIC_VECTOR(1 DOWNTO 0));
end Traffic_Light;
architecture Behavioral of Traffic_Light is
type state_type is (S0,S1,S2); --type of state machine.
signal present_state, next_state: state_type; --current and next state declaration.
begin
process
begin
wait until clk'event and clk = '0';
present_state <= next_state;
end process;
process (clk,reset)
begin
if (reset='1') then
current_state <= S0; --default state on reset.
end if;
end process;
process (present_state, input)
begin
case present_state is
when S0 => --when current state is s0
if(input = '0') then
output <= "10";
next_state <= S1;
else
output <= "00";
next_state <= S2;
end if;
when S1 => --when current state is s1
if(input = '0') then
output <= "01";
next_state <= S0;
else
output <= "00";
next_state <= S2;
end if;
when S2 => --when current state is s2
if(input = '0') then
output <= "01";
next_state <= S0;
else
output <= "11";
next_state <= S2;
end if;
end case;
end process;
end Behavioral;
I cant seem to get every state change to occur only at the falling edge of the clock.
The simulation does not show the various changes in the present state, it just shows S0 all the way through.
All the state changes have been entered correctly. It just requires the synchronous reset an state changes to occur at the falling edge.
First replace current_state with present_state. Then you can't drive present_state from two processes since it's not a resolved type. You have to do something like
process (clk,reset)
begin
if (reset='1') then
present_state <= S0; --default state on reset.
elsif clk'event and clk = '0' then
present_state <= next_state;
end if;
end process;

FSM in vhdl using counter as output

I am currently writing my first FSM and am unsure of if I have the logic correct. I am tasked with creating a state diagram for the following logic:
A = 00
B = 01
C = 10
D = 11
Output is 1 when:
BDA
BAA
BAD
So I created the following vhdl code to accomplish this:
So every time I get it to output 1 I send it back to B and make count + 1. This is supposed to display on the LED as the number of times it is found in an 18 bit sequence.
Did I approach this in the correct way? I am confused on how I move it through the 18 bit sequence. I am supposed to us the swtiches on the board as my 18 bits which is represented as SW. Would I replace data_in with SW(17 downto 0)?
This is a comment not an answer I putting it in answer as I am not eligible to comment yet.
I think you have some problem in FSM concepts. Also as in the comment said data_in is std_logic not a vector.
you are taking input serially one bit at a time so accordingly write the processes. you can write code to detect the sequences BDA, BAA, BAD that is sequences "011100","010000" and "010011". I would write a simple FSM code so that you can clear you concepts then you can try.
library ieee;
use IEEE.std_logic_1164.all;
entity mealy is
port (clk : in std_logic;
reset : in std_logic;
input : in std_logic;
output : out std_logic
);
end mealy;
architecture behavioral of mealy is
type state_type is (s0,s1,s2,s3); --type of state machine.
signal current_s,next_s: state_type; --current and next state declaration.
begin
process (clk,reset)
begin
if (reset='1') then
current_s <= s0; --default state on reset.
elsif (rising_edge(clk)) then
current_s <= next_s; --state change.
end if;
end process;
--state machine process.
process (current_s,input)
begin
case current_s is
when s0 => --when current state is "s0"
if(input ='0') then
output <= '0';
next_s <= s1;
else
output <= '1';
next_s <= s2;
end if;
when s1 =>; --when current state is "s1"
if(input ='0') then
output <= '0';
next_s <= s3;
else
output <= '0';
next_s <= s1;
end if;
when s2 => --when current state is "s2"
if(input ='0') then
output <= '1';
next_s <= s2;
else
output <= '0';
next_s <= s3;
end if;
when s3 => --when current state is "s3"
if(input ='0') then
output <= '1';
next_s <= s3;
else
output <= '1';
next_s <= s0;
end if;
end case;
end process;
end behavioral;

VHDL edge detection

I want to detect the edges on the serial data signal (din). I have written the following code in VHDL which is running successfully but the edges are detected with one clock period delay i.e change output is generated with one clk_50mhz period delay at each edge. Could anyone please help me to detect edges without delay. Thank you.
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (rst = '0') then
shift_reg <= (others => '0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if rst = '0' then
change <= '0' ;
elsif(clk_enable_2mhz = '1') then
change <= shift_reg(0) xor shift_reg(1);
end if ;
end if ;
end process ;
When I changed my code to following I am able to detect the edges
process (clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
if (RST = '0') then
shift_reg <= (others=>'0');
else
shift_reg(1) <= shift_reg(0);
shift_reg(0) <= din;
end if;
end if;
end process;
change <= shift_reg(1) xor din;
Here you go
library ieee;
use ieee.std_logic_1164.all;
entity double_edge_detector is
port (
clk_50mhz : in std_logic;
rst : in std_logic;
din : in std_logic;
change : out std_logic
);
end double_edge_detector;
architecture bhv of double_edge_detector is
signal din_delayed1 :std_logic;
begin
process(clk_50mhz)
begin
if rising_edge(clk_50mhz) then
if rst = '1' then
din_delayed1 <= '0';
else
din_delayed1 <= din;
end if;
end if;
end process;
change <= (din_delayed1 xor din); --rising or falling edge (0 -> 1 xor 1 -> 0)
end bhv;
You have to use a combinatorial process to detect the difference without incurring extra clock cycle delays. (You will still need one register to delay the input as well.)
DELAY: process(clk_50mhz)
begin
if clk_50mhz'event and clk_50mhz = '1' then
din_reg <= din;
end if;
end process;
change <= din xor din_reg;

Resources