I am trying to implement a 1hz clock for a D flipflop in VHDL.
Below is my code:
entity d_flip_flop is
Port ( clk : in STD_LOGIC;
D : in STD_LOGIC;
Q : out STD_LOGIC);
end d_flip_flop;
architecture Behavioral of d_flip_flop is
signal clk_div: std_logic; --divided clock
begin
--process to divide clock
clk_divider: process(clk) --clk is the clock port
variable clk_count: std_logic_vector(25 downto 0) := (others => '0');
begin
if clk'event and clk = '1' then
clk_count <= clk_count+1;
clk_div <= clk_count(25);
end if;
end process;
--main process
main:process(clk_div)
begin
if clk'event and clk = '1' then
Q <= D;
end if;
end process;
end Behavioral;
But when I tried to compile it, the following error is reported:
ERROR:HDLParsers:808 - "F:/EE4218/XQ/d_flip_flop.vhd" Line 47. + can
not have such operands in this context.
I have checked with several reference for the syntax and found nothing wrong with it. Can anyone point out the cause of the error ?
Thanks in advance!
clk_count is being used to represent a number, not a bag of bits.
So use the type system instead of fighting it, and declare it as a number or at least some numeric type.
The best tool for this purpose, since you need to extract a bit from it, is numeric_std.unsigned.
So add use ieee.numeric_std.all;after the library ieee; clause, declare it as
variable clk_count: unsigned(25 downto 0) := (others => '0');
and you are done.
Brian has the best answer, for powers-of-two anyway. Arguably, for other wrap around values, you should also use an integer for clock_count and wrap it:
signal clk_div : std_logic := '0';
clk_divider: process(clk) --clk is the clock port
subtype t_clk_count: integer range 0 to 12345678; -- for example
variable clk_count: t_clk_count := 0;
begin
if clk'event and clk = '1' then
if clk_count+1 >= t_clk_count'high then
clk_div <= not clk_div;
clk_count <= 0;
else
clk_count <= clk_count+1;
end if;
end if;
end process;
In process clk_divider modify the following line:
clk_count <= clk_count +1;
to
clk_count := std_logic_vector(UNSIGNED(clk_count) + 1);
This is because clk_count is defined as a variable of type 'std_logic_vector'.
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 am unfortunately new to VHDL but not new to software development. What is the equivalency to functions in VHDL? Specifically, in the code below I need to debounce four push buttons instead of one. Obviously repeating my process code four times and suffixing each of my signals with a number to make them unique for the four instances is not the professional nor correct way of doing this. How do I collapse all this down into one process "function" to which I can "pass" the signals so I can excise all this duplicate code?
----------------------------------------------------------------------------------
-- Debounced pushbutton examples
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pushbutton is
generic(
counter_size : integer := 19 -- counter size (19 bits gives 10.5ms with 50MHz clock)
);
port(
CLK : in std_logic; -- input clock
BTN : in std_logic_vector(0 to 3); -- input buttons
AN : out std_logic_vector(0 to 3); -- 7-segment digit anodes ports
LED : out std_logic_vector(0 to 3) -- LEDs
);
end pushbutton;
architecture pb of pushbutton is
signal flipflops0 : std_logic_vector(1 downto 0); -- input flip flops
signal flipflops1 : std_logic_vector(1 downto 0);
signal flipflops2 : std_logic_vector(1 downto 0);
signal flipflops3 : std_logic_vector(1 downto 0);
signal counter_set0 : std_logic; -- sync reset to zero
signal counter_set1 : std_logic;
signal counter_set2 : std_logic;
signal counter_set3 : std_logic;
signal counter_out0 : std_logic_vector(counter_size downto 0) := (others => '0'); -- counter output
signal counter_out1 : std_logic_vector(counter_size downto 0) := (others => '0');
signal counter_out2 : std_logic_vector(counter_size downto 0) := (others => '0');
signal counter_out3 : std_logic_vector(counter_size downto 0) := (others => '0');
signal button0 : std_logic; -- debounce input
signal button1 : std_logic;
signal button2 : std_logic;
signal button3 : std_logic;
signal result0 : std_logic; -- debounced signal
signal result1 : std_logic;
signal result2 : std_logic;
signal result3 : std_logic;
begin
-- Make sure Mercury BaseBoard 7-Seg Display is disabled (anodes are pulled high)
AN <= (others => '1');
-- Feed buttons into debouncers
button0 <= BTN(0);
button1 <= BTN(1);
button2 <= BTN(2);
button3 <= BTN(3);
-- Start or reset the counter at the right time
counter_set0 <= flipflops0(0) xor flipflops0(1);
counter_set1 <= flipflops1(0) xor flipflops1(1);
counter_set2 <= flipflops2(0) xor flipflops2(1);
counter_set3 <= flipflops3(0) xor flipflops3(1);
-- Feed LEDs from the debounce circuitry
LED(0) <= result0;
LED(1) <= result1;
LED(2) <= result2;
LED(3) <= result3;
-- Debounce circuit 0
process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
flipflops0(0) <= button0;
flipflops0(1) <= flipflops0(0);
if (counter_set0 = '1') then -- reset counter because input is changing
counter_out0 <= (others => '0');
elsif (counter_out0(counter_size) = '0') then -- stable input time is not yet met
counter_out0 <= counter_out0 + 1;
else -- stable input time is met
result0 <= flipflops0(1);
end if;
end if;
end process;
-- Debounce circuit 1
process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
flipflops1(0) <= button1;
flipflops1(1) <= flipflops1(0);
if (counter_set1 = '1') then -- reset counter because input is changing
counter_out1 <= (others => '0');
elsif (counter_out1(counter_size) = '0') then -- stable input time is not yet met
counter_out1 <= counter_out1 + 1;
else -- stable input time is met
result1 <= flipflops1(1);
end if;
end if;
end process;
-- Debounce circuit 2
process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
flipflops2(0) <= button2;
flipflops2(1) <= flipflops2(0);
if (counter_set2 = '1') then -- reset counter because input is changing
counter_out2 <= (others => '0');
elsif (counter_out2(counter_size) = '0') then -- stable input time is not yet met
counter_out2 <= counter_out2 + 1;
else -- stable input time is met
result2 <= flipflops2(1);
end if;
end if;
end process;
-- Debounce circuit 3
process (CLK)
begin
if (CLK'EVENT and CLK = '1') then
flipflops3(0) <= button3;
flipflops3(1) <= flipflops3(0);
if (counter_set3 = '1') then -- reset counter because input is changing
counter_out3 <= (others => '0');
elsif (counter_out3(counter_size) = '0') then -- stable input time is not yet met
counter_out3 <= counter_out3 + 1;
else -- stable input time is met
result3 <= flipflops3(1);
end if;
end if;
end process;
end pb;
VHDL has functions but function calls are expressions and not statements or expression statements as in some programming languages. A function call always returns a value of a type and an expression can't represent a portion of a design hierarchy.
Consider the other subprogram class procedures which are statements instead.
The debouncer processes and associated declarations can also be simplified without using a procedure:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity pushbutton is
generic (
counter_size: integer := 19 -- The left bound of debounce counters
);
port (
clk: in std_logic;
btn: in std_logic_vector(0 to 3);
an: out std_logic_vector(0 to 3);
led: out std_logic_vector(0 to 3)
);
end entity pushbutton;
architecture pb1 of pushbutton is
-- There are two flip flops for each of four buttons:
subtype buttons is std_logic_vector(0 to 3);
type flip_flops is array (0 to 1) of buttons;
signal flipflops: flip_flops;
signal counter_set: std_logic_vector(0 to 3);
use ieee.numeric_std.all;
type counter is array (0 to 3) of
unsigned(counter_size downto 0);
signal counter_out: counter := (others => (others => '0'));
begin
an <= (others => '1');
counter_set <= flipflops(0) xor flipflops(1);
DEBOUNCE:
process (clk)
begin
if rising_edge (clk) then
flipflops(0) <= btn;
flipflops(1) <= flipflops(0);
for i in 0 to 3 loop
if counter_set(i) = '1' then
counter_out(i) <= (others => '0');
elsif counter_out(i)(counter_size) = '0' then
counter_out(i) <= counter_out(i) + 1;
else
led(i) <= flipflops(1)(i);
end if;
end loop;
end if;
end process;
end architecture pb1;
Moving part of the design specification into a procedure:
architecture pb2 of pushbutton is
-- There are two flip flops for each of four buttons:
subtype buttons is std_logic_vector(0 to 3);
type flip_flops is array (0 to 1) of buttons;
signal flipflops: flip_flops;
signal counter_set: std_logic_vector(0 to 3);
use ieee.numeric_std.all;
type counter is array (0 to 3) of
unsigned(counter_size downto 0);
signal counter_out: counter := (others => (others => '0'));
procedure debounce (
-- Can eliminate formals of mode IN within the scope of their declaration:
-- signal counter_set: in std_logic_vector (0 to 3);
-- signal flipflops: in flip_flops;
signal counter_out: inout counter;
signal led: out std_logic_vector(0 to 3)
) is
begin
for i in 0 to 3 loop
if counter_set(i) = '1' then
counter_out(i) <= (others => '0');
elsif counter_out(i)(counter_size) = '0' then
counter_out(i) <= counter_out(i) + 1;
else
led(i) <= flipflops(1)(i);
end if;
end loop;
end procedure;
begin
an <= (others => '1');
counter_set <= flipflops(0) xor flipflops(1);
DEBOUNCER:
process (clk)
begin
if rising_edge (clk) then
flipflops(0) <= btn;
flipflops(1) <= flipflops(0);
-- debounce(counter_set, flipflops, counter_out, led);
debounce (counter_out, led);
end if;
end process;
end architecture pb2;
Here the procedure serves as a collection of sequential statements and doesn't save any lines of code.
Sequential procedure calls can be useful to hide repetitious clutter. The clutter has been removed already by consolidating declarations and using the loop statement. There's a balancing act between the design entry effort, code maintenance effort and user readability, which can also be affected by coding style. Coding style is also affected by RTL constructs implying hardware.
Moving the clock evaluation into a procedure would require the procedure call be be a concurrent statement, similar to an instantiation, which you already have. It doesn't seem worthwhile here should you consolidate signals declared as block declarative items in the architecture body or when using a loop statement.
Note that result and button declarations have been eliminated. Also the use of package numeric_std and type unsigned for the counters prevents inadvertent assignment to other objects with the same subtype. The counter values are treated as unsigned numbers while counter_set for instance is not.
Also there's an independent counter for each input being debounced just as in the original. Without independent counters some events might be lost for independent inputs when a single counter is repetitively cleared.
This code hasn't been validated by simulation, lacking a testbench. With the entity both architectures analyze and elaborate.
There doesn't appear to be anything here other than sequential statements now found in a for loop that would benefit from a function call. Because a function call returns a value the type of that value would either need to be a composite (here a record type) or be split into separate function calls for each assignment target.
There's also the generate statement which can elaborate zero or more copies of declarations and concurrent statements (here a process) as block statements with block declarative items. Any signal used only in an elaborated block can be a block declarative item.
architecture pb3 of pushbutton is
begin
DEBOUNCERS:
for i in btn'range generate
signal flipflops: std_logic_vector (0 to 1);
signal counter_set: std_logic;
signal counter_out: unsigned (counter_size downto 0) :=
(others => '0');
begin
counter_set <= flipflops(0) xor flipflops(1);
DEBOUNCE:
process (clk)
begin
if rising_edge (clk) then
flipflops(0) <= btn(i);
flipflops(1) <= flipflops(0);
if counter_set = '1' then
counter_out <= (others => '0');
elsif counter_out(counter_size) = '0' then
counter_out <= counter_out + 1;
else
led(i) <= flipflops(1);
end if;
end if;
end process;
end generate;
end architecture pb3;
Addendum
The OP pointed out an error made in the above code due to a lack of simulation and complexity hidden by abstraction when synthesizing architecture pb2. While the time for the debounce counter was given at 10.5 ms (50 MHz clock) the name of the generic (counter_size) is also actually the left bound of the counter (given as an unsigned binary counter using type unsigned).
The mistake (two flip flops in the synchronizer for each of four buttons) and simply acceding to the OP's naming convention with respect to the counter has been corrected in the above code.
The OP's synthesis error in the comment relates to the requirement there be a matching element for each element on the left hand or right hand of an aassignment statement.
Without synthesizing the code (which the OP did) the error can't be found without simulation. Because the only thing necessary to find the particular error assigning flipflops(0) is the clock a simple testbench can be written:
use ieee.std_logic_1164.all;
entity pushbutton_tb is
end entity;
architecture fum of pushbutton_tb is
signal clk: std_logic := '0';
signal btn: std_logic_vector (0 to 3);
signal an: std_logic_vector(0 to 3);
signal led: std_logic_vector(0 to 3);
begin
CLOCK:
process
begin
wait for 0.5 ms;
clk <= not clk;
if now > 50 ms then
wait;
end if;
end process;
DUT:
entity work.pushbutton (pb2)
generic map (
counter_size => 4 -- FOR SIMULATION
)
port map (
clk => clk,
btn => btn,
an => an,
led => led
);
STIMULUS:
process
begin
btn <= (others => '0');
wait for 20 ms;
btn(0) <= '1';
wait for 2 ms;
btn(1) <= '1';
wait for 3 ms;
btn(2) <= '1';
wait for 6 ms;
btn(3) <= '1';
wait;
end process;
end architecture;
The corrected code and a testbench to demonstrate there are no matching element errors in assignment during simulation.
Simulation was provided for both architectures with identical results.
The generic was used to reduce the size of the debounce counters using a 1 millisecond clock in the testbench (to avoid simulation time with 50 MHz clock events that don't add to the narrative).
Here's the output of the first architecture's simulation:
The caution here is that designs should be simulated. There's a class of VHDL semantic error conditions that are checked only at runtime (or in synthesis).
Added abstraction for reducing 'uniquified' code otherwise identically performing can introduce such errors.
The generate statement wouldn't have that issue using names in a design hierarchy:
The concurrent statements and declarations found in a generate statement are replicated in any generated block statements implied by the generate statement. Each block statement represents a portion of a design hierarchy.
There's been a trade off between design complexity and waveform display organization for debugging.
A design description depending on hiding repetitious detail should be simulated anyway. Here there are two references to the generate parameter i used in selected names, susceptible to the same errors as ranges should parameter substitution be overlooked.
A multiple bit debouncing circuit might look like this:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.Utilities.all;
entity Debouncer is
generic (
CLOCK_PERIOD_NS : positive := 10;
DEBOUNCE_TIME_MS : positive := 3;
BITS : positive
);
port (
Clock : in std_logic;
Input : in std_logic_vector(BITS - 1 downto 0);
Output : out std_logic_vector(BITS - 1 downto 0) := (others => '0')
);
end entity;
architecture rtl of Debouncer is
begin
genBits: for i in Input'range generate
constant DEBOUNCE_COUNTER_MAX : positive := (DEBOUNCE_TIME_MS * 1000000) / CLOCK_PERIOD_NS;
constant DEBOUNCE_COUNTER_BITS : positive := log2(DEBOUNCE_COUNTER_MAX);
signal DebounceCounter : signed(DEBOUNCE_COUNTER_BITS downto 0) := to_signed(DEBOUNCE_COUNTER_MAX - 3, DEBOUNCE_COUNTER_BITS + 1);
begin
process (Clock)
begin
if rising_edge(Clock) then
-- restart counter, whenever Input(i) was unstable within DEBOUNCE_TIME_MS
if (Input(i) /= Output(i)) then
DebounceCounter <= DebounceCounter - 1;
else
DebounceCounter <= to_signed(DEBOUNCE_COUNTER_MAX - 3, DebounceCounter'length);
end if;
-- latch input bit, if input was stable for DEBOUNCE_TIME_MS
if (DebounceCounter(DebounceCounter'high) = '1') then
Output(i) <= Input(i);
end if;
end if;
end process;
end generate;
end architecture;
In stead of a counter size, it expects the user to provide a frequency (as period in nanoseconds) and a debounce time (in milliseconds).
The referenced package implements a log2 function.
I am starting with VHDL. My code is pretty simple, I am switching LEDs on/off with a process which takes clk rising edge and counts circles of the clock in "t" variable:
entity leds_vhdl is
Port ( clk : in STD_LOGIC;
led1 : out STD_LOGIC;
led2: out STD_LOGIC;
change : in STD_LOGIC);
end leds_vhdl;
architecture Behavioral of leds_vhdl is
constant t1s : integer := 50000000;
begin
process (clk)
variable t : integer := 0;
begin
if (rising_edge(clk)) then
t := t + 1;
if (t > 5*t1s) then
t := 0;
if (t <= 3*t1s) then
led1 <= '0';
led2 <= '0';
elsif (t > 3*t1s and t <= 5*t1s) then
led1 <= '1';
led2 <= '1';
end if;
end if;
end process;
end Behavioral;
Now, I want to modify the LEDs when different states of the input "change". For example, if "change" is '1', how could I make change the LEDs? (led1 = '1', led2 = '0' for example). ¿It would be possible to do in the same process, or better do another one?.
I´ve been trying but I´ve been having so many problems in synthetizing phase.
Thank you very much.
I want to implement a random-number game on BASYS2. In this game there would be five LEDs chosen out of which one would turn on at random for a second or two (this time can be changed to increase or decrease the difficulty level of the game). Then the user is required to respond to this LED event by pressing the switch button behind it within the time that it is on. If he or she is able to do so successfully a point would be scored and it would be showed on the Seven Segment Display. If he or she fails no point would be scored. There would be 9 such events after which the game can be replayed.
Now following is my code (only for the random LED turning on). However, I am unable to fix it. Please somebody help. The FPGA I am using is BASYS2 SPARTAN 3E-100.
Thanks in advance to everyone.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity random_number is
generic ( width : integer := 4 );
port (
clk : in std_logic;
reset : in std_logic;
random_num : out std_logic_vector (width-1 downto 0) --output vector
);
end random_number;
architecture Behavioral of random_number is
signal q: std_logic_vector(23 downto 0);
signal divided_clock: std_logic;
begin
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
end process;
divided_clock <= q(22);
process (divided_clock)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(divided_clock)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
random_num <= rand_temp;
end process;
end Behavioral;
I think the second process should even run with the main clk and the devided clock should be an enable.
signal divided_enable: std_logic;
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
if (q(22) = '1') then
--short pulse wenn q bit 22 is high
divided_enable <= '1';
q <= (others => '0');
end if;
end process;
process (clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(clk)) then
if(divided_enable = '1') then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
end if;
random_num <= rand_temp;
end process;
I don't know if this will fix all your problems. Please discribe compiler errors or errors in the behavior.
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;