How can I add a maximum value to my bidirectional 4bit counter (loop)? - vhdl

I have this code which is a bidirectional counter that loops around.
I now want to add an input (maybe from switches or something), which controls the maximum value of the counter, for example if the max value from the input is "0111" the counter will count up to 0111 and then loop back around to 0000, and if the counter is counting down to 0000 it will loop back to 0111. I'm getting a bit confused on how/where I should do this because I've used nested ifs to implement an enable and reset input.
Here is the code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity UPDOWN_COUNTER is
Port ( clk: in std_logic; -- clock input
reset: in std_logic; -- reset input
up_down: in std_logic; -- up or down
enable: in std_logic; -- enable
max: in std_logic_vector(3 downto 0); -- max value counter
counter: out std_logic_vector(3 downto 0) -- output 4-bit counter
);
end UPDOWN_COUNTER;
architecture Behavioral of UPDOWN_COUNTER is
signal counter_updown: std_logic_vector(3 downto 0);
begin
process(clk,reset,enable,max)
begin
if(enable ='1') then
if(rising_edge(clk)) then
if(reset='1') then
counter_updown <= x"0";
elsif(up_down='1') then
counter_updown <= counter_updown - x"1"; -- count down
else
counter_updown <= counter_updown + x"1"; -- count up
end if;
end if;
end if;
end process;
counter <= counter_updown;
end Behavioral;
Here is the test bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity tb_counters is
end tb_counters;
architecture Behavioral of tb_counters is
component UPDOWN_COUNTER
Port ( clk: in std_logic; -- clock input
reset: in std_logic; -- reset input
up_down: in std_logic; -- up or down input
enable: in std_logic; -- enable input
max: in std_logic_vector(3 downto 0); -- max value counter
counter: out std_logic_vector(3 downto 0) -- output 4-bit counter
);
end component;
signal reset,clk,enable,up_down: std_logic;
signal max,counter:std_logic_vector(3 downto 0);
begin
dut: UPDOWN_COUNTER port map (clk => clk, reset=>reset,enable => enable, up_down => up_down, max => max,counter => counter);
-- Clock
clock_process :process
begin
clk <= '0';
wait for 10 ns;
clk <= '1';
wait for 10 ns;
end process;
stim_proc: process
begin
max <= "1000"; -- Test value for Counter max value
enable <= '1';
reset <= '1';
up_down <= '0';
wait for 20 ns;
reset <= '0';
wait for 300 ns;
up_down <= '1';
--
wait for 50 ns;
enable <= '0';
wait for 50 ns;
enable <= '1';
wait;
end process;
end Behavioral;

You've specified a synchronous reset. There's at least one synthesis issue, where enable is inferred to gate the clock. The numeric package has been switched to ieee.numeric_std in the following (the example can be modified for the non-standard Synopsys numeric package):
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity updown_counter is
port (
clk: in std_logic;
reset: in std_logic;
up_down: in std_logic;
enable: in std_logic;
max: in std_logic_vector(3 downto 0);
counter: out std_logic_vector(3 downto 0)
);
end entity updown_counter;
architecture behavioral of updown_counter is
signal counter_updown: unsigned(3 downto 0);
begin
process (clk) -- other signals evaluated inside clock edge
begin
if rising_edge(clk) then
if enable = '1' then -- don't gate the clock
if reset = '1' then
counter_updown <= (others => '0');
elsif up_down = '1' then -- down
if counter_updown = 0 then
counter_updown <= unsigned(max);
else
counter_updown <= counter_updown - 1;
end if;
else -- count up
if counter_updown = unsigned(max) then
counter_updown <= (others => '0');
else
counter_updown <= counter_updown + 1;
end if;
end if;
end if;
end if;
end process;
counter <= std_logic_vector(counter_updown);
end architecture behavioral;
And that gives:
with your testbench.

This is the similar to #user1155120's answer (which I recommend you accept as the answer), but I've used an asynchronous reset instead. Also added a generic to specify the number bits in the counter.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity UpdownCounter is
generic
(
COUNTER_BITS: natural := 4
);
port
(
clk: in std_logic; -- clock input
reset: in std_logic; -- reset input
up_down: in std_logic; -- up or down input
enable: in std_logic; -- enable input
max: in std_logic_vector(COUNTER_BITS - 1 downto 0); -- max value counter
counter: out std_logic_vector(COUNTER_BITS - 1 downto 0) -- output N-bit counter
);
end UpdownCounter;
architecture V1 of UpdownCounter is
signal counter_updown: unsigned(COUNTER_BITS - 1 downto 0);
begin
process(clk, reset)
begin
if reset then
-- Do asynchronous reset.
counter_updown <= (others => '0');
elsif rising_edge(clk) then
-- Do synchronous stuff.
if enable then
if up_down then
-- Count down to zero cyclically.
if counter_updown = 0 then
counter_updown <= unsigned(max);
else
counter_updown <= counter_updown - 1;
end if;
else
-- Count up to max cyclically.
if counter_updown = unsigned(max) then
counter_updown <= (others => '0');
else
counter_updown <= counter_updown + 1;
end if;
end if;
end if;
end if;
end process;
counter <= std_logic_vector(counter_updown);
end V1;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity UpdownCounter_TB is
end UpdownCounter_TB;
architecture V1 of UpdownCounter_TB is
component UpdownCounter
generic
(
COUNTER_BITS: natural := 4
);
port
(
clk: in std_logic; -- clock input
reset: in std_logic; -- reset input
up_down: in std_logic; -- up or down input
enable: in std_logic; -- enable input
max: in std_logic_vector(COUNTER_BITS - 1 downto 0); -- max value counter
counter: out std_logic_vector(COUNTER_BITS - 1 downto 0) -- output 4-bit counter
);
end component;
signal reset, clk, enable, up_down: std_logic;
signal max, counter: std_logic_vector(3 downto 0);
signal halt_clk: boolean := false;
begin
DUT: UpdownCounter
generic map
(
COUNTER_BITS => 4
)
port map
(
clk => clk,
reset => reset,
enable => enable,
up_down => up_down,
max => max,
counter => counter
);
-- Clock
ClockProocess :process
begin
while not halt_clk loop
clk <= '0';
wait for 10 ns;
clk <= '1';
wait for 10 ns;
end loop;
wait;
end process;
StimulusProcess: process
begin
max <= "1000"; -- Test value for Counter max value
enable <= '1';
reset <= '1';
up_down <= '0';
wait for 20 ns;
reset <= '0';
wait for 300 ns;
up_down <= '1';
--
wait for 50 ns;
enable <= '0';
wait for 50 ns;
enable <= '1';
wait for 1000 ns;
halt_clk <= true;
wait;
end process;
end V1;

Related

VHDL: Button debouncing (or not, as the case may be)

I've read through the other posts but can't seem to fix mine. I'm new to VHDL so I'm sure it's a simple fix.
In short, the button isn't debouncing. The code compiles and the bitstream programs. In the testbench, button presses work, but the output LEDs don't change. On the board, pressing a button makes random LEDs light up (I presume because of bouncing). According to the schematic the inputs are going through the debouncers.
Can anyone identify the issue? And any other hints and tips are always appreciated :)
Thanks!
EDIT1: Added rising_edge(clk).
Also note, when I press either button, at the time it's depressed all the LEDs light up.
button_counter.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity button_counter is
port( clk : in std_logic;
btnU : in std_logic;
btnD : in std_logic;
led : out std_logic_vector (15 downto 0));
end button_counter;
architecture behavioral of button_counter is
component debouncer is
port( clk : in std_logic;
btn : in std_logic;
btn_clr : out std_logic);
end component;
signal btnU_clr : std_logic;
signal btnD_clr : std_logic;
begin
debouncer_btnU : debouncer port map (clk => clk, btn => btnU, btn_clr => btnU_clr);
debouncer_btnD : debouncer port map (clk => clk, btn => btnD, btn_clr => btnD_clr);
process(clk)
variable count : integer := 0;
begin
if (rising_edge(clk)) then
if(btnU_clr = '1') then count := count + 1;
elsif(btnD_clr = '1') then count := count - 1;
end if;
led <= std_logic_vector(to_unsigned(count, led'length));
end if;
end process;
end behavioral;
Debouncer.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity debouncer is
port( clk : in std_logic;
btn : in std_logic;
btn_clr : out std_logic);
end debouncer;
architecture behavioural of debouncer is
constant delay : integer := 650000; -- 6.5ms
signal count : integer := 0;
signal btn_tmp : std_logic := '0';
begin
process(clk)
begin
if rising_edge(clk) then
if (btn /= btn_tmp) then
btn_tmp <= btn;
count <= 0;
elsif (count = delay) then
btn_clr <= btn_tmp;
else
count <= count + 1;
end if;
end if;
end process;
end behavioural;
button_counter_tb.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity button_counter_tb is
end button_counter_tb;
architecture behavioral of button_counter_tb is
signal clk_tb : std_logic;
signal btnU_tb : std_logic;
signal btnD_tb : std_logic;
signal led_tb : std_logic_vector (15 downto 0);
component button_counter
port(clk : in std_logic;
btnU : in std_logic;
btnD : in std_logic;
led : out std_logic_vector (15 downto 0));
end component;
begin
UUT: button_counter port map (clk => clk_tb, btnU => btnU_tb, btnD => btnD_tb, led => led_tb);
process
begin
btnU_tb <= '0';
btnD_tb <= '0';
wait for 100ns;
btnU_tb <= '1';
wait for 100ns;
btnU_tb <= '0';
wait for 100ns;
btnU_tb <= '1';
wait for 100ns;
btnD_tb <= '1';
wait for 100ns;
btnU_tb <= '0';
wait for 100ns;
btnD_tb <= '0';
end process;
end behavioral;
After your code update there are several issues remaining:
The clock isn't being generated in the testbench
The stimuli (button presses) aren't adequately timed in the testbench
The debouncer doesn't produce an enable for a single clock
To facilitate simulation for design validation your design has been modified to allow a slower clock (it appears you're actually using a 100 MHz clock). The idea is to reduce the computation requirements and display waveform storage.
The first two points are addressed in the testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity button_counter_tb is
end entity button_counter_tb;
architecture behavioral of button_counter_tb is
-- NOTE: suffix _tb has been removed, it's annoying to type over and over
signal clk: std_logic := '0'; -- ADDED default value '0'
signal btnU: std_logic;
signal btnD: std_logic;
signal led: std_logic_vector (15 downto 0);
component button_counter
generic ( -- ADDED generic
CLKP: time := 10 ns;
DEBT: time := 6.5 ms -- debounce time supports different
); -- mechanical buttons/switches
port (
clk: in std_logic;
btnU: in std_logic;
btnD: in std_logic;
led: out std_logic_vector (15 downto 0)
);
end component;
constant CLKP: time := 12.5 us; -- ADDED just long enough to show debounce
constant DEBT: time := 6.5 ms; -- ADDED
begin
CLOCK: -- ADDED clock process
process
begin
wait for CLKP/2;
clk <= not clk;
if now > 2 sec then -- stop simulation
wait;
end if;
end process;
UUT:
button_counter
generic map ( -- ADDED generic map
CLKP => CLKP,
DEBT => DEBT
)
port map (
clk => clk,
btnU => btnU,
btnD => btnD,
led => led
);
-- STIMULI:
-- process
-- begin
-- btnU_tb <= '0';
-- btnD_tb <= '0';
-- wait for 100 ns;
-- btnU_tb <= '1';
-- wait for 100 ns;
-- btnU_tb <= '0';
-- wait for 100 ns;
-- btnU_tb <= '1';
-- wait for 100 ns;
-- btnD_tb <= '1';
-- wait for 100 ns;
-- btnU_tb <= '0';
-- wait for 100 ns;
-- btnD_tb <= '0';
-- wait; -- ADDED -- stops simulation
-- end process;
UP_BUTTON:
process
begin
btnU <= '0';
wait for 2 ms;
btnU <= '1'; -- first button press
wait for 0.5 ms;
btnU <= '0';
wait for 0.25 ms;
btnU <= '1';
wait for 7 ms;
btnU <= '0';
wait for 100 us;
btnU <= '1';
wait for 20 us;
btnU <= '0';
wait for 200 ms;
btnU <= '1'; -- second button press
wait for 20 us;
btnU <= '0';
wait for 20 us;
btnU <= '1';
wait for 6.6 ms;
btnU <= '0';
wait for 250 ms;
btnU <= '1'; -- third button press
wait for 20 us;
btnU <= '0';
wait for 20 us;
btnU <= '1';
wait for 6.6 ms;
btnU <= '0';
wait for 200 ms;
btnU <= '1'; -- second button press
wait for 20 us;
btnU <= '0';
wait for 20 us;
btnU <= '1';
wait for 6.6 ms;
btnU <= '0';
wait for 50 us;
btnU <= '1';
wait for 1 ms;
btnU <= '0';
wait;
end process;
DOWN_BUTTON:
process
begin
btnD <= '0';
wait for 800 ms;
btnD <= '1'; -- first button press
wait for 0.5 ms;
btnD <= '0';
wait for 0.25 ms;
btnD <= '1';
wait for 0.5 ms;
btnD <= '0';
wait for 1 ms;
btnD <= '1';
wait for 7 ms;
btnD <= '0';
wait for 100 us;
btnD <= '1';
wait for 20 us;
btnD <= '0';
wait for 200 ms;
btnD <= '1'; -- second button press
wait for 20 us;
btnD <= '0';
wait for 20 us;
btnD <= '1';
wait for 6.6 ms;
btnD <= '0';
wait for 250 ms;
wait;
end process;
end architecture behavioral;
The _tb suffix to signal names has been removed (it was painful to type in repetitively).
A clock period has been picked with a ratio of bounce period to clk period guaranteed to allow dropping 'bounces'. The stimului button presses can be extended as can the simulation which is arbitrary here.
Note the button press values are guaranteed to span one or more clock intervals.
These should tolerate the clock period being changed by modifying CLKP.
The debounce interval DEBT can be modified to reflect the use of different switches or buttons, including membrane switches with severe aging. The debounce interval is a consequence of mechanical characteristics of the particular switches or buttons. Passing these generic constants allows a degree of platform independence.
The third point is addressed by changes to the debouncer:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity debouncer is
generic ( -- ADDED GENERICS to speed up simulation
CLKP: time := 10 ns;
DEBT: time := 6.5 ms
);
port (
clk: in std_logic;
btn: in std_logic;
btn_clr: out std_logic
);
end entity debouncer;
architecture behavioural of debouncer is
-- constant delay: integer := 650000; -- 6.5ms
constant DELAY: integer := DEBT/CLKP;
signal count: integer := 0;
signal b_enab: std_logic := '0'; -- RENAMED, WAS btn_tmp
signal btnd0: std_logic; -- ADDED for clock domain crossing
signal btnd1: std_logic; -- DITTO
begin
CLK_DOMAIN_CROSS: -- ADDED process
process (clk)
begin
if rising_edge(clk) then
btnd0 <= btn;
btnd1 <= btnd0;
end if;
end process;
DEBOUNCE_COUNTER: -- ADDED LABEL
process (clk)
begin
if rising_edge(clk) then
-- if btn /= btn_tmp then -- REWRITTEN
-- btn_tmp <= btn;
-- count <= 0;
-- elsif count = DELAY then
-- btn_clr <= btn_tmp;
-- else
-- count <= count + 1;
-- end if;
btn_clr <= '0'; -- btn_clr for only one clock, used as enable
if btnd1 = '0' then -- test for btn inactive state
count <= 0;
elsif count < DELAY then -- while btn remains in active state
count <= count + 1;
end if;
if count = DELAY - 1 then -- why btn_clr '1' or 1 clock
btn_clr <= '1';
end if;
end if;
end process;
end architecture behavioural;
The debouncer has been modified to get a clock domain button value which is used to reset and enable the counter count. The output btn_clr name has been left intact and is true for only one clock and can be used as an enable.
CLKP and DEBT are used together to allow faster simulation execution while passing the same simulation time.
Note the active state of the button input is hard coded. These would be connected to device pins where the input polarity can be specified.
Modifications to button_counter pass generic constants CLKP and DEBT to the debouncers:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity button_counter is
generic (
CLKP: time := 10 ns; -- GENERIC CONSTANTS for faster simulation
DEBT: time := 6.5 ms -- supports diffeent switches/buttons
);
port (
clk: in std_logic;
btnU: in std_logic;
btnD: in std_logic;
led: out std_logic_vector (15 downto 0)
);
end entity button_counter;
architecture behavioral of button_counter is
component debouncer is
generic (
CLKP: time := 10 ns;
DEBT: time := 6.5 ms
);
port (
clk: in std_logic;
btn: in std_logic;
btn_clr: out std_logic
);
end component;
signal btnU_clr: std_logic;
signal btnD_clr: std_logic;
begin
debouncer_btnU:
debouncer
generic map (
CLKP => CLKP,
DEBT => DEBT
)
port map (
clk => clk,
btn => btnU,
btn_clr => btnU_clr
);
debouncer_btnD:
debouncer
generic map (
CLKP => CLKP,
DEBT => DEBT
)
port map (
clk => clk,
btn => btnD,
btn_clr => btnD_clr
);
process (clk)
variable count: integer := 0;
begin
if rising_edge(clk) then
if btnU_clr = '1' then
count := count + 1;
elsif btnD_clr = '1'then
count := count - 1;
end if;
led <= std_logic_vector(to_unsigned(count, led'length));
end if;
end process;
end architecture behavioral;
And when simulated we now see the LEDs count up and down:
Running the testbench and displaying the various waveforms would allow 'zooming in' to display glitch handling in the two debouncers.
The modifications to pass the clock period and debounce interval through the design hierarchy wouldn't be strictly essential. They facilitate simulation which is used as here for design validation. (The stimuli shown in the testbench don't exhaustively verify the design).
By using the generic defaults (with a 100MHz clock) there's a very good chance the design will function when implemented in a target platform. (The active polarity of button inputs is selected in the debouncer to support the original implementation. if you suspect button bounces while getting increments or decrements you can increase the DEBT value.)
If a particular synthesis tool can't handle value of type time passed as generic constants you can convert the various declarations of CLKP and DEBT to type integer or simply pass the maximum count.
You forget the rising_edge in your button_counter.vhd.
process(clk)
variable count : integer := 0;
begin
if(btnU_clr = '1') then count := count + 1;
elsif(btnD_clr = '1') then count := count - 1;
end if;
led <= std_logic_vector(to_unsigned(count, led'length));
end process;
So fix this and maybe it works (I don´t test the design, because of this obvious error):
process(clk)
variable count : integer := 0;
begin
if(rising_edge(clk)) then
...
end if;
end process;
I´m not sure, but I think the toolchain will produce some warnings for this. So check it please.
And your Testbench doesn´t contain any clock generation process, so you will not have a clock signal. Maybe this will let you believe that your design works (or did you forget the clock clk_tb signal in your post?).
The question has been answered well, but I would like to highlight different techniques for synchronising and debouncing.
Synchronising
For synchronising, a simple buffer or chain can be used which avoids creating separate signals/variables for each stage in the buffer or chain. A generic constant can be used to control the length of the chain (minimum of 2):
signal sync_buffer: std_logic_vector(SYNC_BUFFER_MSB downto 0); -- N-bit synchronisation buffer.
...
sync_buffer <= sync_buffer(SYNC_BUFFER_MSB - 1 downto 0) & input;
Debouncing
For debouncing, hysteresis (a fancy word for history or memory) can be used to create a kind of low pass filter that will debounce both the press and release of a button, and detect edges (both positive and negative) irrespective of whether the signal is active high or active low. The output will stay in its current state until the synchronised input remains in the opposite state for N consecutive clock cycles:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Debounce is
generic
(
CLOCK_PERIOD : time := 20 ns;
DEBOUNCE_PERIOD: time := 125 ms; -- 1/8th second as a rule of thumb for a tactile button/switch.
SYNC_BITS : positive := 3 -- Number of bits in the synchronisation buffer (2 minimum).
);
port
(
clock : in std_logic;
input : in std_logic; -- Asynchronous and noisy input.
output: out std_logic := '0'; -- Synchronised, debounced and filtered output.
edge : out std_logic := '0'; -- Goes high for 1 clock cycle on either edge of synchronised and debounced input.
rise : out std_logic := '0'; -- Goes high for 1 clock cycle on the rising edge of synchronised and debounced input.
fall : out std_logic := '0' -- Goes high for 1 clock cycle on the falling edge of synchronised and debounced input.
);
end entity;
architecture V1 of Debounce is
constant SYNC_BUFFER_MSB: positive := SYNC_BITS - 1;
signal sync_buffer: std_logic_vector(SYNC_BUFFER_MSB downto 0) := (others => '0'); -- N-bit synchronisation buffer (2 bits minimum).
alias sync_input: std_logic is sync_buffer(SYNC_BUFFER_MSB); -- The synchronised input is the MSB of the synchronisation buffer.
constant MAX_COUNT: natural := DEBOUNCE_PERIOD / CLOCK_PERIOD;
signal counter: natural range 0 to MAX_COUNT := 0; -- Specify the range to reduce number of bits that are synthesised.
begin
assert SYNC_BITS >= 2 report "Need a minimum of 2 bits in the synchronisation buffer.";
process(clock)
variable edge_internal: std_logic := '0';
variable rise_internal: std_logic := '0';
variable fall_internal: std_logic := '0';
begin
if rising_edge(clock) then
-- Synchronise the asynchronous input.
-- MSB of sync_buffer is the synchronised input.
sync_buffer <= sync_buffer(SYNC_BUFFER_MSB - 1 downto 0) & input;
edge <= '0'; -- Goes high for 1 clock cycle on either edge.
rise <= '0'; -- Goes high for 1 clock cycle on the rising edge.
fall <= '0'; -- Goes high for 1 clock cycle on the falling edge.
if counter = MAX_COUNT - 1 then -- If successfully debounced, notify what happened, and reset the counter.
output <= sync_input;
edge <= edge_internal; -- Goes high for 1 clock cycle on either edge.
rise <= rise_internal; -- Goes high for 1 clock cycle on the rising edge.
fall <= fall_internal; -- Goes high for 1 clock cycle on the falling edge.
counter <= 0;
elsif sync_input /= output then
counter <= counter + 1;
else
counter <= 0;
end if;
end if;
-- Edge detection.
edge_internal := sync_input xor output;
rise_internal := sync_input and not output;
fall_internal := not sync_input and output;
end process;
end architecture;
Button Counter
Much the same as the other answers, but I've used the rise outputs of the debouncers to trigger the counting. I also added a couple of LEDs for visual button feedback.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ButtonCounter is
generic
(
CLOCK_PERIOD : time := 20 ns;
DEBOUNCE_PERIOD: time := 125 ms
);
port
(
clock : in std_logic;
btn_up: in std_logic;
btn_dn: in std_logic;
led_up: out std_logic;
led_dn: out std_logic;
leds : out std_logic_vector(15 downto 0)
);
end entity;
architecture V1 of ButtonCounter is
signal count_up: std_logic;
signal count_dn: std_logic;
component Debounce is
generic
(
CLOCK_PERIOD : time := 20 ns;
DEBOUNCE_PERIOD: time := 125 ms
);
port
(
clock : in std_logic;
input : in std_logic;
output: out std_logic;
rise : out std_logic
);
end component;
begin
DEBOUNCE_BTN_UP:
Debounce
generic map
(
CLOCK_PERIOD => CLOCK_PERIOD,
DEBOUNCE_PERIOD => DEBOUNCE_PERIOD
)
port map
(
clock => clock,
input => btn_up,
output => led_up,
rise => count_up -- Goes high for 1 clock cycle on the rising edge of btn_up.
);
DEBOUNCE_BTN_DN:
Debounce
generic map
(
CLOCK_PERIOD => CLOCK_PERIOD,
DEBOUNCE_PERIOD => DEBOUNCE_PERIOD
)
port map
(
clock => clock,
input => btn_dn,
output => led_dn,
rise => count_dn -- Goes high for 1 clock cycle on the rising edge of btn_dn.
);
process(clock)
variable counter: natural range 0 to 2 ** leds'length - 1 := 0; -- Specify the range to reduce number of bits that are synthesised.
begin
if rising_edge(clock) then
if count_up then
counter := counter + 1;
elsif count_dn then
counter := counter - 1;
end if;
leds <= std_logic_vector(to_unsigned(counter, leds'length));
end if;
end process;
end architecture;
Test Bench
Some asynchronous and noisy input buttons are synchronised, debounced and filtered. The positive edges of the reformed input signals trigger the counting.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity ButtonCounter_TB is
end;
architecture V1 of ButtonCounter_TB is
constant CLOCK_PERIOD : time := 50 ns;
constant DEBOUNCE_PERIOD: time := 200 ns;
signal halt_sys_clock: boolean := false;
signal clock: std_logic := '0';
signal btn_up: std_logic;
signal btn_dn: std_logic;
signal leds: std_logic_vector(15 downto 0);
component ButtonCounter is
generic
(
CLOCK_PERIOD : time := 10 ns;
DEBOUNCE_PERIOD: time := 125 ms
);
port
(
clock : in std_logic;
btn_up: in std_logic;
btn_dn: in std_logic;
leds : out std_logic_vector(15 downto 0)
);
end component;
begin
ClockGenerator:
process
begin
while not halt_sys_clock loop
clock <= not clock;
wait for CLOCK_PERIOD / 2.0;
end loop;
wait;
end process ClockGenerator;
Stimulus:
process
constant NUM_NOISE_SAMPLES: positive := 10;
constant SWITCH_TIME: time := 2 * DEBOUNCE_PERIOD;
variable seed1: positive := 1;
variable seed2: positive := 1;
variable rrand: real;
variable nrand: natural;
-- Performs noisy transition of sig from current value to final value.
procedure NoisyTransition(signal sig: out std_logic; final: std_logic) is
begin
for n in 1 to NUM_NOISE_SAMPLES loop
uniform(seed1, seed2, rrand);
nrand := natural(round(rrand));
if nrand = 0 then
sig <= not final;
else
sig <= final;
end if;
wait for CLOCK_PERIOD / 5.0;
end loop;
sig <= final;
wait for SWITCH_TIME;
end;
begin
btn_up <= '0';
btn_dn <= '0';
wait for 3 ns;
--
-- Up Button
--
-- Perform 4 noisy presses and releases.
for n in 1 to 4 loop
NoisyTransition(btn_up, '1');
NoisyTransition(btn_up, '0');
end loop;
--
-- Down Button
--
-- Perform 1 noisy press and release.
NoisyTransition(btn_dn, '1');
NoisyTransition(btn_dn, '0');
halt_sys_clock <= true;
wait;
end process;
DUT:
ButtonCounter
generic map
(
CLOCK_PERIOD => CLOCK_PERIOD,
DEBOUNCE_PERIOD => DEBOUNCE_PERIOD
)
port map
(
clock => clock,
btn_up => btn_up,
btn_dn => btn_dn,
leds => leds
);
end architecture;
Simulation

What is Simulator 45-1 Error in Xilinx Vivado?

I have been trying to make a generic sequence detector. When i try to simulate my design, I get a simulator 45-1 Fatal run time error. Can somebody please help me with this. Here is my Test bench and design.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Sequence_tb is
end Sequence_tb;
architecture Behavioral of Sequence_tb is
component sequence is
Generic(width: integer;
sequence: std_logic_vector);
Port(din,CLK,RST:in std_logic;
dout: out std_logic;
temp: buffer std_logic_vector(0 to width-1));
end component;
constant CLK_period: time := 10ns;
constant width: integer := 4;
constant sequence0: std_logic_vector(width-1 downto 0) := "1010";
signal din,CLK,RST,dout: std_logic := '0';
signal temp : std_logic_vector(0 to width-1) := (others=>'0');
begin
uut: sequence generic map(width=>width,sequence=>sequence0)
port map(din=>din,CLK=>CLK,RST=>RST,dout=>dout,temp=>temp);
CLK_proc: process
begin
CLK <= not CLK;
wait for CLK_period;
end process;
RST_proc: process
begin
RST <= '1';
wait for 20 ns;
RST <= '0';
wait;
end process;
din_proc: process
begin
din <= '1';
wait for 30 ns;
din <= '0';
wait for 10 ns;
din <= '1';
wait for 10 ns;
din <= '0';
wait for 10 ns;
din <= '1';
wait for 10 ns;
wait;
end process;
end Behavioral;
Design File:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Sequence is
Generic(width: integer;
sequence: std_logic_vector);
Port (din, CLK, rst: in std_logic;
dout: out std_logic;
temp: buffer std_logic_vector(0 to width-1));
end Sequence;
architecture Beh of Sequence is
subtype statetype is integer range 0 to width-1;
signal prstate,nxstate: statetype := 0;
begin
process(RST,CLK)
begin
if RST='1' then
temp <= (others => '0');
nxstate <= 0;
elsif CLK'event and CLK='1' then
temp(prstate) <= din;
for k in prstate downto 0 loop
if temp(k downto 0) = sequence(k downto 0) then
nxstate <= k;
exit;
else temp <= temp(1 to width-1) & '0';
end if;
end loop;
end if;
prstate <= nxstate;
end process;
dout <= '1' when prstate = width-1 and din = sequence(sequence'left) else '0';
end Beh;

Modelsim Altera VHDL MEMORY ROM

I am confused on to why my VHDL design is not working. I am to create a top.vhd file that will program an FPGA board to display addresses 0 through 15 and the corresponding values to each address. When I simulate my design, all the clocks and resets work. The problem I am having is my FSM processes and Address process. I know there is a lot going on here, so if you need clarification I can answer your questions.
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.all;
entity top is
port(Clock : in std_logic;
Reset : in std_logic;
SW : in std_logic_vector (1 downto 0);
HEX2, HEX4: out std_logic_vector ( 6 downto 0);
KEY0: in std_logic);
end entity;
architecture top_arch of top is
component char_decoder is
port(BIN_IN : in std_logic_vector (3 downto 0);
HEX_OUT : out std_logic_vector (6 downto 0));
end component;
component rom_16x4_sync is
port (clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0));
end component;
type state_type is (start, read_rom, clear_addr, done);
signal current_state, next_state : state_type;
signal Rom_en, addr_count_clr, addr_count_en : std_logic;
signal address_counter : integer range 0 to 15;
signal address_uns : unsigned (3 downto 0);
signal clock_slow : std_logic;
signal rom_out : std_logic_vector (3 downto 0);
begin
char : char_decoder port map (BIN_IN => rom_out, HEX_OUT => HEX2);
char1 : char_decoder port map (BIN_IN => std_logic_vector(address_uns), HEX_OUT => HEX4);
clock_slow <= Clock;
rom : rom_16x4_sync port map (clock => clock_slow, address => std_logic_vector(address_uns), rom_en => Rom_en, data_out => rom_out);
State_Memory : process (clock_slow, Reset)
begin
if (Reset = '0') then
current_state <= start;
elsif (clock_slow'event and clock_slow = '1') then
current_state <= next_state;
end if;
end process;
NEXT_STATE_LOGIC : process (current_state)
begin
case (current_state) is
when start => if (KEY0 = '0') then
next_state <= read_rom;
else next_state <= start;
end if;
when read_rom => if (address_counter = 15) then
next_state <= clear_addr;
else
address_counter <= address_counter + 1;
end if;
when clear_addr => next_state <= done;
address_counter <= 0;
when done => next_state <= done;
end case;
end process;
OUTPUT_LOGIC : process (current_state)
begin
case (current_state) is
when start => Rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
when read_rom => Rom_en <= '1';
addr_count_en <= '1';
addr_count_clr <= '0';
when clear_addr => Rom_en <= '0';
addr_count_en <= '1';
addr_count_clr <= '1';
when done => Rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
end case;
end process;
Address_Count : process (addr_count_en, addr_count_clr, clock_slow)
begin
if (clock_slow'event and clock_slow = '1') then
if (addr_count_en = '1') then
if (addr_count_clr = '1') then
address_uns <= "0000";
else
address_uns <= address_uns + 1;
end if;
end if;
end if;
end process;
address_uns <= to_unsigned(address_counter,4);
end architecture;
I commented on what I could see wrong with your code:
address_counter isn't clocked and is redundant. Remove the assignments and change the comparison to address_uns (which should also go into the sensitivity list) in process NEXT_STATE_LOGIC. Remove the concurrent signal assignment to address_uns following process Address_Counter. If processes Address_Count and OUTPUT_LOGIC are correct as well as rom_16x4_sync you should have something that works.
Well I had most the bits and pieces sitting around from other questions to gen a complete MCVE together with little effort mostly by copying and pasting and that gave:
As you can see that didn't work, and the reason why is that address_uns needs to be reset (it's default value is all 'U's).
Adding a reset gives:
So the gist of this is that your state machine was almost correct, it was missing the address counter in it's sensitivity list and had two address counters. Limiting that to one and resetting it so you weren't adding 1 to all 'U's shows your state machine is working.
And the code with all the fixes:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity char_decoder is
port (
bin_in: in std_logic_vector (3 downto 0);
hex_out: out std_logic_vector (6 downto 0)
);
end entity;
architecture dummy of char_decoder is
-- seven segment display
--
-- a
-- f b
-- g
-- e c
-- d
--
-- SEGMENT is defined (g downto a)
--
type segment7 is array (integer range 0 to 15) of
std_logic_vector (6 downto 0);
constant hex_to_segment: segment7 := (
"1000000", -- 0
"1111001", -- 1
"0100100", -- 2
"0110000", -- 3
"0011001", -- 4
"0010010", -- 5
"0000010", -- 6
"1111000", -- 7
"0000000", -- 8
"0011000", -- 9
"0001000", -- A
"0000011", -- b
"0111001", -- C
"0100001", -- d
"0000110", -- E
"0001110" -- F
);
begin
process (bin_in)
variable seg7_val: integer range 0 to 15;
begin
seg7_val := to_integer(unsigned(bin_in));
hex_out <= hex_to_segment(seg7_val);
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rom_16x4_sync is
port (
clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0)
);
end entity;
architecture dummy of rom_16x4_sync is
type rom_array is array (0 to 15) of std_logic_vector(3 downto 0);
function fill_rom return rom_array is
variable ret_val: rom_array;
begin
for i in rom_array'reverse_range loop -- backward to i
ret_val(i) := std_logic_vector(to_unsigned(i,4));
end loop;
return ret_val;
end function;
constant rom: rom_array := fill_rom;
begin
process (clock)
begin
if rising_edge(clock) and rom_en = '1' then -- NO RESET
data_out <= rom(to_integer(unsigned(address)));
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity top is
port (
clock: in std_logic;
reset: in std_logic;
sw: in std_logic_vector (1 downto 0); -- not used?
hex2, hex4: out std_logic_vector ( 6 downto 0);
key0: in std_logic
);
end entity;
architecture top_arch of top is
component char_decoder is
port (
bin_in: in std_logic_vector (3 downto 0);
hex_out: out std_logic_vector (6 downto 0)
);
end component;
component rom_16x4_sync is
port (
clock: in std_logic;
address: in std_logic_vector (3 downto 0);
rom_en: in std_logic;
data_out: out std_logic_vector(3 downto 0)
);
end component;
type state_type is (start, read_rom, clear_addr, done);
signal current_state,
next_state: state_type;
signal rom_en,
addr_count_clr,
addr_count_en: std_logic;
-- signal address_counter: integer range 0 to 15;
signal address_uns: unsigned (3 downto 0);
signal clock_slow: std_logic;
signal rom_out: std_logic_vector (3 downto 0);
begin
char:
char_decoder
port map (
bin_in => rom_out,
hex_out => hex2
);
char1:
char_decoder
port map (
bin_in => std_logic_vector(address_uns),
hex_out => hex4
);
clock_slow <= clock;
rom:
rom_16x4_sync
port map (
clock => clock_slow,
address => std_logic_vector(address_uns),
rom_en => rom_en, data_out => rom_out
);
state_memory:
process (clock_slow, reset)
begin
if reset = '0' then
current_state <= start;
elsif clock_slow'event and clock_slow = '1' then
current_state <= next_state;
end if;
end process;
next_state_logic:
-- process (current_state)
process (current_state, address_uns)
begin
case (current_state) is
when start =>
if key0 = '0' then
next_state <= read_rom;
else
next_state <= start;
end if;
when read_rom =>
if address_uns = 15 then
next_state <= clear_addr;
-- else
-- address_counter <= address_counter + 1;
end if;
when clear_addr => -- not a defined sequential logic inference
next_state <= done;
-- address_counter <= 0;
when done =>
next_state <= done;
end case;
end process;
output_logic:
process (current_state)
begin
case (current_state) is
when start =>
rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
when read_rom =>
rom_en <= '1';
addr_count_en <= '1';
addr_count_clr <= '0';
when clear_addr =>
rom_en <= '0';
addr_count_en <= '1';
addr_count_clr <= '1';
when done =>
rom_en <= '0';
addr_count_en <= '0';
addr_count_clr <= '0';
end case;
end process;
address_count:
process (addr_count_en, addr_count_clr, clock_slow)
begin
if reset = '0' then -- added reset
address_uns <= (others =>'0');
elsif clock_slow'event and clock_slow = '1' then
if addr_count_en = '1' then
if addr_count_clr = '1' then
address_uns <= "0000";
else
address_uns <= address_uns + 1;
end if;
end if;
end if;
end process;
-- address_uns <= to_unsigned(address_counter, 4);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity top_tb is
end entity;
architecture foo of top_tb is
signal clock: std_logic := '0';
signal reset: std_logic := '1';
signal sw: std_logic_vector (1 downto 0) := "00";
signal hex2, hex4: std_logic_vector ( 6 downto 0);
signal key0: std_logic := '0';
begin
DUT:
entity work.top
port map (
clock => clock,
reset => reset,
sw => sw,
hex2 => hex2,
hex4 => hex4,
key0 => key0
);
CLK:
process
begin
wait for 5 ns;
clock <= not clock;
if now > 200 ns then
wait;
end if;
end process;
STIMULIS:
process
begin
wait for 1 ns;
reset <= '0';
wait for 10 ns;
reset <= '1';
wait for 10 ns;
wait;
end process;
end architecture;
The char_decoder I used should be fully functional. The ROM contents are simply dummied up.

Issue in Quartus Post synthesis -- output is obtaining as xxxxxxxx

I have written a vhdl code and I want to run it in FPGA, The code is working fine in ghdl and also in the Quartus 2 pre synthesis(RTL simulation) , but when i am running in gatelevel simulation, it is showing data_out as xxxxxxx .I cant able figure out what is the problem. Can anyone help me?
--- device code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SimpleCalculator is
port ( data_in :in std_logic_vector(3 downto 0);
data_valid : in std_logic;
data_out : out std_logic_vector(7 downto 0);
clk, reset: in std_logic);
end entity SimpleCalculator;
architecture behave of SimpleCalculator is
----------------------------------
-- defining main state consisting of states of main thread
----------------------------------
type main_state is (main_idle,main_read0,main_read1,main_read2,main_read3,main_read4,main_calc);
signal next_mainstate: main_state;
-- below code creates two dimensional
-- array of 8 inputs with 16 bits each
type inputs_bit is array(0 to 4) of std_logic_vector(3 downto 0);
signal input_array : inputs_bit;
signal calc_start : std_logic;
signal calc_done : std_logic;
------------------------------
-- defining signals and states for calc thread
------------------------------
type calc_state is (calc_idle,calc_check_inputs,calc_running,calc_error);
signal calcstate : calc_state;
-----------------------------
begin
main: process(clk,reset,data_valid,next_mainstate,calc_done)
variable nstate:main_state;
--variable count: integer:=0;
begin
nstate := next_mainstate;
case next_mainstate is
when main_idle =>
if(data_valid = '1' ) then
nstate:= main_read0;
else
nstate:= main_idle;
end if;
when main_read0 =>
input_array(0) <= data_in;
nstate:=main_read1;
when main_read1 =>
input_array(1) <= data_in;
nstate:=main_read2;
when main_read2 =>
input_array(2) <= data_in;
nstate:=main_read3;
when main_read3 =>
input_array(3) <= data_in;
nstate:=main_read4;
when main_read4 =>
input_array(4) <= data_in;
nstate:=main_calc;
calc_start <= '1';
when main_calc =>
calc_start <= '0';
if(calc_done ='1') then
nstate:= main_idle;
else
nstate:=main_calc;
end if;
when others => null;
end case;
if(clk'event and clk = '1') then
if(reset = '1') then
next_mainstate <= main_idle;
else
next_mainstate <= nstate;
end if;
end if;
end process main;
------------------------------------------------
--calc fsm
---------------------------------------------
calc: process(clk,reset,calc_start,calcstate)
variable nstate:calc_state;
begin
nstate := calcstate;
case calcstate is
when calc_idle =>
if(calc_start = '1') then
nstate := calc_check_inputs;
else
nstate := calc_idle;
end if;
when calc_check_inputs =>
if(input_array(0) = "1010" and input_array(1) < "1010" and input_array(2) > "1011"
and input_array(3) < "1010" and input_array(4) = "1011") then
nstate := calc_running;
else
nstate := calc_error;
end if;
-- check for correct sequence
when calc_error =>
data_out <= "11111111";
when calc_running =>
case input_array(2) is
when "1100" =>
data_out <= std_logic_vector(unsigned(input_array(1)) * unsigned(input_array(3)) ) after 1 ns;
when "1101" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) + unsigned(input_array(3)) ) after 1 ns;
when "1110" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) - unsigned(input_array(3)) ) after 1 ns;
when "1111" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) / unsigned(input_array(3)) ) after 1 ns;
when others => null;
end case;
calc_done <='1';
nstate := calc_idle;
when others => null;
end case;
if(clk'event and clk = '1') then
if(reset = '1') then
calcstate <= calc_idle;
else
calcstate <= nstate;
end if;
end if;
end process calc;
end behave;
--- **testbench**
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
entity Simplecalculator_tb is
end entity;
architecture behave of Simplecalculator_tb is
signal data_in : std_logic_vector(3 downto 0);
signal data_valid : std_logic:= '0';
signal data_out : std_logic_vector(7 downto 0);
signal clk, reset: std_logic:= '0';
file stimulus_file: text is in "calci_inputs.txt";
file result_file: text is in "calci_result.txt";
component SimpleCalculator is
port ( data_in :in std_logic_vector(3 downto 0);
data_valid : in std_logic;
data_out : out std_logic_vector(7 downto 0);
clk, reset: in std_logic);
end component;
begin
-- 10 ns clock.
clk <= not clk after 5 ns;
process
variable L: line;
variable next_number_input: bit_vector(3 downto 0);
variable next_number_output: bit_vector(7 downto 0);
begin
reset <= '1';
data_valid <= '0';
wait until clk ='1';
reset <= '0';
data_valid <= '1';
wait until clk ='1';
data_valid <= '0';
while( not endfile(stimulus_file)) loop
readline(stimulus_file,L);
read(L,next_number_input);
data_in <= To_StdLogicVector(next_number_input);
wait until clk='1';
assert false report "Sent item " severity note;
end loop;
assert false report "Sent all items " severity note;
wait for 20 ns;
assert false report "Received done " severity note;
readline(result_file,L);
read(L,next_number_output);
if(data_out = To_StdLogicVector(next_number_output)) then
assert false report "SUCCESS: got the correct result." severity note;
else
assert false report "FAILURE: incorrect result! " severity ERROR;
end if;
wait;
end process;
dut : SimpleCalculator port map
( data_in => data_in, data_valid => data_valid, data_out => data_out, clk => clk,
reset => reset);
end behave;
---input file
1010
0111
1110
0010
1011
-- output file content
00000101
I have changed my code and the testbench and I have included the even the delays, but still I am getting the same xxxx error...Can anyone pls help me what is wrong in the code..what else I need to change.Thanks in advance
------ modified code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SimpleCalculator is
port ( data_in :in std_logic_vector(3 downto 0);
data_valid : in std_logic;
data_out : out std_logic_vector(7 downto 0);
clk, reset: in std_logic);
end entity SimpleCalculator;
architecture behave of SimpleCalculator is
----------------------------------
-- defining main state consisting of states of main thread
----------------------------------
type main_state is (main_idle,main_read0,main_read1,main_read2,main_read3,main_read4,main_calc);
signal next_mainstate: main_state;
-- below code creates two dimensional
-- array of 8 inputs with 16 bits each
type inputs_bit is array(0 to 4) of std_logic_vector(3 downto 0);
signal input_array : inputs_bit;
signal calc_start : std_logic;
signal calc_done : std_logic;
------------------------------
-- defining signals and states for calc thread
------------------------------
type calc_state is (calc_idle,calc_check_inputs,calc_running,calc_error);
signal calcstate : calc_state;
-----------------------------
begin
main: process(clk,reset,data_valid,next_mainstate,calc_done)
variable nstate:main_state;
--variable count: integer:=0;
begin
nstate := next_mainstate;
case next_mainstate is
when main_idle =>
if(data_valid = '1' ) then
nstate:= main_read0;
else
nstate:= main_idle;
end if;
when main_read0 =>
input_array(0) <= data_in after 2 ns;
nstate:=main_read1;
when main_read1 =>
input_array(1) <= data_in after 2 ns;
nstate:=main_read2;
when main_read2 =>
input_array(2) <= data_in after 2 ns;
nstate:=main_read3;
when main_read3 =>
input_array(3) <= data_in after 2 ns;
nstate:=main_read4;
when main_read4 =>
input_array(4) <= data_in after 2 ns;
nstate:=main_calc;
calc_start <= '1' after 2 ns;
when main_calc =>
calc_start <= '0' after 2 ns;
if(calc_done ='1') then
nstate:= main_idle;
else
nstate:=main_calc;
end if;
when others => null;
end case;
if(clk'event and clk = '1') then
if(reset = '1') then
next_mainstate <= main_idle;
else
next_mainstate <= nstate;
end if;
end if;
end process main;
------------------------------------------------
--calc fsm
---------------------------------------------
calc: process(clk,reset,calc_start,calcstate)
variable nstate:calc_state;
begin
nstate := calcstate;
case calcstate is
when calc_idle =>
if(calc_start = '1') then
nstate := calc_check_inputs;
else
nstate := calc_idle;
end if;
when calc_check_inputs =>
if(input_array(0) = "1010" and input_array(1) < "1010" and input_array(2) > "1011"
and input_array(3) < "1010" and input_array(4) = "1011") then
nstate := calc_running;
else
nstate := calc_error;
end if;
-- check for correct sequence
when calc_error =>
data_out <= "11111111";
when calc_running =>
case input_array(2) is
when "1100" =>
data_out <= std_logic_vector(unsigned(input_array(1)) * unsigned(input_array(3)) ) after 1 ns;
when "1101" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) + unsigned(input_array(3)) ) after 1 ns;
when "1110" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) - unsigned(input_array(3)) ) after 1 ns;
when "1111" =>
data_out <= "0000" & std_logic_vector(unsigned(input_array(1)) / unsigned(input_array(3)) ) after 1 ns;
when others => null;
end case;
calc_done <='1' after 2 ns;
nstate := calc_idle;
when others => null;
end case;
if(clk'event and clk = '1') then
if(reset = '1') then
calcstate <= calc_idle;
else
calcstate <= nstate;
end if;
end if;
end process calc;
end behave;
-- new testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
entity Simplecalculator_tb is
end entity;
architecture behave of Simplecalculator_tb is
signal data_in : std_logic_vector(3 downto 0):= (others => '0');
signal data_valid : std_logic:= '0';
signal data_out : std_logic_vector(7 downto 0);
signal clk, reset: std_logic:= '0';
file stimulus_file: text is in "/home/student/pavanpalla/lab_5/calci_inputs.txt";
file result_file: text is in "/home/student/pavanpalla/lab_5/calci_result.txt";
component SimpleCalculator is
port ( data_in :in std_logic_vector(3 downto 0);
data_valid : in std_logic;
data_out : out std_logic_vector(7 downto 0);
clk, reset: in std_logic);
end component;
begin
-- 10 ns clock.
clk <= not clk after 20 ns;
process
variable L: line;
variable next_number_input: bit_vector(3 downto 0);
variable next_number_output: bit_vector(7 downto 0);
begin
reset <= '1';
data_valid <= '0';
wait until clk ='1';
reset <= '0' after 2 ns;
data_valid <= '1' after 2 ns;
wait until clk ='1';
data_valid <= '0' after 2 ns;
while( not endfile(stimulus_file)) loop
readline(stimulus_file,L);
read(L,next_number_input);
data_in <= To_StdLogicVector(next_number_input) after 10 ns;
wait until clk='1';
assert false report "Sent item " severity note;
end loop;
assert false report "Sent all items " severity note;
wait for 50 ns;
assert false report "Received done " severity note;
readline(result_file,L);
read(L,next_number_output);
if(data_out = To_StdLogicVector(next_number_output)) then
assert false report "SUCCESS: got the correct result." severity note;
else
assert false report "FAILURE: incorrect result! " severity ERROR;
end if;
wait;
end process;
dut : SimpleCalculator port map
( data_in => data_in, data_valid => data_valid, data_out => data_out, clk => clk,
reset => reset);
end behave;
I am also attaching the images of presynthesis and postsynthesis. I cant able to figure out where I am giving wrong
presynthesis
post_synthesis
Gate-level simulation includes timing for design primitives, for example flip-flops, so setup and hold time for data to flip-flops must be respected, and otherwise the flip-flops may generate 'X' on the output.
The test bench code is not written with this in mind; for example:
wait until clk ='1';
reset <= '0';
The reset is removed 0 ps after rising edge of clk, and depending on the implementation there may be hold-time requirement for the synchronous design reset.
This can be addressed by running at a "slow" clock and only change data "far" from the rising clk edge. This is acceptable since design timing should be verified through Static Timing Analysis (STA) and not simulation; post-synthesis simulation is only to get a good feeling that the design is OK, but it is unrealistic to verify design timing through test cases.
You may also consider writing the processes as either clocked process or combinatorial process, since this generally will make design easier to write, read, and debug. The calc process is an example of a process both updating on rising edge of clk and on calcstate.

VHDL Counter result giving X

I am attempting to build a counter in VHDL. Eventual goal is to hook the "do_count" to a button. The total will be converted to BCD and displayed on a 7-segment display. Push the button, watch the numbers increment.
I'm using ModelSim and I can see the internal "counter_value" correctly increment by 1. But the output signal "total" becomes "000X" then "00X0" during my two test "do_count"s. Why am I getting an X'd signal?
I've moved the "output <= current_value" around inside the process, outside the process, inside the 'if's, etc. Still the "000X".
I've tried using a variable 'tmp' inside the process.
count_up : process(clk) is
variable tmp : unsigned (15 downto 0 );
begin
tmp := current_value;
-- snip
if do_count='1' then
current_value <= tmp + to_unsigned(1,16);
end if;
Still I get the "000X".
Full code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity d_counter is
port ( rst : in std_logic;
clk : in std_logic;
do_count : in std_logic;
total : out unsigned (15 downto 0)
);
end entity d_counter;
architecture counter_arch of d_counter is
signal current_value : unsigned (15 downto 0) := (others=>'0');
begin
count_up : process(clk) is
begin
if rst='1' then
current_value <= (others=>'0');
total <= (others=>'0');
elsif rising_edge(clk) then
if do_count='1' then
current_value <= current_value + to_unsigned(1,16);
end if;
end if;
end process count_up;
total <= current_value;
end architecture counter_arch;
Testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity test_counter is
begin
end entity test_counter;
architecture run_test_counter of test_counter is
signal t_rst : std_logic := '1';
signal t_clk : std_logic := '0';
signal t_do_count : std_logic;
signal t_total : unsigned( 15 downto 0 );
component d_counter is
port ( rst : in std_logic;
clk : in std_logic;
do_count : in std_logic;
total : out unsigned( 15 downto 0 )
);
end component d_counter;
begin
uut : d_counter
port map( rst => t_rst,
clk => t_clk,
do_count => t_do_count,
total => t_total );
clock : process is
begin
t_clk <= '0'; wait for 10 ns;
t_clk <= '1'; wait for 10 ns;
end process clock;
stimulus : process is
begin
t_rst <= '1';
t_do_count <= '0';
t_total <= (others =>'0');
wait for 15 ns;
t_rst <= '0';
wait for 10 ns;
t_do_count <= '1';
wait for 10 ns;
t_do_count <= '0';
wait for 10 ns;
t_do_count <= '1';
wait for 10 ns;
t_do_count <= '0';
wait for 10 ns;
wait;
end process stimulus;
end architecture run_test_counter;
Update 03-Oct-2012.
BOTH the answers helped. Moving "total <= current_value" inside the process (From #simon) and removing the extra "t_total <= (others =>'0');" (From #peter-bennett) in my testbench was required. I had to do both to get rid of the X's.
It looks like your mistake is in your testbench. The signal t_total is mapped to the total output of your counter component, yet you are writing to it with the t_total <= (others => '0') assignment. If you remove this I think your problem will go away.
uut : d_counter
port map( rst => t_rst,
clk => t_clk,
do_count => t_do_count,
total => t_total );
clock : process is
begin
t_clk <= '0'; wait for 10 ns;
t_clk <= '1'; wait for 10 ns;
end process clock;
stimulus : process is
begin
t_rst <= '1';
t_do_count <= '0';
t_total <= (others =>'0'); <-- Do not assign to t_total (its an output)
Your code write multi-driven with "total". You should delete assigment in process count_up.
count_up : process(clk) is
begin
if rst='1' then
current_value <= (others=>'0');
total <= (others=>'0'); --> Remove it
elsif rising_edge(clk) then
if do_count='1' then
current_value <= current_value + to_unsigned(1,16);
end if;
end if;
end process count_up;
total <= current_value; -- Keep it

Resources