i am trying to practice debouncing on FPGA following the approach (full count based), that introduced in the book from Volnei ("Circuit Design with VHDL third edition").
A very important feature of this circuit is the way the timer is constructed, which eliminates the need for a comparator (a large circuit).
For example, for the numeric values just given, $S = 50,MHz * 20,ms= 10e6$ results, where the number of bits (DFFs) in the counter is $N= log_2(S) = 20$ implying a counter running from zero to $10e6 - 1$ = 1 1 1 1_0100_0010_00 1 1_1 1 1 1, thus requiring a comparator that is at least 12 bits wide (only the s need to be monitored), which is indeed a large circuit. This can be avoided by taking into consideration that the time does not need to be exact in debouncers, so if an extra bit (flip-flop) is included in the counter, its MSB alone can play the role of comparator; when MSB= 1 occurs, it enables the output register, so y is updated, leading subsequently to clear= 1, which zeros the counter (and therefore the MSB too) at the next positive clock edge. In summary, the counter spans a total of $ S = 2^N+ 1$ states, leading to $T{deb} = 2^N/f_{clk (50MHz)} = 21 ms$ for the numeric values given above.
However, testing the code given from this Example not giving the expected result.
Debouncing
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE IEEE.math_real.ALL;
ENTITY E13_button_debouncer IS
GENERIC (
T_DEB_MS : NATURAL := 25;
f_clk : NATURAL := 50_000);
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
b_in : IN STD_LOGIC;
b_out : OUT STD_LOGIC
);
END E13_button_debouncer;
ARCHITECTURE single_switch OF E13_button_debouncer IS
CONSTANT COUNTER_BITS : NATURAL := 1 + INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));
-- ! Optional :
SIGNAL x_reg : STD_LOGIC;
BEGIN
proc_name : PROCESS (clk)
VARIABLE count : unsigned(COUNTER_BITS - 1 DOWNTO 0);
BEGIN
IF rising_edge(clk) THEN
IF rst = '0' THEN
count := (OTHERS => '0');
x_reg <= '0';
b_out <= '0';
ELSE
x_reg <= b_in;
IF b_out = x_reg THEN
count := (OTHERS => '0');
ELSE
count := count + 1;
END IF;
END IF;
END IF;
IF falling_edge(clk) THEN
IF count(COUNTER_BITS - 1) THEN
b_out <= NOT b_out;
END IF;
END IF;
END PROCESS proc_name;
END ARCHITECTURE;
Test Bench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY E13_button_debouncer_tb IS
END E13_button_debouncer_tb;
ARCHITECTURE sim OF E13_button_debouncer_tb IS
CONSTANT clk_hz : INTEGER := 50_000;
CONSTANT clk_period : TIME := 1 sec / clk_hz;
CONSTANT T_DEB_MS : NATURAL := 25;
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC := '0';
SIGNAL b_in : STD_LOGIC := '0';
SIGNAL b_out : STD_LOGIC := '1';
BEGIN
clk <= NOT clk AFTER clk_period / 2;
bu_deboun : ENTITY work.E13_button_debouncer(single_switch)
GENERIC MAP(f_clk => clk_hz, T_DEB_MS => T_DEB_MS)
PORT MAP(
clk => clk,
rst => rst,
b_in => b_in,
b_out => b_out
);
SEQUENCER_PROC : PROCESS
BEGIN
WAIT FOR clk_period * 1;
rst <= '1';
b_in <= '1';
WAIT FOR 1 ms;
b_in <= '0';
WAIT FOR 1 ms;
b_in <= '1';
WAIT FOR 100 ms;
b_in <= '0';
WAIT FOR 1 ms;
b_in <= '1';
WAIT FOR 10 ms;
b_in <= '0';
WAIT FOR 10 ms;
END PROCESS;
END ARCHITECTURE;
Simulation
I expepct that the code work like photo below:
to solve the problem first to avoid errors when synthesize it need the changes to the code thanks to (#thebusybee, #user16145658,#MatthiasSchweikart):
BEGIN
IF rising_edge(clk) THEN
IF rst = '0' THEN
count := (OTHERS => '0');
x_reg <= '0';
ELSE
x_reg <= b_in;
IF b_out = x_reg THEN
count := (OTHERS => '0');
ELSE
count := count + 1;
END IF;
END IF;
END IF;
IF falling_edge(clk) THEN
IF rst = '0' THEN
b_out <= '0';
ELSE
REPORT "we are in falling edge and the counter value : " & INTEGER'image(to_integer(count));
IF count(COUNTER_BITS - 1) THEN
b_out <= NOT b_out;
END IF;
END IF;
END IF;
END PROCESS proc_name;
END ARCHITECTURE;
the problem was here:
GENERIC (
T_DEB_MS : NATURAL := 25;
f_clk : NATURAL := 50_000);
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
b_in : IN STD_LOGIC;
b_out : OUT STD_LOGIC
);
END E13_button_debouncer;
ARCHITECTURE single_switch OF E13_button_debouncer IS
CONSTANT COUNTER_BITS : NATURAL := 1 + INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));
which result in N=21 that mean the debounce time will be 41 Second. so to solve it i should do it like this : 0.025 * fclk = 1250 => result in N= 10 => +1 =11.
then the counter will count till 2048 resulting in debounce time von 40 ms. which is ok for my application.
Related
I am completly new for the FPGA and basys3 development board.
I have a project for Counter on the 7 segment displays on the board.
We got 3 different layers as a design.
cntr /
cntr_rtl /
cntr_top /
cntr_top_struc /
io_ctrl /
io_ctrl_rtl /
And in the project it has to diplay on the 7 segment controlled by the switches : count up/count down / hold / reset options:
The priorities for these switches are:
reset
hold
count direction
top level VHDL file cntr_top.vhd
Port Name Direction Description
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
sw_i(15:0) In 16 switches
pb_i(3:0) In 4 buttons
ss_o(7:0) Out Contain the value for all 7-segment digits
ss_sel_o(3:0) Out Select a 7-segment digit
io_ctrl
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
cntr0_i(n:0) In Digit 0 (from internal logic)
cntr1_i(n:0) In Digit 1 (from internal logic)
cntr2_i(n:0) In Digit 2 (from internal logic)
cntr3_i(n:0) In Digit 3 (from internal logic)
sw_i(15:0) In 16 switches (from FPGA board)
pb_i(3:0) In 4 buttons (from FPGA board)
ss_o(7:0) Out to 7-segment displays of the FPGA board
ss_sel_o(3:0) Out Selection of a 7-segment digit
swclean_o(15:0) Out 16 switches (to internal logic)
pbclean_o(3:0) Out 4 buttons (to internal logic)
cntr.vhd
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
cntrup_i In Counts up if signal is ‘1’
cntrdown_i In Counts down if signal is ‘1’
cntrreset_i In Sets counter to 0x0 if signal is ‘1’
cntrhold_i In Holds count value if signal is ‘1’
cntr0_o(n:0) Out Digit 0 (from internal logic)
cntr1_o(n:0) Out Digit 1 (from internal logic)
cntr2_o(n:0) Out Digit 2 (from internal logic)
cntr3_o(n:0) Out Digit 3 (from internal logic)
I will attach also the file to the attachment. Now my code is working and do all the funcitionality correct but there is only one issue which is the DEBOUNCE code part.
I didnt use the clk signal for the code and i have to change it. The certain given clock signal has to be used.
So can any be give me suggestions how i can correct the debounce concept in the code.
io_ctrl_rtl.vhd -code down below:
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of io_ctrl is
constant COUNTVALUE : std_logic_vector(16 downto 0):= "01100001101010000";
signal s_enctr : std_logic_vector(16 downto 0):="00000000000000000";
signal s_2khzen : std_logic :='0';
signal s_1hzen : std_logic :='0';
signal s_2khzcount : std_logic_vector(3 downto 0) := "0000";
signal swsync0 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync0 : std_logic_vector(3 downto 0):="0000";
signal swsync1 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync1 : std_logic_vector(3 downto 0):="0000";
signal swtmp : std_logic_vector(15 downto 0):="0000000000000000";
signal pbtmp : std_logic_vector(3 downto 0):="0000";
signal swdebounced : std_logic_vector(15 downto 0):="0000000000000000";
signal pbdebounced : std_logic_vector(3 downto 0):="0000";
signal s_ss_sel : std_logic_vector(3 downto 0) := "0000";
signal s_ss : std_logic_vector(7 downto 0) := "00000000";
begin -- rtl
-----------------------------------------------------------------------------
--
-- Synchronize the inputs
--
-----------------------------------------------------------------------------
p_sync: process (clk_i, reset_i)
begin
if reset_i = '1' then
swsync0 <= (others => '0');
pbsync0 <= (others => '0');
swsync1 <= (others => '0');
pbsync1 <= (others => '0');
elsif clk_i'event and clk_i = '1' then
swsync0 <= sw_i;
pbsync0 <= pb_i;
swsync1 <= swsync0;
pbsync1 <= pbsync0;
else null;
end if;
end process;
-----------------------------------------------------------------------------
--
-- Generate 1 KHz enable signal.
--
-----------------------------------------------------------------------------
p_slowen: process (clk_i, reset_i)
begin
if reset_i = '1' then
s_enctr <= (others => '0');
s_2khzen <= '0';
elsif clk_i'event and clk_i = '1' then
if s_enctr = COUNTVALUE then -- When the terminal counter is reached, set the release flag and reset the counter
s_enctr <= (others => '0');
s_2khzen <= '1';
s_2khzcount <= std_logic_vector(to_unsigned(to_integer(unsigned( s_2khzcount )) + 1, 4));
else
s_enctr <= std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 17)); -- As long as the terminal count is not reached: increment the counter.
if s_2khzen = '1' then
s_2khzen <= '0';
end if;
end if;
if s_2khzcount = "1010" then
s_1hzen <= not s_1hzen;
s_2khzcount <= "0000";
end if;
end if;
end process p_slowen;
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (s_1hzen, reset_i)
variable dbouncecntr : integer:=0;
begin
if reset_i = '1' then
swdebounced <= "0000000000000000";
pbdebounced <= "0000";
dbouncecntr :=0; -- Change clocking the process with signal from sens list.
else
if (dbouncecntr = 0) then
swtmp <= swsync1;
pbtmp <= pbsync1;
dbouncecntr := dbouncecntr + 1;
elsif (dbouncecntr = 1) then
if (swtmp = swsync1) then
swdebounced <= swsync1;
end if;
if (pbtmp = pbsync1) then
pbdebounced <= pbsync1;
end if;
dbouncecntr := 0;
end if;
end if;
end process p_debounce;
swclean_o <= swdebounced;
pbclean_o <= pbdebounced;
-----------------------------------------------------------------------------
--
-- Display controller for the 7-segment display
--
-----------------------------------------------------------------------------
p_displaycontrol: process (clk_i, reset_i)
variable v_scancnt : std_logic_vector(1 downto 0):= "00";
variable v_output : std_logic_vector(3 downto 0):="0000";
begin
if reset_i = '1' then
v_scancnt := "00";
s_ss <= "00000000";
elsif clk_i'event and clk_i = '1' then
if s_2khzen = '1' then
case v_scancnt is
when "00" =>
v_output := cntr0_i;
s_ss_sel <= "0001";
when "01" =>
v_output := cntr1_i;
s_ss_sel <= "0010";
when "10" =>
v_output := cntr2_i;
s_ss_sel <= "0100";
when "11" =>
v_output := cntr3_i;
s_ss_sel <= "1000";
when others =>
v_output := "1111";
s_ss_sel <= "0001";
end case;
case v_output is --ABCDEFG,
when "0000" => s_ss <= "11111100"; --0
when "0001" => s_ss <= "01100000"; --1
when "0010" => s_ss <= "11011010"; --2
when "0011" => s_ss <= "11110010"; --3
when "0100" => s_ss <= "01100110"; --4
when "0101" => s_ss <= "10110110"; --5
when "0110" => s_ss <= "10111110"; --6
when "0111" => s_ss <= "11100000"; --7
when "1000" => s_ss <= "11111110"; --8
when "1001" => s_ss <= "11110110"; --9
when others => s_ss <= v_scancnt & "000000";
end case;
if v_scancnt = "11" then
v_scancnt := "00";
else
v_scancnt := std_logic_vector(to_unsigned(to_integer(unsigned( v_scancnt )) + 1, 2));
end if;
else null;
end if;
else null;
end if;
end process p_displaycontrol;
ss_o <= not s_ss;
ss_sel_o <= not s_ss_sel;
end rtl;
The code for : cntr_top_struc.vhd
library IEEE;
use IEEE.std_logic_1164.all;
architecture rtl of cntr_top is
component cntr -- component of cntr
port (clk_i: in std_logic; -- 100 MHz system clock
reset_i: in std_logic; -- async high active reset
cntrup_i : in std_logic; --counts up if signal is '1'
cntrdown_i : in std_logic; --counts down if signal is '1'
cntrreset_i : in std_logic; --sets counter to 0x0 if signal is '1'
cntrhold_i : in std_logic; --holds count value if signal is '1'
cntr0_o: out std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_o: out std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_o: out std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_o: out std_logic_vector(3 downto 0)); -- Digit 3 (from internal logic)
end component;
component io_ctrl ---- component io_crtl
port (clk_i: in std_logic; -- 100 MHz system clock
reset_i: in std_logic; -- async high active reset
cntr0_i: in std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_i: in std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_i: in std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_i: in std_logic_vector(3 downto 0); -- Digit 3 (from internal logic)
swclean_o: out std_logic_vector(15 downto 0);
pbclean_o: out std_logic_vector(3 downto 0);
ss_o: out std_logic_vector(7 downto 0); -- Contain the Value for All 7-Segment Digits
ss_sel_o: out std_logic_vector(3 downto 0); -- Select a 7-segment digits
pb_i: in std_logic_vector(3 downto 0); --4 Buttons
sw_i: in std_logic_vector(15 downto 0) ); --16 Switches
end component;
-- Declare the signals that are used to connect the submodules.
signal s_cntr0 : std_logic_vector(3 downto 0);
signal s_cntr1 : std_logic_vector(3 downto 0);
signal s_cntr2 : std_logic_vector(3 downto 0);
signal s_cntr3 : std_logic_vector(3 downto 0);
signal s_cntrup : std_logic;
signal s_cntrdown : std_logic;
signal s_cntrreset : std_logic;
signal s_cntrhold : std_logic;
signal s_overflow : std_logic_vector(11 downto 0);
begin
--Instantiate the counter that is connected to the IO-Control
i_cntr_top1 : cntr
port map
(clk_i => clk_i,
reset_i => reset_i,
-- cntrdir_i => s_cntrdir, --swsync_o(13);
cntrup_i => s_cntrup, --swsync_o(13);
cntrdown_i => s_cntrdown, --swsync_o(12);
cntrreset_i => s_cntrreset, --swsync_o(15),
cntrhold_i => s_cntrhold, --swsync_o(14),
cntr0_o => s_cntr0,
cntr1_o => s_cntr1,
cntr2_o => s_cntr2,
cntr3_o => s_cntr3);
--Instantiate the IO control to which it is connected
i_io_ctrl : io_ctrl
port map
(clk_i => clk_i,
reset_i => reset_i,
swclean_o(12) => s_cntrdown,
swclean_o(13) => s_cntrup,
swclean_o(15) => s_cntrreset,
swclean_o(14) => s_cntrhold,
swclean_o(11 downto 0) => s_overflow(11 downto 0),
cntr0_i => s_cntr0,
cntr1_i => s_cntr1,
cntr2_i => s_cntr2,
cntr3_i => s_cntr3,
ss_o => ss_o,
ss_sel_o => ss_sel_o,
sw_i => sw_i,
pb_i => pb_i);
end rtl;
cntr_top.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity cntr_top is
port (clk_i : in std_logic; -- First Data Bit
reset_i : in std_logic; -- Second Data Bit
sw_i : in std_logic_vector (15 downto 0); -- 16 Switches Input
pb_i : in std_logic_vector(3 downto 0); -- 4 Buttons Input
ss_o : out std_logic_vector(7 downto 0); -- Contain the Value for All 7-Segment Digits
ss_sel_o : out std_logic_vector(3 downto 0)); -- Select a 7-segment digits
end cntr_top;
io_ctrl.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity io_ctrl is
port (clk_i : in std_logic; -- System clock (100 MHZ)
reset_i : in std_logic; -- Asynchronous high active reset
cntr0_i : in std_logic_vector(3 downto 0); -- Digit 0 from internal logic
cntr1_i : in std_logic_vector(3 downto 0); -- Digit 1 from internal logic
cntr2_i : in std_logic_vector(3 downto 0); -- Digit 2 from internal logic
cntr3_i : in std_logic_vector(3 downto 0); -- Digit 3 from internal logic
sw_i : in std_logic_vector(15 downto 0); -- 16 switches (from FPGA board)
pb_i : in std_logic_vector(3 downto 0); -- 4 buttons (from FPGA board)
ss_o : out std_logic_vector(7 downto 0); -- to 7 segment displays of the FPGA board
ss_sel_o : out std_logic_vector(3 downto 0); -- Selection of a 7 segment digit
swclean_o: out std_logic_vector(15 downto 0); -- 16 switches (to internal logic)
pbclean_o : out std_logic_vector(3 downto 0)); -- 4 buttons
end io_ctrl;
cntr_rtl.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of cntr is
constant COUNTVALUE : std_logic_vector(26 downto 0):= "000000000000000001111101000";
--constant COUNTVALUE : std_logic_vector(26 downto 0):= "101111101011110000100000000";
signal s_enctr : std_logic_vector(26 downto 0) := "000000000000000000000000000";
signal s_1hzen : std_logic :='0';
signal s_cntr0 : std_logic_vector(3 downto 0) :="0000"; -- All digits set to zero.
signal s_cntr1 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr2 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr3 : std_logic_vector(3 downto 0) :="0000";
type s_state is (reset, hold, up, down);
signal s_present_state : s_state;
signal s_next_state : s_state;
begin
p_cntr: process(clk_i, reset_i)
variable v_digit0 : std_logic_vector(3 downto 0):= "0000";
variable v_digit1 : std_logic_vector(3 downto 0):= "0000";
variable v_digit2 : std_logic_vector(3 downto 0):= "0000";
variable v_digit3 : std_logic_vector(3 downto 0):= "0000";
begin
if reset_i = '1' then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
s_enctr <= (others => '0');
elsif (clk_i'event and clk_i = '1') then
s_present_state <= s_next_state;
if s_enctr = COUNTVALUE then --When the number of terminals is reached, set the release flag and reset the counter
s_enctr <= (others => '0');
s_1hzen <= '1';
case s_present_state is
when up => --counting up.
if v_digit0 /= "1001" then
v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) + 1, 4)); -- incrementing the bits.
elsif v_digit0 = "1001" and v_digit1 /= "1001" then
v_digit0 := "0000";
v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) + 1, 4));
elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 /= "1001" then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) + 1, 4));
elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 = "1001" and v_digit3 /= "1001"then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) + 1, 4));
else
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
end if;
when down => --counting down.
if v_digit0 /= "0000" then
v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) - 1, 4)); -- decrementing the bits.
elsif v_digit0 = "0000" and v_digit1 /= "0000" then
v_digit0 := "1001";
v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) - 1, 4));
elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 /= "0000" then
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) - 1, 4));
elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 = "0000" and v_digit3 /= "0000"then
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := "1001";
v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) - 1, 4));
else
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := "1001";
v_digit3 := "1001";
end if;
when hold => null; -- holding the counting.
when reset => -- reset all the values to zero.
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
end case;
else
s_enctr <=std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 27));
if s_1hzen = '1' then
s_1hzen <= '0';
end if;
end if;
s_cntr0 <= v_digit0;
s_cntr1 <= v_digit1;
s_cntr2 <= v_digit2;
s_cntr3 <= v_digit3;
end if;
end process p_cntr;
cntr0_o <= s_cntr0;
cntr1_o <= s_cntr1;
cntr2_o <= s_cntr2;
cntr3_o <= s_cntr3;
----------------------------------------------------------------------------------------------------------------
-- State machine
----------------------------------------------------------------------------------------------------------------
p_states: process(s_present_state, cntrup_i, cntrdown_i, cntrreset_i, cntrhold_i,reset_i)
begin
case s_present_state is
when reset => -- reset state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when hold => -- hold state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when up => -- up count state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when down => -- down count conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when others => s_next_state <= reset;
end case;
end process p_states;
end rtl;
cntr.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity cntr is
port (clk_i : in std_logic; -- System clock (100 MHZ)
reset_i : in std_logic; -- Asysnchronous high active reset
cntrup_i : in std_logic; --counts up if signal is '1'
cntrdown_i : in std_logic; --counts down if signal is '1'
cntrreset_i : in std_logic; --sets counter to 0x0 if signal is '1'
cntrhold_i : in std_logic; --holds count value if signal is '1'
cntr0_o : out std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_o : out std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_o : out std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_o : out std_logic_vector(3 downto 0)); -- Digit 3 (from internal logic)
end cntr;
Please waiting for your suggestions.
Any help would be great appricated thanks for all.
here down below example for debounce but couldnt find to way to implement.
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (clk_i, reset_i)
begin -- process debounce
if reset_i = '1' then -- asynchronous reset (active high)
elsif clk_i'event and clk_i = '1' then -- rising clock edge
end if;
end process p_debounce;
swsync_o <= swsync;
pbsync_o <= pbsync;
------------------------------------------------------------
You're on the right track in that you need to synchronise the asynchronous inputs and debounce them.
But your debounce code needs to use a separate debouncer for each input with a timeout value of around 100 for a 1 kHz clock.
Here is a generic synchroniser and debouncer which uses parameters to specify the bus width, number of sync registers and timeout value.
Synchroniser.vhd
--
-- Synchronise an asynchronous bus input to avoid metastability problems
--
--
-- Signal Synchroniser (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SynchroniserBit is
generic
(
reg_size: integer := 3 -- Default number of bits in sync register.
);
port
(
clock: in std_logic;
async_in: in std_logic := '0';
sync_out: out std_logic := '0';
rise: out std_logic := '0';
fall: out std_logic := '0'
);
end;
architecture V1 of SynchroniserBit is
constant MSB: integer := reg_size - 1;
signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
begin
process (clock)
begin
if rising_edge(clock) then
rise <= not sync_reg(MSB) and sync_reg(MSB - 1);
fall <= sync_reg(MSB) and not sync_reg(MSB - 1);
sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
end if;
end process;
sync_out <= sync_reg(MSB);
end;
--
-- Bus Synchroniser (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Synchroniser is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
sync_bus_out: out std_logic_vector(bus_size - 1 downto 0);
rise_bus_out: out std_logic_vector(bus_size - 1 downto 0);
fall_bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end;
architecture V1 of Synchroniser is
component SynchroniserBit is
generic
(
reg_size: integer := 3 -- Default number of bits in sync register.
);
port
(
clock: in std_logic;
async_in: in std_logic;
sync_out: out std_logic;
rise: out std_logic;
fall: out std_logic
);
end component;
begin
SyncGen: for i in 0 to bus_size - 1 generate
begin
Sync: SynchroniserBit
generic map
(
reg_size => reg_size
)
port map
(
clock => clock,
async_in => async_bus_in(i),
sync_out => sync_bus_out(i),
rise => rise_bus_out(i),
fall => fall_bus_out(i)
);
end generate;
end;
Debouncer.vhd
--
-- Debounce a bus.
--
--
-- Signal Debouncer (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DebouncerBit is
port
(
clock: in std_logic;
counter: in integer;
input: in std_logic;
output: out std_logic := '0'
);
end;
architecture V1 of DebouncerBit is
begin
process(clock)
variable counter_snapshot: integer := 0;
variable previous_input: std_logic := '0';
begin
if rising_edge(clock) then
-- If counter wraps around to counter_snapshot,
-- a full debounce period has elapsed without a change in input,
-- so output the debounced value.
if counter_snapshot = counter then
output <= previous_input;
end if;
-- If the input has changed, save a snapshot of the counter.
if not(input = previous_input) then
counter_snapshot := counter;
end if;
previous_input := input;
end if;
end process;
end;
--
-- Bus Debouncer (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Debouncer is
generic
(
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
bus_in: in std_logic_vector(bus_size - 1 downto 0);
bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end;
architecture V1 of Debouncer is
component DebouncerBit is
port
(
clock: in std_logic;
counter: in integer;
input: in std_logic;
output: out std_logic
);
end component;
-- One counter to be shared by all debouncers.
-- Each debouncer takes a snapshot of the count value when its input changes value.
signal counter: integer := 0;
begin
-- Create the debounce period.
process(clock)
begin
if rising_edge(clock) then
if counter = timeout then
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
DebouncerGen: for i in 0 to bus_size - 1 generate
begin
Debounce: DebouncerBit
port map
(
clock => clock,
counter => counter,
input => bus_in(i),
output => bus_out(i)
);
end generate;
end;
SynchroniseDebounce.vhd
--
-- SynchroniseDebounce
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SynchroniseDebounce is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
);
end;
architecture V1 of SynchroniseDebounce is
component Synchroniser is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
rise_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
fall_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
);
end component;
component Debouncer is
generic
(
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
bus_in: in std_logic_vector(bus_size - 1 downto 0);
bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end component;
signal sync_bus_out: std_logic_vector(bus_size - 1 downto 0);
signal rise_bus_out: std_logic_vector(bus_size - 1 downto 0);
signal fall_bus_out: std_logic_vector(bus_size - 1 downto 0);
begin
Synchroniser_Inst: Synchroniser
generic map
(
reg_size => REG_SIZE, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
async_bus_in => async_bus_in,
sync_bus_out => sync_bus_out, -- Goes to Debouncer_Inst
rise_bus_out => rise_bus_out,
fall_bus_out => fall_bus_out
);
Debouncer_Inst: Debouncer
generic map
(
timeout => TIMEOUT, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
bus_in => sync_bus_out, -- From Synchroniser_Inst
bus_out => db_sync_bus_out
);
end;
Testbench.vhd
--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity testbench is
end;
architecture V1 of testbench is
component SynchroniseDebounce is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end component;
constant NUM_SWITCHES: integer := 16;
constant NUM_PUSH_BUTTONS: integer := 4;
signal switches_async, switches_db_sync: std_logic_vector(NUM_SWITCHES - 1 downto 0) := (others => '0');
signal push_buttons_async, push_buttons_db_sync: std_logic_vector(NUM_PUSH_BUTTONS - 1 downto 0) := (others => '0');
constant REG_SIZE: integer := 3;
constant BUS_SIZE: integer := NUM_SWITCHES + NUM_PUSH_BUTTONS;
signal async_bus_in, db_sync_bus_out, rise_bus_out, fall_bus_out: std_logic_vector(BUS_SIZE - 1 downto 0) := (others => '0');
constant TIMEOUT: integer := 10; -- Number of clock cycles in debounce period.
signal clock: std_logic;
constant PERIOD: time := 10 ns; -- System clock frequency.
signal stop_clock: boolean := false;
begin
ClockGenerator: process
begin
while not stop_clock loop
clock <= '0';
wait for PERIOD / 2;
clock <= '1';
wait for PERIOD / 2;
end loop;
wait;
end process ClockGenerator;
Stimulus: process
variable seed1, seed2: positive;
variable rrand: real;
variable irand: integer;
begin
switches_async <= (others => '0');
push_buttons_async <= (others => '0');
wait for 23 ns;
-- Some noisy inputs.
seed1 := 1;
seed2 := 1;
for n in 1 to 500 loop
for i in 0 to NUM_PUSH_BUTTONS - 1 loop
uniform(seed1, seed2, rrand);
irand := integer(round(rrand));
if irand = 0 then
push_buttons_async(i) <= '0';
else
push_buttons_async(i) <= '1';
end if;
end loop;
for i in 0 to NUM_SWITCHES - 1 loop
uniform(seed1, seed2, rrand);
irand := integer(round(rrand));
if irand = 0 then
switches_async(i) <= '0';
else
switches_async(i) <= '1';
end if;
end loop;
wait for 1 ns;
end loop;
-- Pulse the push buttons.
for i in 0 to NUM_PUSH_BUTTONS - 1 loop
push_buttons_async(i) <= '1';
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
push_buttons_async(i) <= '0';
end loop;
-- Pulse the switches.
for i in 0 to NUM_SWITCHES - 1 loop
switches_async(i) <= '1';
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
switches_async(i) <= '0';
end loop;
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
stop_clock <= true;
wait;
end process Stimulus;
DUT: SynchroniseDebounce
generic map
(
reg_size => REG_SIZE, -- Override default value.
timeout => TIMEOUT, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
async_bus_in => async_bus_in,
db_sync_bus_out => db_sync_bus_out
);
-- Connect the input switches and input push buttons to the asynchronous bus input.
async_bus_in <= switches_async & push_buttons_async;
-- Connect the debounced and synchronised output bus to the debounced synchronised switches and push buttons.
switches_db_sync <= db_sync_bus_out(NUM_SWITCHES + NUM_PUSH_BUTTONS - 1 downto NUM_PUSH_BUTTONS);
push_buttons_db_sync <= db_sync_bus_out(NUM_PUSH_BUTTONS - 1 downto 0);
end;
Testbench Waveforms
Bit 2 of the debounced synchronous bus (db_sync_bus_out) goes high only when a long enough pulse is applied to the input (async_bus_in).
I'm working with a feed forward neural network developed by David Aledo (See OpenCores project Artificial Neural Network (ANN)) and I am having trouble with initializing RAM arrays in instances generated by the code.
The code generates layers of the neural network as instances. Each of these instances has block RAM associated with a layer weight matrix. This RAM is represented in the code as an array of arrays of std_logic_vector as shown below:
type ramd_type is array (NumN-1 downto 0) of std_logic_vector(NbitW -1 downto 0);
type layer_ram is array (NumIn-1 downto 0) of ramd_type;
where NumN and NumIN are layer-dependent and NbitW is constant.
What I want to do is to initialize this RAM with a constant. To do this I've created a package containing the following:
type ramd_type0 is array (33 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram0 is array (26 downto 0) of ramd_type0;
type ramd_type1 is array (4 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram1 is array (33 downto 0) of ramd_type1;
type ramd_type2 is array (0 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram2 is array (4 downto 0) of ramd_type2;
constant w0 : layer_ram0 := (others => (others => (others => '0')));
constant w1 : layer_ram1 := (others => (others => (others => '0')));
constant w2 : layer_ram2 := (others => (others => (others => '0')));
Inside the layer Entities I've declared functions which select the constant apropriate to the layer number generic Lnum:
function w_init(LNum : natural) return layer_ram is
begin
if LNum = 0 then
return layer_ram(w0);
elsif LNum = 1 then
return layer_ram(w1);
elsif LNum = 2 then
return layer_ram(w2);
else
return layer_ram(w2);
end if;
end w_init;
Where layer_ram is defined like above.
When analyzing with GHDL I get the following error:
conversion not allowed between not closely related types
In Modelsim I get this one:
Illegal type conversion from work.wb_init.layer_ram0 to layer_ram (array element type difference).
I get that the problem is that according to the simulators the layer_ram and layer_ram0 are not closely related and it's because the array elements have different types ramd and ramd0. For me this seems to be against the 1993 standard which states that array types are closely related when:
-- For each index position, the index types are either the same or are closely related;
Am I right? How could I initialize these arrays with constants without changing the layer_ram type into an array of std_logic_vectors?
edit:
A minimal working example that reproduces my problem can be viewed here: https://gist.github.com/jstefanowicz/e4f43a822cf5dd46c2668bfffa33c66c
library ieee;
use ieee.std_logic_1164.all;
library work;
package wb_init is
constant NbitW : natural := 18;
type ramd_type0 is array (1 downto 0) of std_logic_vector(NbitW-1 downto 0);
type ramd_type1 is array (2 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram0 is array (3 downto 0) of ramd_type0;
type layer_ram1 is array (4 downto 0) of ramd_type1;
constant w0 : layer_ram0 := (others => (others => (others => '0')));
constant w1 : layer_ram1 := (others => (others => (others => '0')));
end wb_init ;
--- test_gen:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
library work;
use work.wb_init.all;
entity test_gen is
generic
(
LNum : natural ;
NumN : natural := 8;
NumIn : natural := 8
);
port
(
inputs : in std_logic_vector(NbitW-1 downto 0);
outputs : out std_logic_vector(NbitW-1 downto 0)
);
end test_gen;
architecture beh of test_gen is
type ramd_type is array (NumN-1 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram is array (NumIn-1 downto 0) of ramd_type;
function w_init(LNum : natural) return layer_ram is
begin
if LNum = 0 then
return layer_ram(w0);
elsif LNum = 1 then
return layer_ram(w1);
else
return layer_ram(w1);
end if;
end w_init;
signal lram : layer_ram := w_init(LNum);
begin
outputs<= inputs;
end beh;
--- test_gen_tb:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
library work;
use work.wb_init.all;
entity test_gen_tb is
end test_gen_tb;
architecture beh of test_gen_tb is
component test_gen is
generic
(
LNum : natural := 0;
NumN : natural := 64;
NumIn : natural := 8
);
port
(
inputs : in std_logic_vector(NbitW-1 downto 0);
outputs : out std_logic_vector(NbitW-1 downto 0)
);
end component;
type gen_ar is array (1 downto 0) of natural;
signal NumN_ar : gen_ar := (2,3);
signal NumIn_ar : gen_ar := (4,5);
signal inputs,outputs : std_logic_vector(NbitW-1 downto 0);
begin
test_gen_inst:
for i in 0 to 1 generate
test_gen
generic map (
LNum => i,
NumN => NumN_ar(i),
NumIn => NumIn_ar(i)
)
port map (
inputs => inputs,
outputs => outputs
);
end generate;
end beh;
I finally managed to initialize the array of arrays by assigning it element by element in the function winit. Here is a fix for the minimal example posted above: (https://gist.github.com/jstefanowicz/abad35de9b0a930033e54ed0deeed771)
library ieee;
use ieee.std_logic_1164.all;
library work;
package wb_init is
constant NbitW : natural := 18;
type ramd_type0 is array (1 downto 0) of std_logic_vector(NbitW-1 downto 0);
type ramd_type1 is array (2 downto 0) of std_logic_vector(NbitW-1 downto 0);
type layer_ram0 is array (3 downto 0) of ramd_type0;
type layer_ram1 is array (4 downto 0) of ramd_type1;
constant w0 : layer_ram0 := (others => (others =>(others =>'0')));
constant w1 : layer_ram1 := (others => (others =>(others =>'0')));
end wb_init ;
--- test_gen:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
library work;
use work.wb_init.all;
entity test_gen is
generic
(
LNum : natural ;
NumN : natural ;
NumIn : natural
);
port
(
inputs : in std_logic_vector(17 downto 0);
outputs : out std_logic_vector(17 downto 0)
);
end test_gen;
architecture beh of test_gen is
type ramd_type is array (NumN-1 downto 0) of std_logic_vector(17 downto 0);
type layer_ram is array (NumIn-1 downto 0) of ramd_type;
function w_init(LNum : natural) return layer_ram is
variable tmp_arr : layer_ram ;
begin
if LNum = 0 then
for i in 0 to NumIn-1 loop
for j in 0 to NumN-1 loop
tmp_arr(i)(j) := w0(i)(j);
end loop;
end loop;
elsif LNum = 1 then
for i in 0 to NumIn-1 loop
for j in 0 to NumN-1 loop
tmp_arr(i)(j) := w1(i)(j);
end loop;
end loop;
else
for i in 0 to NumIn-1 loop
for j in 0 to NumN-1 loop
tmp_arr(i)(j) := (others => '0');
end loop;
end loop;
end if;
return tmp_arr ;
end w_init;
signal lram : layer_ram := w_init(LNum);
begin
outputs<= inputs;
end beh;
--- test_gen_tb:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
--library work;
--use work.wb_init.all;
entity test_gen_tb is
end test_gen_tb;
architecture beh of test_gen_tb is
component test_gen is
generic
(
LNum : natural ;
NumN : natural ;
NumIn : natural
);
port
(
inputs : in std_logic_vector(17 downto 0);
outputs : out std_logic_vector(17 downto 0)
);
end component;
type gen_ar is array (1 downto 0) of natural;
signal NumN_ar : gen_ar := (3,2);
signal NumIn_ar : gen_ar := (5,4);
signal inputs,outputs : std_logic_vector(17 downto 0);
begin
test_gen_inst:
for i in 0 to 1 generate
tg:test_gen
generic map (
LNum => i,
NumN => NumN_ar(i),
NumIn => NumIn_ar(i)
)
port map (
inputs => inputs,
outputs => outputs
);
end generate;
end beh;
This is what i am required to do. - Show the following repeating sequence on the onboard LEDs (Leftmost LED is MSB):
o 0x00 -> 0x03 -> 0x40 -> 0xE8 -> 0x00 -> …
- LED transitions must be visible
- Command the sequence to start/pause upon pressing BTN0
- Upon power up the sequence is paused
This is what i have so far:
entity vhdl_primer is
port ( clk, rst_n, btn0: in std_logic;
LED: out std_logic_vector (7 downto 0)
);
end vhdl_primer;
architecture behavior of vhdl_primer is
type statetype is (S0, S1, S2, S3);
signal currentstate, nextstate: statetype;
begin
statereg: process(clk, rst)
begin
if (rst='0') then
currentstate <= S0; --initial state
elsif rising_edge(clk) then
currentstate <= nextstate;
end if;
end process;
comblogic: process(currentstate, btn0)
begin
LED <= '0';
case currentstate is
when S0 =>
LED <= '0'; -- led off
nextstate <= S1;
when S1 =>
if (btn0='1') then
nextstate <= S2;
else
nextstate <= S1;
end if;
when S2 =>
LED <= '1'; -- led 0x40
nextstate <= S3;
when S3 =>
LED <= '1'; -- led 0xE8
if (btn0='1') then
nextstate <= S0;
else
nextstate <= S3;
end if;
when others =>
end case;
end process;
end behavior;
I'm a beginner at VHDL and I have problems when to decide whether I should initialize my signal or not...
Here's an exemple :
entity tatoo is
port (
clk, reset : in std_logic;
opcode : in std_logic_vector(2 downto 0);
A, B : in std_logic_vector(3 downto 0);
F : out std_logic_vector(3 downto 0)
);
architecture toota of tatoo is
signal Q : std_logic_vector(3 downto 0);
begin
process (clk, reset) -- register for F
begin
if(reset = '1')
then F <= "0000";
elsif(Clk'event and Clk = '1')
then F <= Q;
end if;
end process;
process(opcode, A, B) -- ALU
begin
Should I initialize Q here ? => Q <= "0000"; ?
case opcode is
when "00" =>
Q <= "0000";
when "01" =>
Q <= A-B;
when "10" =>
Q <= B-A;
when "11" =>
Q <= A xor B;
end case;
end process;
Thanks a lot,
You need to initialise it somewhere, or you'll get a latch. Your suggestion is fine (though Q <= (others => '0') is more future-proof), of you could have a default/others branch in the case statement, where you give Q a default value. Basically, when you have a combinatorial process like this one, make sure that anything your drive always has a defined value whatever the value of the inputs may be. If not, you're inferring memory of some sort.
So, long story short, I'm trying to make a processor of sorts ('of sorts' is put there for a reason, but let's not go into details), and I'm running into one problem which pretty much ruins the whole thing.
Namely, in this piece of code :
programmProcess: process (clk,rst) is
variable counter : natural;
begin
if (rst = '1') then
counter := 0;
elsif (clk'event and clk = '1' and pm_nEn= '1') then
RAM(counter) <= data; --This is where the issue is
counter := counter + 1;
if (counter = 1024) then
counter := 0;
end if;
end if;
data <= "ZZZZZZZZZZZZZZZZ";
end process programmProcess;
... and this is the testbench process :
stim_proc1: process
begin
rst <= '1';
pm_nEn <= '1';
wait for clk_period;
rst <= '0' ;
data <="0000111110111001";
wait for clk_period;
data <="0000111010111001";
wait for clk_period;
data <= "ZZZZZZZZZZZZZZZZ";
pm_nEn <= '0';
wait for 10*clk_period;
wait;
end process;
... where RAM is an array of 1024 vectors of 16 bits, data is a 16 bit inout vector and pm_nEn is a single bit which basically allows the RAM to be filled with values.
The idea is that RAM(counter) gets values from the data vector, which is manually fed values in the testbench, but this doesn't happen. Namely, all of RAM's values just stay "UUUUUUUUUUUUUUUU", despite data having the required values. Even when it's first evaluated and counter is 0, RAM(0) is undefined.
I'm using the ISE suite, and I tried simulating, and then just tracing through all the steps, and the step where RAM(counter) should get assigned a value is shown, the data vector does have the value which is added manually from the testbench, but RAM still doesn't get any values.
So, the question is basically - why does this happen? Why doesn't RAM get its values assigned?
Also, here's the full VHDL and testbench (which was conveniently generated by ISE) in google doc form -
VHDL
Testbench
Assigning "zzzz" to Data within the main process should do no harm (although in the current code fragment, it is redundant).
One thing that may lead to problems in synthesis is:
elsif (clk'event and clk = '1' and pm_nEn= '1') then
... actions
end if;
To match the pattern a synthesis tool expects for a clocked process, it is better to write
elsif clk'event and clk = '1' then
if pm_nEn= '1' then
... actions
end if;
end if;
though I would expect the two versions to be equivalent in simulation.
There isn't another driver on RAM in another process, is there?
EDIT: apparently there IS a separate driver setting RAM in another process.
Now from a software perspective, you might think that is OK because one process drives when en = '0' and the other when en = '1'. However you can't make the driver hardware appear and disappear at the flick of a boolean; there are always two drivers on the RAM signal. And the one you aren't explicitly using is holding the value as "UUUU".
The best thing to do is to eliminate one of them. Make one process or the other responsible for writing to RAM. I'll use this process; you may find the design is cleaner and tidier using the other process; that's OK too.
It's easy : just reorganise this process along these lines:
elsif clk'event and clk = '1' then
if pm_nEn= '1' then
... actions
else -- or elsif external_enable then
RAM(external_address) <= external_data;
end if;
end if;
Incidentally, when you see an expression like RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3))))))) <= std_logic_vector(signed(OP1) + signed(OP2));
it's usually a clue that some things have been declared as the wrong types in the first place : for example, OP1 and OP2 should possibly be signed, R should be an array of integers, and so on. If you can't eliminate all the ugliness, you can at least stop it interfering with the main program flow using helper functions (possibly in a package):
function gen_reg_addr(IR : Register) return natural is ...
RAM(gen_reg_addr(IR)) <= ...
I imagine that the problem is with the multitude of places where you write to data. It wouldn't surprise me if you are having multiple statements write to the same variable, and that should cause the simulator to give it a value of Z.
For example, one of your processes looks like this:
glavenProcess: process (clk,rst) is
begin
data <= "ZZZZZZZZZZZZZZZZ";
...
end process;
Sorry for the delay, i found your problem, change RAM to variable instead of Signal, check VHDL manual to see the differences between Signals and variables:
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity mp is
port(
clk, rst, pm_nEn : in std_logic;
data : inout std_logic_vector(15 downto 0);
adr : out std_logic_vector(15 downto 0);
rd_nwr : out std_logic
);
end entity mp;
architecture beh of mp is
signal PC, IR, OP1, OP2 : std_logic_vector(15 downto 0);
type csignals is array(7 downto 0) of std_logic_vector(15 downto 0);
signal R: csignals;
type memory_array is array(1024 downto 0) of std_logic_vector(15 downto 0);
shared variable RAM: memory_array;
begin
glavenProcess: process (clk,rst) is
begin
data <= "ZZZZZZZZZZZZZZZZ";
if (rst = '1') then
PC <= "0000000000000000";
R(0) <= "0000000000000000";
R(1) <= "0000000000000000";
R(2) <= "0000000000000000";
R(3) <= "0000000000000000";
R(4) <= "0000000000000000";
R(5) <= "0000000000000000";
R(6) <= "0000000000000000";
R(7) <= "0000000000000001";
elsif (clk'event and clk = '1' and pm_nEn= '0') then
IR <= RAM(to_integer(unsigned(PC)));
if (IR(15) = '0') then
if (IR(14) = '0') then
OP1 <= R(to_integer(unsigned(IR(11 downto 9))));
else
OP1 <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(11 downto 9)))))));
end if;
if (IR(13) = '0') then
OP2 <= R(to_integer(unsigned(IR(8 downto 6))));
else
if (IR(0) = '0') then
adr <= R(to_integer(unsigned(IR(8 downto 6))));
OP2 <= data;
rd_nwr <= '1' ;
else
OP2 <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(8 downto 6)))))));
end if;
end if;
if (IR(2) = '1') then OP2 <= not OP2 ; end if;
if (IR(1) = '1') then OP1 <= not OP1 ; end if;
if (IR(0) = '0') then
if (IR(12) = '0') then
R(to_integer(unsigned(IR(5 downto 3)))) <= std_logic_vector(signed(OP1) + signed(OP2));
else
RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3))))))) := std_logic_vector(signed(OP1) + signed(OP2));
end if;
else
if (IR(12) = '0') then
adr <= R(to_integer(unsigned(IR(5 downto 3))));
else
adr <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3)))))));
end if;
data <= std_logic_vector(signed(OP1) + signed(OP2));
rd_nwr <= '0' ;
end if;
PC <= std_logic_vector(unsigned(PC) + 1);
else
if (IR(8 downto 7) = "00") then
if (R(to_integer(unsigned(IR(11 downto 9)))) = R(to_integer(unsigned(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "01") then
if (R(to_integer(signed(IR(11 downto 9)))) > R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "10") then
if (R(to_integer(signed(IR(11 downto 9)))) < R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "11") then
if ( not R(to_integer(signed(IR(11 downto 9)))) = R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
end if;
end if;
end if;
end process glavenProcess;
programmProcess: process (clk,rst) is
variable counter : natural;
begin
if (rst = '1') then
counter := 0;
else
if (clk'event and clk = '1' and pm_nEn= '1') then
RAM(counter) := data;
counter := counter + 1;
if (counter = 1024) then counter := 0; end if;
end if;
end if;
end process programmProcess;
end architecture beh;
Testbench:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
-- Add your library and packages declaration here ...
entity mp_tb is
end mp_tb;
architecture TB_ARCHITECTURE of mp_tb is
-- Component declaration of the tested unit
component mp
port(
clk : in STD_LOGIC;
rst : in STD_LOGIC;
pm_nEn : in STD_LOGIC;
data : inout STD_LOGIC_VECTOR(15 downto 0);
adr : out STD_LOGIC_VECTOR(15 downto 0);
rd_nwr : out STD_LOGIC );
end component;
-- Stimulus signals - signals mapped to the input and inout ports of tested entity
signal clk : STD_LOGIC;
signal rst : STD_LOGIC;
signal pm_nEn : STD_LOGIC;
signal data : STD_LOGIC_VECTOR(15 downto 0);
-- Observed signals - signals mapped to the output ports of tested entity
signal adr : STD_LOGIC_VECTOR(15 downto 0);
signal rd_nwr : STD_LOGIC;
-- Add your code here ...
begin
-- Unit Under Test port map
UUT : mp
port map (
clk => clk,
rst => rst,
pm_nEn => pm_nEn,
data => data,
adr => adr,
rd_nwr => rd_nwr
);
clock:process is
begin
clk<='0';
wait for 10 ns;
clk<='1';
wait for 10 ns;
end process;
process is
begin
rst <= '1';
pm_nEn <= '1';
wait for 25 ns;
rst <= '0' ;
data <="0000111110111001";
wait for 45 ns;
data <="0000111010111001";
wait for 55 ns;
data <= "ZZZZZZZZZZZZZZZZ";
pm_nEn <= '0';
wait;
end process;
end TB_ARCHITECTURE;
configuration TESTBENCH_FOR_mp of mp_tb is
for TB_ARCHITECTURE
for UUT : mp
use entity work.mp(beh);
end for;
end for;
end TESTBENCH_FOR_mp;