How to simulate buttons in VHDL test bench? - vhdl

I have a basic morse code decoder design implemented in VHDL. It is working fine on an FPGA board but does not work in the test bench.
I guess there is something wrong with the buttons, but I am not sure.
I've tried playing with the clock times in the test bench to no avail.
ARCHITECTURE behavior OF ProjTest IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT LabProject
PORT(
char : IN std_logic_vector(4 downto 0);
save : IN std_logic;
start_read : IN std_logic;
clk : IN std_logic;
p_out : OUT std_logic
);
END COMPONENT;
--Inputs
signal char : std_logic_vector(4 downto 0) := (others => '0');
signal save : std_logic := '0';
signal start_read : std_logic := '0';
signal clk : std_logic := '0';
--Outputs
signal p_out : std_logic := '0';
-- Clock period definitions
constant clk_period : time := 2 ns;
constant wait_time : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: LabProject PORT MAP (
char => char,
save => save,
start_read => start_read,
clk => clk,
p_out => p_out
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
wait for wait_time;
char <= "00001";
wait for wait_time;
save <= '1';
wait for wait_time;
save <= '0';
wait for wait_time;
char <= "00010";
wait for wait_time;
save <= '1';
wait for wait_time;
save <= '0';
wait for wait_time;
char <= "00000";
wait for wait_time;
save <= '1';
wait for wait_time;
save <= '0';
wait for wait_time;
start_read <= '1';
-- wait for wait_time;
-- start_read <= '0';
wait;
end process;
END;
Here is the entire test bench. The start_read and save signals are controlled with push buttons on the FPGA.
The p_out signal should give the Morse code representation of the given letter bit by bit but it never changes in the test bench. There are no problems on the FPGA as I mentioned.

Related

VHDL - Behavioral work correctly, Post Route has problem

I'm new on StackOverflow and I'm sorry for eventual error.
I'm workin on VHDL and I have a problem with the Post-Place & Route. While behavioral works correctly, Post-Place & Route has problem and the result remain UNDEFINED for the all the time.
entity step1 is
port ( d: in std_logic_vector (0 to 5);
clk : in std_logic;
RESET: in std_logic;
q: out std_logic_vector (0 to 5)
);
end step1;
architecture Behavioral of step1 is
begin
ff: process (clk)
begin
if (clk'event and clk='1') then
if (RESET = '1') then
q <= "000000";
else
q <= d;
end if;
end if;
end process;
end Behavioral;
I place here the code. It should be a flip flop D that I use to make a pipeline architecture. Thanks for your reply, and please excuse me for any mistake.
Here's the test bench:
entity test_step1 is
end test_step1
ARCHITECTURE behavior OF test_step1 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT step1
PORT(
input : IN std_logic_vector(0 to 5);
clk : IN std_logic;
RESET : IN std_logic;
output : OUT std_logic_vector(0 to 5)
);
END COMPONENT;
--Inputs
signal input : std_logic_vector(0 to 5) := (others => '0');
signal clk : std_logic := '0';
signal RESET : std_logic := '0';
--Outputs
signal output : std_logic_vector(0 to 5);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: step1 PORT MAP (
input => input,
clk => clk,
RESET => RESET,
output => output
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
RESET <= '1';
wait for 10 ns;
RESET <= '0';
input <= "111111";
wait for clk_period*10;
input <= "101010";
-- insert stimulus here
wait;
end process;
END;
The first warning messages for HDL Compiler 89 and 648 found on the internet are:
WARNING:HDLCompiler:89 - "my_module" remains a black-box since it has no binding entity.
WARNING:Simulator:648 - "Top_LCD_test.vhd" Line 35. Instance top_lcd is unboundCompiling architecture behavior of entity testbench
This means that the compiler has not fount any entity corresponding to the component used in your testbench.
In your case, the port names of your entity and component didn't match !
Try to use the same names in port for the component and entity :
entity test_step1 is
end test_step1;
ARCHITECTURE behavior OF test_step1 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT step1
PORT(
d : IN std_logic_vector(0 to 5);
clk : IN std_logic;
RESET : IN std_logic;
q : OUT std_logic_vector(0 to 5)
);
END COMPONENT;
--Inputs
signal input : std_logic_vector(0 to 5) := (others => '0');
signal clk : std_logic := '0';
signal RESET : std_logic := '0';
--Outputs
signal output : std_logic_vector(0 to 5);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: step1 PORT MAP (
d => input,
clk => clk,
RESET => RESET,
q => output
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
RESET <= '1';
wait for 10 ns;
RESET <= '0';
input <= "111111";
wait for clk_period*10;
input <= "101010";
-- insert stimulus here
wait;
end process;

Issue with synchronous FIFO [VHDL]

I am trying to implement a FIFO from Fpga Prototyping By Vhdl Examples (Wiley) and I am having some issues. The first poped data is actually the second data pushed. It seems to be skipping one slot of the FIFO.
Here is the code:
library IEEE;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
use WORK.my_pkg.ALL;
entity Fifo is
Port(
clk : in STD_LOGIC;
rst_n : in STD_LOGIC;
-- DATA
push_data_i : in STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0); -- Data IN.
pop_data_o : out STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0); -- Data out.
-- CONTROL
push_valid_i : in STD_LOGIC; -- 1 to write push_data_i into the FIFO.
pop_grant_i : in STD_LOGIC; -- 1 to read from the FIFO.
-- STATUS
push_grant_o : out STD_LOGIC; -- 0 when full. To write push_grant_o=1 and push_valid_i=1.
pop_valid_o : out STD_LOGIC -- 1 where there is data available in the FIFO.
);
end Fifo;
architecture Behavioral of Fifo is
type reg_type is array (2**FIFO_DEPTH-1 downto 0) of STD_LOGIC_VECTOR (FIFO_WIDTH-1 downto 0); -- FIFO_WIDTH x FIFO_DEPTH 2D-array.
signal array_reg : reg_type; -- FIFO itself. Data is stored here.
signal write_ptr_reg, write_ptr_next, write_ptr_succ : STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0); -- Write control registers.
signal read_ptr_reg, read_ptr_next, read_ptr_succ : STD_LOGIC_VECTOR (FIFO_DEPTH-1 downto 0); -- Read control registers.
signal full_reg, full_next : STD_LOGIC := '0'; -- Status registers
signal empty_reg, empty_next : STD_LOGIC := '1'; -- Status registers
signal operation : STD_LOGIC_VECTOR (1 downto 0) := "00"; -- Operation 2 bit array
signal wr_en: STD_LOGIC; -- Write possible register.
begin
-- ** PUSH & POP PORTS (data) ** --
process(clk, rst_n)
begin
if(rst_n='0') then
array_reg <= (others=>(others=>'0')); -- Sets the entire array_reg (2D-array) to 0.
write_ptr_reg <= (others=>'0'); -- Resets all write registers (to 0).
read_ptr_reg <= (others=>'0'); -- Resets all read registers (to 0).
full_reg <= '0'; -- Full register is set to 0 as FIFO is not FULL.
empty_reg <= '1'; -- Empty register is set to 1 as FIFO is empty.
elsif (clk'event and clk='1') then -- Rising edge of the clock.
if (wr_en='1') then
array_reg(to_integer(unsigned(write_ptr_reg))) <= push_data_i; -- It writes the incoming data (push_data_i) to the corresponding position in the FIFO.
-- It expects an intiger as the position in the array. Therefore the 'to_intiger' function.
end if;
write_ptr_reg <= write_ptr_next; -- Current write position becomes the next one on clock event.
read_ptr_reg <= read_ptr_next; -- Current read position becomes the next one on clock event.
full_reg <= full_next; -- Current full position becomes the next one on clock event.
empty_reg <= empty_next; -- Current empty position becomes the next one on clock event.
end if;
end process;
-- Input port:
wr_en <= push_valid_i and (not full_reg); -- If FIFO is NOT full it is possible to write.
-- Output port:
-- It is done differently from the input port as the output data ('first-in', pointed by read_ptr_reg)has to be available all the time.
pop_data_o <= array_reg(to_integer(unsigned(read_ptr_reg)));
-- Successive values to read and write when requested.
write_ptr_succ <= STD_LOGIC_VECTOR(unsigned(write_ptr_reg)+1);
read_ptr_succ <= STD_LOGIC_VECTOR(unsigned(read_ptr_reg)+1);
-- ** Events and register control ** --
operation <= (push_valid_i & pop_grant_i); -- Concatenates the two control inputs for the 'case, when' statement.
process(write_ptr_reg, write_ptr_succ, read_ptr_reg, read_ptr_succ,
operation, full_reg, empty_reg)
begin
write_ptr_next <= write_ptr_reg; -- This four lines are to assure that the current state does not
read_ptr_next <= read_ptr_reg; -- change in case none of the case-when statements happen.
full_next <= full_reg;
empty_next <= empty_reg;
case operation is
when "00" => -- Not write (push) or read (pop).
when "01" => -- Read.
if(empty_reg /= '1') then -- If FIFO is NOT empty, it can be read.
read_ptr_next <= read_ptr_succ; -- It points to the successive position to read.
full_next <= '0'; -- As one position is read, FIFO will NOT be full.
if(read_ptr_succ=write_ptr_reg) then -- Read 'reached' write. So the FIFO will be EMPTY.
empty_next <= '1';
end if;
end if;
when "10" => -- Write.
if(full_reg /='1') then -- If FIFO is NOT full, it can be written.
write_ptr_next <= write_ptr_succ;
empty_next <= '0'; -- The FIFO is written, so it will NOT be empty.
if(write_ptr_succ=read_ptr_reg) then -- Write 'reached' read, so the FIFO will be full.
full_next <= '1';
end if;
end if;
when others => -- Write and Read at the same time.
write_ptr_next <= write_ptr_succ;
read_ptr_next <= read_ptr_succ;
end case;
end process;
-- Output STATUS
push_grant_o <= not full_reg;
pop_valid_o <= not empty_reg;
end Behavioral;
my_pkg.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
--use IEEE.math_real."ceil";
--use IEEE.math_real."log2";
package my_pkg is
-- ** This should be used if math_real library available. Otherwise comment lines 24 and 25. Uncomment line 27 ** --
--constant SLOTS : positive := 4; -- This values has to be a power of two (2, 4, 8, 16, etc).
--constant FIFO_DEPTH : positive := integer(ceil(log2(real(SLOTS))));
constant FIFO_DEPTH : positive := 2; -- The number of SLOTS of the FIFO will be 2^FIFO_DEPTH. In this case, 4 slots.
constant DATA_WIDTH : positive := 3;
constant FIFO_WIDTH : positive := DATA_WIDTH+1; --DATAWIDTH=WIDTH+1bitParity
constant PARITY : bit := '0'; -- EVEN or ODD.
constant PARITY_BIT : bit := '0'; -- LSB or MSB.
end my_pkg;
Here is the testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY Fifo_testbench IS
END Fifo_testbench;
ARCHITECTURE behavior OF Fifo_testbench IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Fifo
PORT(
clk : IN std_logic;
rst_n : IN std_logic;
push_data_i : IN std_logic_vector(3 downto 0);
pop_data_o : OUT std_logic_vector(3 downto 0);
push_valid_i : IN std_logic;
pop_grant_i : IN std_logic;
push_grant_o : OUT std_logic;
pop_valid_o : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal rst_n : std_logic := '0';
signal push_data_i : std_logic_vector(3 downto 0) := (others => '0');
signal push_valid_i : std_logic := '0';
signal pop_grant_i : std_logic := '0';
--Outputs
signal pop_data_o : std_logic_vector(3 downto 0);
signal push_grant_o : std_logic;
signal pop_valid_o : std_logic;
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Fifo PORT MAP (
clk => clk,
rst_n => rst_n,
push_data_i => push_data_i,
pop_data_o => pop_data_o,
push_valid_i => push_valid_i,
pop_grant_i => pop_grant_i,
push_grant_o => push_grant_o,
pop_valid_o => pop_valid_o
);
-- Clock process definitions
clk_process :process
begin
clk <= '1';
wait for clk_period/2;
clk <= '0';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 20 ns;
rst_n <= '1';
push_valid_i <= '1';
push_data_i <= "1001";
wait for clk_period;
push_data_i <= "1010";
wait for clk_period;
push_data_i <= "1011";
wait for clk_period;
push_data_i <= "1100";
wait for clk_period;
push_data_i <= "1101";
wait for clk_period;
push_valid_i <= '0';
wait;
end process;
END;
And here the simulation:
The idea is that all the 4 initial values (1001, 1010, 1011 and 1100) are pushed into the FIFO as push_grant_i is enable and the FIFO is not full. For the 5th value (1101) the FIFO cannot push it as it is full. It seems to be working ok, but after the first rising edge of the clock (30ns in the simulation) when the first value (1001) has been pushed it is not on the output port (pop_data_o). In fact, it is the second value, so it skipped 1001. pop_data_o should be updated only if pop_grant_i is 1.
Thanks for the help.
There's a race condition in your testbench. I.e. you change push_data_i at the time of the clock edge. That would also not work in real-life as registers have setup- and hold times. You should use the same clock for the test bench as you use for the UUT. E.g.
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
rst_n <= '1';
wait until rising_edge(clk);
push_valid_i <= '1';
push_data_i <= "1001";
wait until rising_edge(clk);
push_data_i <= "1010";
wait until rising_edge(clk);
push_data_i <= "1011";
wait until rising_edge(clk);
push_data_i <= "1100";
wait until rising_edge(clk);
push_data_i <= "1101";
wait until rising_edge(clk);
push_valid_i <= '0';
wait;
end process;

Simple VHDL clocked counter simulation confusion

I am currently slightly confused about my simple counter.
It is implemented as follows:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity simple_counter is
port(
DOUT : out std_logic_vector(3 downto 0);
CE : in std_logic;
CLK : in std_logic;
RSTN : in std_logic
);
end simple_counter;
architecture behavioral of simple_counter is
signal temp : unsigned(3 downto 0);
begin
process(CLK)
begin
if RSTN = '0' then
temp <= (others => '0');
elsif(rising_edge(CLK)) then
if CE = '1' then
if std_logic_vector(temp) = (temp'range => '1') then
temp <= (others => '0');
else
temp <= temp + 1;
end if;
end if;
end if;
end process;
DOUT <= std_logic_vector(temp);
end behavioral;
I use the following testbench for simulation:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
use work.tools_pkg.all;
library work;
--! #class tools_tb
--! #brief Test bench for the tools_tb design
entity counter_tb is
generic (
VOID : integer := 0);
port (
void_i : in std_logic);
end entity counter_tb;
--! #brief
--! #details
architecture sim of counter_tb is
-- Clock period definitions
-- Clock, reset and baud rate definitions
constant CLK_FREQ : integer := 100_000_000;
constant clk_period : time := (1.0 / real(CLK_FREQ)) * (1 sec);
signal end_sim : boolean := false;
signal rstn : std_logic;
signal clk : std_logic;
signal s_en : std_logic := '0';
------------------------------------------------------------------------------
-- DUT signals
------------------------------------------------------------------------------
signal s_dout : std_logic_vector(3 downto 0) := (others => '0');
signal s_ce : std_logic := '0';
begin -- architecture
fifo : entity work.simple_counter
port map (
DOUT => s_dout,
CE => s_ce,
RSTN => rstn,
CLK => clk
);
-- Clock process definitions (clock with 50% duty cycle is generated here).
clk_process : process
begin
if end_sim = false then
clk <= '1';
wait for clk_period/2;
clk <= '0';
wait for clk_period/2;
else
wait;
end if;
end process;
-- Stimulus process
stim_proc: process
begin
-- startup and wait for some time
rstn <= '0';
wait for clk_period;
rstn <= '1';
wait for clk_period;
wait for clk_period;
wait for clk_period;
s_ce <= '1';
wait;
end process;
end architecture sim;
I am confused why the counter increases instantly when I set CE <= '1
(see the attached simulation).
Since the counter is implemented in a synchrous process, shouldn't it take a single clock cycle until it is increased from '0' to '1'?
Thanks a lot!
You most likely have a race condition between s_ce and clk. If you will generate the s_ce on the rising edge of clk then you should see that counter works correctly.
I don't know this simulator but to check the race you can expand deltas when counter changes 0->1

Why isnt this code in vhdl simulating anything?(testbench and design)

--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity D_flip_flop is
port (
D : in STD_LOGIC;
Q : inout STD_LOGIC;
Q_tonos : out STD_LOGIC;
CLK : in STD_LOGIC;
RST : in STD_LOGIC
);
end D_flip_flop;
architecture Behavioral of D_flip_flop is
begin
process_flip_flip: process
begin
wait until CLK'EVENT AND CLK = '1';
if(RST='1') then
Q <= '0';
else
Q <= D;
end if;
Q_tonos <= not Q;
end process process_flip_flip;
end Behavioral;
-------------------------
--testbench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_flip_flop IS
END test_flip_flop;
ARCHITECTURE tb OF test_flip_flop IS
COMPONENT D_flip_flop
PORT(
D : IN std_logic;
Q : INout std_logic;
Q_tonos : OUT std_logic;
CLK : IN std_logic;
RST : IN std_logic
);
END COMPONENT;
signal D : std_logic ;
signal CLK : std_logic ;
signal RST : std_logic ;
signal Q : std_logic;
signal Q_tonos : std_logic;
constant CLK_period : time := 10 ns;
signal stopClk : boolean;
BEGIN
-- Instantiate the Unit Under Test (UUT)
dut: D_flip_flop PORT MAP (
D => D,
Q => Q,
Q_tonos => Q_tonos,
CLK => CLK,
RST => RST
);
CLK_process :process
begin
while not stopClk loop
CLK <= '0';
wait for CLK_period/2;
CLK <= '1';
wait for CLK_period/2;
end loop;
wait;
end process CLK_process;
-- Stimulus process
stim_proc: process
begin
-- insert stimulus here
D <= '0';
RST <= '1';
wait for 100 ns;
D <= '0';
RST <= '0';
wait for 100 ns;
D <= '1';
RST <= '0';
wait for 100 ns;
D <= '1';
RST <= '0';
wait for 100 ns;
wait;
end process;
END;
You are missing one line in your testbench, I think:
D <= '1';
RST <= '0';
wait for 100 ns;
stopClk <= TRUE; -- add this line
wait;
end process;
END;
http://www.edaplayground.com/x/56Mm
That way, when the test is finished, the clock stopClk signal turns off the clock generator and the simulation finishes. It finishes because it reaches a state called event starvation. Every time a line of code containing a signal assignment is executed, an event is added to the simulators event queue (its "to do list"). If you create a situation where no such lines continue to be executed, then the event queue becomes empty. This is event starvation. The simulator detects that and the simulation stops. (If you think about, what else could it do?)
Without this extra line, the simulation runs forever, because the clock generation process executes signal assignments forever, so the event queue is never empty.
Not really an answer, but: consider using if rising_edge(CLK) or maybe if CLK='1' and CLK'event instead of wait until. Not all synhtesis tools support that kind of code and anyway it's rare to see it in professional world ;)
p.s. stopClk signal is not driven (or was it?) Your TB clock is enably by that, yet I guess it remains 'u' for the whole simulation. Unless forced in the simulation.

VHDL state transitions based on if statements - works on board but doesn't work in simulator

I hate to ask yet another question on here but apparently I'm really useless with simulators :(.
Basically, I have a traffic light controller that is made up of a bunch of different states and a few timers running for different lengths of time. When the system enters a state, it activates a timer and there is an if statement that watches the timer output and points the system to the next state when the timer output value is 1.
This all works fine on the board, but when I simulate it the count ticks to '1' but the next state isn't selected. This can be seen, here:
I've tried to boil the code down into the essentials below, but if you need more context (and are feeling far more generous than I deserve) then the full code is here.
Initialisation:
entity trafficlightcontroller is
port
(
clk : in std_logic;
reset : in std_logic;
ambulance : in std_logic;
smr : in std_logic;
sml : in std_logic;
ssr : in std_logic;
rlmr : out std_logic;
almr : out std_logic;
glmr : out std_logic;
rlsr : out std_logic;
alsr : out std_logic;
glsr : out std_logic
);
end entity;
architecture rtl of trafficlightcontroller is
-- Build an enumerated type for the state machine
-- r=red;a=amber;g=green;c=car waiting;m=main road;s=side road
type state_type is (rmgs, rmas, rmrs, amrs, gmrs, gmrcs, ramrs, rmacs, rmrcs, ramrcs, rmras, rmrs2);
-- Signals to hold the states
signal present_state, next_state : state_type;
signal divclk, reset2, reset2b, reset3, reset3b, reset10, reset20, reset20b, count2, count2b, count3, count3b, count10, count20, count20b: std_logic;
component timer is
generic (
trigger_cnt: natural := 20
);
port (
clk: in std_logic;
reset: in std_logic;
count: buffer std_logic
);
end component timer;
component clockdivider
port(clkin : in std_logic;
dividedclk : out std_logic
);
end component clockdivider;
begin
timer2 : timer generic map (trigger_cnt => 2) port map(divclk,reset2,count2);
timer2b : timer generic map (trigger_cnt => 2) port map(divclk,reset2b,count2b);
timer3 : timer generic map (trigger_cnt => 3) port map(divclk,reset3,count3);
timer3b : timer generic map (trigger_cnt => 3) port map(divclk,reset3b,count3b);
timer10 : timer generic map (trigger_cnt => 10) port map(divclk,reset10,count10);
timer20 : timer generic map (trigger_cnt => 20) port map(divclk,reset20,count20);
timer20b : timer generic map (trigger_cnt => 20) port map(divclk,reset20b,count20b);
divider : clockdivider port map(clk, divclk);
The beginning of the states (including the state shown in the simulation):
case present_state is
--Red light main; green side road
when rmgs=>
reset2 <= '0';
reset2b <= '0';
reset3 <= '0';
reset3b <= '0';
reset20 <= '0';
reset20b <= '0';
rlmr <= '1';
almr <= '0';
glmr <= '0';
rlsr <= '0';
alsr <= '0';
glsr <= '1';
reset10 <= '1';
--if count is complete then move to next state
if ( count10='1' ) THEN
next_state <= rmas;
--otherwise, return to current state
else
next_state <= rmgs;
end if;
Clock process:
--Every clock tick, the next state is selected as the present state.
state_clocked: process(clk)
begin
if ( rising_edge( clk ) ) THEN
present_state <= next_state;
end if;
end process state_clocked;
The line I entered into the simulator to initialise the clock:
force clk 0 0ns, 1 10 ns -repeat 20ns
Your next_state process is missing lots of signals in the sensitivity list. This will probably fix it. VHDL-2008 allows you to use the keyword "all" instead of signal names. If your synthesis tool supports this, it might be worth using.
The rest are suggestions:
With a two process statemachine, reset logic is most often captured in the state_clocked process. And hence, look more like this:
state_clocked: process(clk)
begin
if ( rising_edge( clk ) ) THEN
if Reset = '0' then
present_state <= rmrs;
else
present_state <= next_state;
end if ;
end if;
end process state_clocked;
You can shorten your code significantly if you use a default assignment to assign the "off" value to all signal outputs of the next_state process:
next_state_proc : process (present_state, ssr, ambulance, Count10, Count3, ... )
begin
-- default assignments
reset2 <= '0';
reset2b <= '0';
reset3 <= '0';
reset3b <='0';
reset10 <= '0';
reset20 <= '0';
reset20b <= '0';
rlmr <= '1';
almr <= '0';
glmr <= '0';
rlsr <= '1';
alsr <= '0';
glsr <= '0';
next_state <= present_state ; -- optional
-- Statemachine code starts here
-- Only do assignments that are different from the default.
if ssr = '0' then
-- Do you change the values from the defaults here?
-- with the defaults, it is not necessary to do any assignments here, however,
-- without the defaults these outputs would have latches on them.
case present_state is
when gmrs => next_state <= gmrcs;
when rmas => next_state <= rmacs;
...
end case ;
elsif ambulance = '0' then
-- Do you change the values from the defaults here?
-- with the defaults, it is not necessary to do any assignments here, however,
-- without the defaults these outputs would have latches on them.
case present_state is
when gmrs | ramrs | ramrcs => next_state <= amrs;
-- when rmas => ???
when rmgs | rmras => next_state <= rmas;
...
end case ;
else
-- main statemachine
case present_state is
when rmgs=>
-- Only drive outputs that are different from the defaults here.
rlsr <= '0';
glsr <= '1';
reset10 <= '1';
--if count is complete then move to next state
if ( count10='1' ) THEN
next_state <= rmas;
--otherwise, return to current state
else
next_state <= rmgs;
end if;
when rmas=>
. . .
end case ;
The reset for the present_state register isn't strictly needed for simulation, but should be there for synthesis.
state_clocked:
process(reset,clk)
begin
if reset = '0' then
present_state <= rmrs;
elsif rising_edge( clk ) THEN
present_state <= next_state;
end if;
end process;
(Jim beat me to it).
process (present_state, reset, ssr, ambulance, count2, count2b,
count3, count3b, count10, count20, count20b)
Adding the process sensitivity elements (and using reset):
(I added a bit more to it. A lot of your design appears to be working to a good extent.)
And think about using a test bench, it would allow automated testing by generating inputs on ambulance, smr, sml and ssr.
library ieee;
use ieee.std_logic_1164.all;
entity tb_tfc is
end entity;
architecture foo of tb_tfc is
signal clk: std_logic := '0';
signal reset: std_logic;
signal ambulance: std_logic := '1';
signal smr: std_logic := '1';
signal sml: std_logic := '1';
signal ssr: std_logic := '1';
signal rlmr: std_logic;
signal almr: std_logic;
signal glmr: std_logic;
signal rlsr: std_logic;
signal alsr: std_logic;
signal glsr: std_logic;
begin
DUT:
entity work.trafficlightcontroller
port map (
clk,
reset,
ambulance,
smr,
sml,
ssr,
rlmr, -- out
almr, -- out
glmr, -- out
rlsr, -- out
alsr, -- out
glsr -- out
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 1280 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
reset <= '0'; --
wait for 20 ns;
reset <= '1';
wait for 1020 ns;
ssr <= '0';
wait;
end process;
end architecture;

Resources