Just wondering if I'm implementing a finite state machine in VHDL whether or not I need to state what all of the outputs are in every possible state? Even if I know that some outputs won't change from one state to the other and I know that the order of the states will also be in the same order?
For example, in this (forced) example:
entity test is
port (
clk : in std_logic;
a : in std_logic;
b: out std_logic;
c: out std_logic;
);
end test;
architecture Behavioral of test is
type executionStage is (s1,s2,s3);
signal currentstate, nextstate: executionStage;
begin
process (clk)
begin
if(rising_edge(clk)) then
currentstate <= nextstate;
else
currentstate <= currentstate;
end if;
end process;
process(currentstate)
begin
case currentstate is
when s1 =>
if (a = '1') then
b <= '1';
c <= '0';
else
b <= '1';
c <= '1';
end if;
nextstate <= s2;
when s2 =>
-- b doesnt change state from s1 to here, do I need to define what it is here?
if (a = '1') then
b <= '1';
c <= '1';
else
b <= '1';
c <= '0';
end if;
nextstate <= s3;
when s3 =>
if (a = '1') then
b <= '0';
c <= '0';
else
b <= '1';
c <= '1';
end if;
nextstate <= s1;
end case;
end process;
end Behavioral;
From my understanding if I don't do this then latches are created?
It's not a big deal in something like that example but if I have a machine with more than 10 outputs and more than 10 states then my VHDL files start to look incredibly messy and I'm sure it must be bad practice to copy and paste the same thing over and over. Is there a better way of doing this?
edit: Can I define a 'default' state for an ouput? IE set b to be 1 outside of all the processes and then only define what it is in the case statements where it is 0? Would that work?
Yes, you will infer latches if you only drive signals intended to be combinatorial in some branches of the process.
However, you can define a 'default' state for the signal simply by assigning a value to it before the case statement (but within the same process). For example:
process(currentstate, a)
begin
b <= '1';
c <= '1';
case currentstate is
when s1 =>
if (a = '1') then
c <= '0';
end if;
nextstate <= s2;
when s2 =>
-- b doesnt change state from s1 to here, do I need to define what it is here?
if (a /= '1') then
c <= '0';
end if;
nextstate <= s3;
when s3 =>
if (a = '1') then
b <= '0';
c <= '0';
end if;
nextstate <= s1;
end case;
end process;
Three problems with your example code:
The last port in your port list should not have a semicolon:
port (
clk : in std_logic;
a : in std_logic;
b: out std_logic;
c: out std_logic -- no semicolon here!!!
);
In your register process, you should not have an "else" statement. While this will probably be accepted by the tools, it will confuse your fellow-VHDL designers.
process (clk)
begin
if(rising_edge(clk)) then
currentstate <= nextstate;
end if;
end process;
In your combinational logic, the sensitivity list should contain all signals that you read: process(a, currentstate). In this particular case (again) things will probably work out fine, but you are bound to infer latches or cause other problems if your sensitivity list is not correct.
As for your question:
Yes, you need to assign a value (for each state) to each signal in the combinational process.
As Tomi mentions, you can easily do this by assigning a default value in the beginning of the process.
But you can also write the entire state machine in one single synchronous process. This way, you do not have to assign a value to every signal in every state.
Just a note to Philippe's response (can't comment on it directly?)..
I do prefer to write state machines in the two process style. It makes it very clear where you expect inferred flipflops and where you don't. It's also a bit more along the lines of
describing the hardware - imagine building a state machine with board level logic for example.
The registered device matches the state <= next_state process,
and the case statement maps to the and/or array in front of the state register..
Having said that, I typically use one process state machines for small simple tasks, and move over to two process machines for bigger ones.
I will even sometimes use a third process for organizing state outputs into different "task" groups.. but not often. A really large state machine tends to tell me the architecture needs work..
process (clk)
begin
if(rising_edge(clk)) then
currentstate <= nextstate;
end if;
end process;
Hi
the above process is problematic but not due to the sensitivity list. It is ok to only declare clk for sequential process. Both simulation and synthesis tools won't have problems with it. clk is the fastest changing/transitioning signal after all in your code.
However, you should use an (preferrably) asynchronous reset. Of course, vendors nowadays say that for FPGA design, resets are not even necessary; they happen at boot time. Or they propose a synchronous reset.
Still, an asynchronous reset is valuable for a board-based environment.
In short: add a reset to your design and fix its behavior properly.
Kind regards
Nikolaos Kavvadias
The following VHDL code is edge sensitive state machine.
The edge sensitive process in this example will make both “out1” and “out2” in phase with “clk”.
entity main_code is
Port ( clk : in STD_LOGIC;
in1 : in STD_LOGIC;
in2 : in STD_LOGIC;
out1 : out STD_LOGIC;
out2 : out STD_LOGIC);
end main_code;
architecture Behavioral of main_code is
-- here are temp signals to associate or assign output (out1 and out2) values indirectly
signal out1_temp : std_logic := '0';
signal out2_temp : std_logic := '0';
-- counter registers
signal counter : integer range 0 to 255 := 0;
signal counter_8th_clk : integer range 0 to 255 := 0;
-- state machines definition
type state_machine_type is (s0,s1);
signal state : state_machine_type := s0;
begin
-- concurrent assignments
out1 <= out1_temp;
out2 <= out2_temp;
--half clock generator process
half_clock : process (clk) is
begin
if rising_edge(clk) then
--out1_temp <= not out1_temp;
end if;
end process half_clock;
-- max counter = ndiv -1; here ndiv=4; counter starts from zero;
one_fourth_clock : process (clk)
begin
if rising_edge(clk) then
counter <= counter + 1;
if (counter >= 3) then
counter <= 0;
-- out2_temp <= not out2_temp;
end if;
end if;
end process one_fourth_clock;
one_eighth_clock : process (clk)
begin
if rising_edge(clk) then
counter_8th_clk <= counter_8th_clk + 1;
if (counter_8th_clk>=7) then
counter_8th_clk <= 0;
-- out2_temp <= not out2_temp;
end if;
end if;
end process one_eighth_clock;
-- state_process creates two half clock (speed) with out1 out of phase with clk
-- and out2 in-phase with clk
-- following process is sensitive to clk level not edge
state_process_edge_sensitive : process (clk)
begin
if rising_edge (clk) then
case state is
when s0 =>
out1_temp <= not out1_temp;
state <= s1;
when s1 =>
out2_temp <= not out2_temp;
state <= s0;
end case;
end if;
end process state_process_edge_sensitive;
end Behavioral;
here is the test bench
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 my_test_bench IS
END my_test_bench;
ARCHITECTURE behavior OF my_test_bench IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT main_code
PORT(
clk : IN std_logic;
in1 : IN std_logic;
in2 : IN std_logic;
out1 : OUT std_logic;
out2 : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal in1 : std_logic := '0';
signal in2 : std_logic := '0';
--Outputs
signal out1 : std_logic;
signal out2 : std_logic;
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: main_code PORT MAP (
clk => clk,
in1 => in1,
in2 => in2,
out1 => out1,
out2 => out2
);
-- 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.
-- wait for 100 ns;
--
-- wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
The following VHDL code is level sensitive state machine.
The level sensitive process in this example will make “out1” out of phase with “clk” and “out2” in phase with “clk”.
entity main_code is
Port ( clk : in STD_LOGIC;
in1 : in STD_LOGIC;
in2 : in STD_LOGIC;
out1 : out STD_LOGIC;
out2 : out STD_LOGIC);
end main_code;
architecture Behavioral of main_code is
-- here are temp signals to associate or assign output (out1 and out2) values indirectly
signal out1_temp : std_logic := '0';
signal out2_temp : std_logic := '0';
-- counter registers
signal counter : integer range 0 to 255 := 0;
signal counter_8th_clk : integer range 0 to 255 := 0;
-- state machines definition
type state_machine_type is (s0,s1);
signal state : state_machine_type := s0;
begin
-- concurrent assignments
out1 <= out1_temp;
out2 <= out2_temp;
--half clock generator process
half_clock : process (clk) is
begin
if rising_edge(clk) then
--out1_temp <= not out1_temp;
end if;
end process half_clock;
-- max counter = ndiv -1; here ndiv=4; counter starts from zero;
one_fourth_clock : process (clk)
begin
if rising_edge(clk) then
counter <= counter + 1;
if (counter >= 3) then
counter <= 0;
-- out2_temp <= not out2_temp;
end if;
end if;
end process one_fourth_clock;
one_eighth_clock : process (clk)
begin
if rising_edge(clk) then
counter_8th_clk <= counter_8th_clk + 1;
if (counter_8th_clk>=7) then
counter_8th_clk <= 0;
-- out2_temp <= not out2_temp;
end if;
end if;
end process one_eighth_clock;
-- state_process creates two half clock (speed) with out1 out of phase with clk
-- and out2 in-phase with clk
-- following process is sensitive to clk level not edge
state_process_level_sensitive : process (clk)
begin
case state is
when s0 =>
out1_temp <= not out1_temp;
state <= s1;
when s1 =>
out2_temp <= not out2_temp;
state <= s0;
end case;
end process state_process_level_sensitive;
end Behavioral;
here is the test bench
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 my_test_bench IS
END my_test_bench;
ARCHITECTURE behavior OF my_test_bench IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT main_code
PORT(
clk : IN std_logic;
in1 : IN std_logic;
in2 : IN std_logic;
out1 : OUT std_logic;
out2 : OUT std_logic
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal in1 : std_logic := '0';
signal in2 : std_logic := '0';
--Outputs
signal out1 : std_logic;
signal out2 : std_logic;
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: main_code PORT MAP (
clk => clk,
in1 => in1,
in2 => in2,
out1 => out1,
out2 => out2
);
-- 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.
-- wait for 100 ns;
--
-- wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
Related
Let's assume I have two processes PROC_A and PROC_B, and they share a signal between them. Let me write a dummy example:
library ieee;
use ieee.std_logic_1164.all;
entity example is
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end architecture rtl;
Now, I want to have a pipeline register between a_and_b and ab_xor_c signals, and I want to hardcode it but also enable/disable it with ease. I really want something like a ifdef in C/C++. I could think of a generic to do that but I am also open to any other method (maybe with pragmas?). I am writing an example below, I know that it is so wrong in terms of VHDL but just see it as an idea:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic (
PIPELINE_EN : std_logic := '1');
port (
clk : in std_logic;
rst_n : in std_logic;
a : in std_logic;
b : in std_logic;
c : in std_logic;
z_out : out std_logic);
end entity example;
architecture rtl of example is
signal a_and_b : std_logic;
signal ab_xor_c : std_logic;
if PIPELINE_EN = '1' then
signal pipeline_reg : std_logic;
end if;
begin -- architecture rtl
z_out <= ab_xor_c;
PROC_A : process (clk, rst_n) is
begin -- process PROC_A
if rst_n = '0' then -- asynchronous reset (active low)
a_and_b <= '0';
elsif rising_edge(clk) then -- rising clock edge
a_and_b <= a and b;
end if;
end process PROC_A;
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN = '1' then
pipeline_reg <= '0'
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN = '1' then
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
end architecture rtl;
Your example has been modified to removed the register from process A and show a generic controlling the presence of the register. Additional pipeline registers could be added generically as well.
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic ( PIPELINED: BOOLEAN := TRUE);
port (
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example;
architecture genericly_pipelined of example is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic;
begin
NO_PIPELINE:
if not PIPELINED generate
PROC_A:
process (a, b) is
begin
a_and_b <= a and b; -- could be a concurrent statement instead
end process;
end generate;
GEN_PIPELINED:
if PIPELINED generate
PIPELINED_PROC_A:
process (clk, rst_n) is
begin
if rst_n = '0' then
a_and_b <= '0';
elsif rising_edge(clk) then
a_and_b <= a and b;
end if;
end process;
end generate;
PROC_B:
process (clk, rst_n) is
begin
if rst_n = '0' then
ab_xor_c <= '0';
elsif rising_edge(clk) then
ab_xor_c <= a_and_b xor c;
end if;
end process;
end architecture genericly_pipelined;
The granularity using a generate statement is to a concurrent statement. For purposes of changing signal names you can declare intermediary signals in the block statement elaborated by the generate statement's block declarative region. Generate statements can be nested (it's a concurrent statement) which can be used to add more pipeline registers.
A generate statement body can have a block declarative part prior to any concurrent statements in the block statement body. Concurrent statements are delineated by the reserved words begin and end followed by a semicolon when any declarations are present in the block declarative part. E.g. IEEE Std 10786-2008:
11.8 Generate statements
if_generate_statement ::=
generate_label :
if [ alternative_label : ] condition generate
generate_statement_body
{ elsif [ alternative_label : ] condition generate
generate_statement_body }
[ else [ alternative_label : ] generate
generate_statement_body ]
end generate [ generate_label ] ;
generate_statement_body ::=
[ block_declarative_part
begin ]
{ concurrent_statement }
[ end [ alternative_label ] ; ]
The generate statements in the above VHDL code have no declarations. Braces { } enclosing the item concurrent_statement indicate you can use the 'long form' with the begin and end reserved words with zero or more concurrent statements. You'd declare any intermediary signals used to communicate between statements found in different generate statements in the same design hierarchy. (The block statement elaborated by a generate statement is a separate declarative region.)
The BNF found in the standard's numbered sections is normative.
Note you didn't assign z_out.
Here's an example compatible with the OP's code:
library ieee;
use ieee.std_logic_1164.all;
entity example1 is
generic ( PIPELINES: natural := 1);
port (
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example1;
architecture generic_pipeline_stages of example1 is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic;
begin
NO_PIPELINE:
if PIPELINES = 0 generate
PROC_A:
process (a, b) is
begin
a_and_b <= a and b; -- could be a concurrent statement instead
end process;
end generate;
GEN_PIPELINED:
if PIPELINES > 0 generate
type pipeline is array (0 to PIPELINES - 1) of std_logic;
signal pipeline_reg: pipeline;
begin
PIPELINED_PROC_A:
process (clk, rst_n) is
begin
if rst_n = '0' then
pipeline_reg <= (others => '0');
elsif rising_edge(clk) then
for i in pipeline'range loop
if i = 0 then
pipeline_reg(i) <= a and b;
else
pipeline_reg(i) <= pipeline_reg(i - 1);
end if;
end loop;
end if;
end process;
a_and_b <= pipeline_reg(PIPELINES - 1); -- a separate process
end generate;
PROC_B:
process (clk, rst_n) is
begin
if rst_n = '0' then
ab_xor_c <= '0';
elsif rising_edge(clk) then
ab_xor_c <= a_and_b xor c;
end if;
end process;
end architecture generic_pipeline_stages;
which produces:
And shows the two clock delays using natural generic PIPELINES.
With PIPELINES = 1:
The signals a_and_b and a_xor_b show up one clock earlier. It's compatible with the first VHDL example in this answer with PIPELINED = TRUE.
Note the block declarative part contains a composite signal declaration for the pipeline stages. A generate statement is it's own declarative region which means pipeline_reg wouldn't be visible outside the elaborated block. To access intermediary pipeline stages you'd either move the pipeline_reg declaration to the top level (example1, here) or assign signals declared in the top level assigned in the generate statement.
Principles in the design you wrote are fine, except for the if PIPELINE_EN = '1' then part in the declaration of pipeline_reg, which should be skipped, since the synthesis will then just remove the unused pipeline_reg. Also I would suggest that PIPELINE_EN is declared as type boolean instead, since that is a more obvious choice, and the = '1' can then be skipped in the conditions.
If for some reason you want to avoid declaration of the pipeline signal 'pipeline_reg' in the actual design, then you can declare a variable in the process, with code like below. It is required to assign the variable after use in the code, to get a flip-flop, since it otherwise just becomes combinatorial logic. However, such creation of flip-flops through use of variables is advised against, since it is hard to read and get right, thus error prone, and should be avoided in general. Though here it comes:
PROC_B : process (clk, rst_n) is
variable pipeline_reg_v : std_logic; -- Results in pipeline register if PIPELINE_EN, otherwise removed by synthesis
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
if PIPELINE_EN then
pipeline_reg_v := '0';
end if;
elsif rising_edge(clk) then -- rising clock edge
if PIPELINE_EN then
ab_xor_c <= pipeline_reg_v xor c;
pipeline_reg_v := a_and_b;
else
ab_xor_c <= a_and_b xor c;
end if;
end if;
end process PROC_B;
An alternative is to use the VHDL block construction, together with generate, whereby you can have signal declarations that are local to the block, as shown below. Though note that the block construction is rarely used in VHDL, thus there is a higher risk of encountering bugs in tools.
PIPELINE_EN_TRUE_GENERATE : if PIPELINE_EN generate
PIPELINE_EN_TRUE_BLOCK : block
signal pipeline_reg : std_logic;
begin
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
pipeline_reg <= '0';
elsif rising_edge(clk) then -- rising clock edge
pipeline_reg <= a_and_b;
ab_xor_c <= pipeline_reg xor c;
end if;
end process PROC_B;
end block PIPELINE_EN_TRUE_BLOCK;
end generate PIPELINE_EN_TRUE_GENERATE;
PIPELINE_EN_FALSE_GENERATE : if not PIPELINE_EN generate
PROC_B : process (clk, rst_n) is
begin -- process PROC_B
if rst_n = '0' then -- asynchronous reset (active low)
ab_xor_c <= '0';
elsif rising_edge(clk) then -- rising clock edge
ab_xor_c <= a_and_b xor c;
end if;
end process PROC_B;
end generate PIPELINE_EN_FALSE_GENERATE;
With a generic parameter for the pipeline depth:
library ieee;
use ieee.std_logic_1164.all;
entity example is
generic(
depth: natural := 0
);
port(
clk: in std_logic;
rst_n: in std_logic;
a: in std_logic;
b: in std_logic;
c: in std_logic;
z_out: out std_logic
);
end entity example;
architecture rtl of example is
signal a_and_b: std_logic;
signal ab_xor_c: std_logic_vector(0 to depth);
begin
z_out <= ab_xor_c(depth);
process(clk, rst_n) is
begin
if rst_n = '0' then
a_and_b <= '0';
ab_xor_c <= (others => '0');
elsif rising_edge(clk) then
a_and_b <= a and b;
ab_xor_c <= ab_xor_c srl 1;
ab_xor_c(0) <= a_and_b xor c;
end if;
end process;
end architecture rtl;
And then, with depth=2:
use std.env.all;
library ieee;
use ieee.std_logic_1164.all;
entity example_sim is
end entity example_sim;
architecture sim of example_sim is
signal clk: std_logic;
signal rst_n: std_logic;
signal a: std_logic;
signal b: std_logic;
signal c: std_logic;
signal z_out: std_logic;
begin
u0: entity work.example(rtl)
generic map(
depth => 2
)
port map(
clk => clk,
rst_n => rst_n,
a => a,
b => b,
c => c,
z_out => z_out
);
process
begin
clk <= '0';
wait for 1 ns;
clk <= '1';
wait for 1 ns;
end process;
process
begin
rst_n <= '0';
a <= '1';
b <= '1';
c <= '1';
wait until rising_edge(clk);
rst_n <= '1';
for i in 1 to 15 loop
wait until rising_edge(clk);
c <= not c;
end loop;
finish;
end process;
end architecture sim;
Demo:
$ ghdl -a --std=08 example_sim.vhd
$ ghdl -r --std=08 example_sim --vcd=example_sim.vcd
simulation finished #21ns
$ open example_sim.vcd
Of course, if your data type (T) is more complex than a single std_logic you will need some extra work.
Define a vector type of your data type (T_vector).
Define a "zero" constant value for your base type (T_zero), this will be the value that enters on the left when shifting to the right.
Overload the srl operator for the T_vector vector type.
Example with a T type (not tested):
type T_vector is array(natural range <>) of T;
constant T_zero: T := <some zero value for your type>;
...
function "srl"(l: T_vector; r: natural) return T_vector is
constant size: positive := l'length;
constant tmp: T_vector(0 to size - 1) := l;
variable res: T_vector(0 to size - 1);
begin
if r = 0 then
res := tmp;
elsif r = 1 then
res := T_zero & tmp(0 to size - 2);
else
res := (l srl 1) srl (r - 1);
end if;
return res;
end function "srl";
I have a project submission that requires me to design a pattern detector that detects and counts the occurrence of '11100' in the given input sequence. I have 2 codes. One is the actual code to generate the pattern and count it. the 2nd code is a testbench. I have very little experience with VHDL so please guide me.
I am trying to send a '11100' such that it goes in bit by bit automatically.
pattern_recogniser.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--Sequence detector for detecting the sequence "11100".
--Non overlapping type.
entity pattern_recogniser is
port( clk : in std_logic; --clock signal
reset : in std_logic; --reset signal
data : in std_logic; --serial bit sequence
-- det_vld : out std_logic; --A '1' indicates the pattern "1011" is detected in the sequence.
count : out integer);
end pattern_recogniser;
architecture Behavioral of pattern_recogniser is
type state_type is (A,B,C,D,E); --Defines the type for states in the state machine
signal state : state_type := A; --Declare the signal with the corresponding state type.
signal ct : integer;
begin
process(clk)
begin
if( reset = '0' ) then --resets state and output signal when reset is asserted.
-- det_vld <= '0';
ct <= 00000000;
state <= A;
elsif ( rising_edge(clk) ) then --calculates the next state based on current state and input bit.
case state is
when A => --when the current state is A.
-- det_vld <= '0';
if ( data = '0' ) then
state <= A;
else
state <= B;
end if;
when B => --when the current state is B.
if ( data = '0' ) then
state <= A;
else
state <= C;
end if;
when C => --when the current state is C.
if ( data = '0' ) then
state <= A;
else
state <= D;
end if;
when D => --when the current state is C.
if ( data= '0' ) then
state <= E;
else
state <= D;
end if;
when E => --when the current state is D.
if ( data = '0' ) then
state <= A;
-- det_vld <= '1';
ct <= ct + 1;
else
state <= B;
--Output is asserted when the pattern "11100" is found in the sequence.
end if;
when others =>
NULL;
end case;
end if;
end process;
process (ct)
begin
if(ct >=99) then
count <= 99; -- the count must show a "--" on the 7 segment display after it exceeds 99.
else
count <= ct;
end if;
end process;
end Behavioral;
and the second: testbench.vhd:
library ieee;
use ieee.std_logic_1164.all;
entity testbench is
port(count_t: out integer);
end testbench;
architecture behav of testbench is
component testset
port( ck : out std_logic;
rst : out std_logic;
dout : out std_logic);
end component;
component pattern_recogniser
port( clk : in std_logic; --clock signal
reset : in std_logic; --reset signal
data : in std_logic; --serial bit sequence
count : out integer);
end component;
signal clk_1 : std_logic := '0';
signal reset_1 : std_logic := '0';
signal data_1 : std_logic := '1';
signal count_s : integer := 0;
begin
--tb: testset port map (ck => clk_1, rst => reset_1, dout => data_1);
pat_rec : pattern_recogniser port map (clk => clk_1, reset => reset_1, data => data_1, count => count_s);
process(clk_1)
begin
clk_1 <= not clk_1 after 100 ps;
end process;
process is
begin
wait for 600 ps;
data_1 <= '0';
wait for 400 ps;
end process;
count_t <= count_s;
end behav;
I am not able to generate this sequence automatically using the ifs in the testbench. I have to generate it 110 times, then perform a rest and then 50 times more. How do I achieve this? Any help would be highly appreciated!!!
I have a simple VHDL design and test bench that does not produce the expected output. ISim shows 'U' for all the outputs until the 'running' state is achieved (myState='1'). Then they show 0 and X values. The first PROCESS block should set all outputs to '0' when ENABLE is '0'. The test bench toggles ENABLE 0-1-0 to insure an event triggers the process, but the outputs stay at 'U'. Is the problem in the design, the test, or both?
VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TestHarness1 is
port (
ADAT_WDCLK : in std_logic;
ADAT_BCLK: in std_logic;
ADAT_OUT12: in std_logic;
ENABLE: in std_logic;
PCM_FS : out std_logic;
PCM_CLK : out std_logic;
PCM_DIN : out std_logic
);
end TestHarness1;
architecture Behavioral of TestHarness1 is
--type state is (STOPPED, RUNNING);
signal tmp : std_logic;
signal myState : std_logic;
begin
PCM_DIN <= tmp;
-- State management process
process (ENABLE, ADAT_WDCLK) begin -- Eval on input changes
if (ENABLE = '0') then
myState <= '0'; --STOPPED;
PCM_FS <= '0'; -- All outputs muted
PCM_CLK <= '0';
tmp <= '0';
else
if (myState = '0' and rising_edge(ADAT_WDCLK)) then
-- Move to running state only at start of a frame
myState <= '1'; --RUNNING;
end if;
end if;
end process;
-- Output process
process (ADAT_WDCLK, ADAT_BCLK, myState) variable counter: integer := 0; begin
-- Only do something if we are in running state, process above
-- sets outputs when stopped.
if (myState = '1') then
-- Pass the clocks through, inverting the bit clock
PCM_FS <= ADAT_WDCLK;
PCM_CLK <= not ADAT_BCLK;
-- Generate fixed bit pattern data '11000101'
if rising_edge(ADAT_WDCLK) then
-- This would happen naturally since there are 4 bytes per word clock
counter := 0;
end if;
if falling_edge(ADAT_WDCLK) then
-- This would happen naturally since there are 4 bytes per word clock
counter := 0;
end if;
if rising_edge(ADAT_BCLK) then -- Change data state only on falling edge of output PCM_CLK
if counter = 0 or counter = 1 or counter = 5 or counter = 7 then
tmp <= '1';
else
tmp <= '0';
end if;
if (counter = 7) then
counter := 0; -- Reset counter
else
counter := counter + 1; -- Just inc counter
end if;
end if;
end if;
end process;
end Behavioral;
Test Bench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY TH1TestBench3 IS
END TH1TestBench3;
ARCHITECTURE behavior OF TH1TestBench3 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT TestHarness1
PORT(
ADAT_WDCLK : IN std_logic;
ADAT_BCLK : IN std_logic;
ADAT_OUT12 : IN std_logic;
ENABLE : IN std_logic;
PCM_FS : OUT std_logic;
PCM_CLK : OUT std_logic;
PCM_DIN : OUT std_logic
);
END COMPONENT;
--Inputs
signal ADAT_WDCLK : std_logic := '0';
signal ADAT_BCLK : std_logic := '0';
signal ADAT_OUT12 : std_logic := '0';
signal ENABLE : std_logic := '0';
--Outputs
signal PCM_FS : std_logic;
signal PCM_CLK : std_logic;
signal PCM_DIN : std_logic;
-- Clock period definitions. Note WDCLK is defined in terms of the bit clock
-- to insure they are exactly in sync.
constant ADAT_BCLK_period : time := 326 ns; -- About 3.072MHz (https://www.sensorsone.com/frequency-to-period-calculator/)
constant ADAT_WDCLK_period : time := ADAT_BCLK_period * 64; -- 48KHz
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: TestHarness1 PORT MAP (
ADAT_WDCLK => ADAT_WDCLK,
ADAT_BCLK => ADAT_BCLK,
ADAT_OUT12 => ADAT_OUT12,
ENABLE => ENABLE,
PCM_FS => PCM_FS,
PCM_CLK => PCM_CLK,
PCM_DIN => PCM_DIN
);
-- Clock process definitions
ADAT_WDCLK_process :process
begin
ADAT_WDCLK <= '0';
wait for ADAT_WDCLK_period/2;
ADAT_WDCLK <= '1';
wait for ADAT_WDCLK_period/2;
end process;
ADAT_BCLK_process :process
begin
ADAT_BCLK <= '1';
wait for ADAT_BCLK_period/2;
ADAT_BCLK <= '0';
wait for ADAT_BCLK_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
ENABLE <= '1';
wait for 100 ns;
ENABLE <= '0';
wait for 7500 ns;
ENABLE <= '1';
wait for ADAT_WDCLK_period*10;
-- insert stimulus here
wait;
end process;
END;
ISim shows the ENABLE pulse early in the simulation, but the outputs remain 'U' until the rising edge of the WCLK with ENABLE=1. Then they start to change (as designed) but they show some X values.
Modified VHDL
For reference, here is the modified VHDL that resolves the problem of U's and X's in the simulation output. However, there is a functional problem with the PCM_DIN output... seems like it is delayed one (BCLK) cycle. I expected it to be '1' as soon as ADAT_WDCLK goes high the first time after ENABLE. But it does not go to '1' until a BLCK cycle later.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TestHarness1 is
port (
ADAT_WDCLK : in std_logic;
ADAT_BCLK: in std_logic;
ADAT_OUT12: in std_logic;
ENABLE: in std_logic;
PCM_FS : out std_logic;
PCM_CLK : out std_logic;
PCM_DIN : out std_logic
);
end TestHarness1;
architecture Behavioral of TestHarness1 is
--type state is (STOPPED, RUNNING);
signal tmp : std_logic;
signal myState : std_logic;
begin
PCM_DIN <= tmp;
-- State management process
process (ENABLE, ADAT_WDCLK) begin -- Eval on input changes
if (ENABLE = '0') then
myState <= '0'; --STOPPED;
else
if (myState = '0' and rising_edge(ADAT_WDCLK)) then
-- Move to running state only at start of a frame
myState <= '1'; --RUNNING;
end if;
end if;
end process;
-- Output process
process (ADAT_WDCLK, ADAT_BCLK, myState) variable counter: integer := 0; begin
-- Only do something if we are in running state
if (myState = '0') then
PCM_FS <= '0'; -- All outputs muted
PCM_CLK <= '0';
tmp <= '0';
elsif (myState = '1') then
-- Pass the clocks through, inverting the bit clock
PCM_FS <= ADAT_WDCLK;
PCM_CLK <= not ADAT_BCLK;
if rising_edge(ADAT_BCLK) then -- Generate fixed serial bit pattern
if counter = 0 or counter = 1 or counter = 5 or counter = 7 then
tmp <= '1';
else
tmp <= '0';
end if;
if (counter = 7) then
counter := 0; -- Reset counter
else
counter := counter + 1; -- Just inc counter
end if;
end if;
end if;
end process;
end Behavioral;
ISim of the above (including the internal myState signal)... why is PCM_DIN delayed one BCLK cycle?
Regarding the 'X' (Forcing Unknown) values you are seeing:
You are driving the signals PCM_FS, PCM_CLK and tmp from multiple processes, which results in the simulator being unable to resolve the value being driven. You need to fix this such that they are only being driven from one process, or drive 'Z' when they are not in use.
Regarding the 'U' values, they exist because you have no initial values for the signals. Once you write the signals for the first time (after the enable), they will be assigned for the first time.
I am a beginner in VHDL coding and I have some problem with my simple state machine. I just want this machine to change the output value loc_RL when the state changes. When I am simulating, there is no value (like 'U') for loc_RL.
Here is my code:
library ieee;
use ieee.std_logic_1164.all;
entity RL is
port (clk, reset, pon_RL, rtl_RL, ACDS_RL, LADS_RL, REN_RL, LLO_RL, MLA_RL, GTL_RL : in std_logic;
loc_RL : out std_logic);
end RL;
architecture behavioral of RL is
type STATE_TYPE is (LOCS, REMS, LWLS, RWLS);
signal state : STATE_TYPE;
begin
process(clk, reset)
begin
if reset='1' then
state <= LOCS;
elsif (rising_edge(clk)) then
case state is
when LOCS =>
if pon_RL = '1' then
state <= REMS;
else
state <= LOCS;
end if;
when REMS =>
if pon_RL = '1' then
state <= LWLS;
else
state <= REMS;
end if;
when LWLS =>
if pon_RL = '1' then
state <= RWLS;
else
state <= LWLS;
end if;
when RWLS =>
if pon_RL = '1' then
state <= LOCS;
else
state <= RWLS;
end if;
end case;
end if;
end process;
process(state)
begin
case state is
when LOCS =>
loc_RL <= '1';
when REMS =>
loc_RL <= '0';
when LWLS =>
loc_RL <= '1';
when RWLS =>
loc_RL <= '0';
end case;
end process;
end behavioral;
testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity RL_tb is
end RL_tb;
architecture testbench of RL_tb is
component RL
port (clk, reset, pon_RL, rtl_RL, ACDS_RL, LADS_RL, REN_RL, LLO_RL, MLA_RL, GTL_RL : in std_logic;
loc_RL : out std_logic);
end component;
--wejscia
signal tclk : std_logic;
signal treset: std_logic;
signal tpon_RL : std_logic;
signal trtl_RL : std_logic;
signal tACDS_RL : std_logic;
signal tLADS_RL : std_logic;
signal tREN_RL : std_logic;
signal tLLO_RL : std_logic;
signal tMLA_RL : std_logic;
signal tGTL_RL : std_logic;
--wyjscia
signal loc_RL : std_logic;
--definicja zegara
constant clk_period : time := 40 ns;
begin
--inicjalizacja UUT
uut: RL port map (
tclk,
treset,
tpon_RL,
trtl_RL,
tACDS_RL,
tLADS_RL,
tREN_RL,
tLLO_RL,
tMLA_RL,
tGTL_RL
);
process
begin
tclk <= '0';
wait for clk_period/2;
tclk <= '1';
wait for clk_period/2;
end process;
process
begin
treset <= '1';
wait for 10 ns;
treset <= '0';
tpon_RL <= '1';
end process;
end;
It is compiling correctly, I can proceed to the simulation. I am using NCLaunch from Cadence. Thanks in advance for help.
Analyzing, elaborating and simulating your design and testbench gives:
And looking at the testbench shows:
architecture testbench of RL_tb is
component RL
port (
clk,
reset,
pon_RL,
rtl_RL,
ACDS_RL,
LADS_RL,
REN_RL,
LLO_RL,
MLA_RL,
GTL_RL: in std_logic;
loc_RL: out std_logic
);
end component;
--wejscia
signal tclk: std_logic;
signal treset: std_logic;
signal tpon_RL: std_logic;
signal trtl_RL: std_logic;
signal tACDS_RL: std_logic;
signal tLADS_RL: std_logic;
signal tREN_RL: std_logic;
signal tLLO_RL: std_logic;
signal tMLA_RL: std_logic;
signal tGTL_RL: std_logic;
--wyjscia
signal loc_RL: std_logic;
--definicja zegara
constant clk_period: time := 40 ns;
begin
--inicjalizacja UUT
uut:
RL
port map (
tclk,
treset,
tpon_RL,
trtl_RL,
tACDS_RL,
tLADS_RL,
tREN_RL,
tLLO_RL,
tMLA_RL,
tGTL_RL
);
process
begin
tclk <= '0';
wait for clk_period/2;
tclk <= '1';
wait for clk_period/2;
end process;
process
begin
treset <= '1';
wait for 10 ns;
treset <= '0';
tpon_RL <= '1';
end process;
end architecture;
No where is there an assignment to or initial value assigned to an input to the device under test other than clk, reset and tpon_RL.
Looking in the RL process we find that actual state branching out of LOCS depends on reset not being '1':
process (clk, reset)
begin
if reset = '1' then
state <= LOCS;
elsif (rising_edge(clk)) then
case state is
when LOCS =>
if pon_RL = '1' then
state <= REMS;
else
state <= LOCS;
end if;
when REMS =>
What's missing in your testbench stimulus is a release of the reset.
In the unlabeled process:
process
begin
treset <= '1';
wait for 10 ns;
treset <= '0';
tpon_RL <= '1';
end process;
You're missing a final wait statement:
process
begin
treset <= '1';
wait for 10 ns;
treset <= '0';
tpon_RL <= '1';
wait; -- added
end process;
Which prevents you from immediately assigning reset to a '1' again. Without suspension a process will loop, it's only suspending at the one wait statement, after setting reset to a '0' it's immediately setting it to a '1' before the process suspends, reset will only have a '1' value. No signal is updated while any process is active, there's only one projected output waveform value for any time, including the current simulation time. The assignment to a '1' overwrites the assignment to a '0'.
Fixing that gives:
And now we see the state machine is active.
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;