I am trying to use 3 components of the same type under a main module and the displayed output value is uninitialized. It seems that somehow the code I wrote is forcing certain values that contradict the logic I intended.
The problem is in the CLR signal. It's supposed to reset the counters values when all of them have the same digit as the TOP_COUNT
input (value of 2 in the testbench in the screensot below).
The component:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity counter is
Port ( EN : in STD_LOGIC;
CLR : INOUT STD_LOGIC :='0'; -- WAS BUFFER
clk_5 : in STD_LOGIC;
RST : in STD_LOGIC;
TOP_COUNT : in STD_LOGIC_VECTOR (3 downto 0);
TOP_CNT_REACH : out STD_LOGIC;
REACH_9 : out STD_LOGIC;
Q : inout integer range 0 to 9); -- was buffer
end counter;
architecture Behavioral of counter is
signal top_cnt: integer range 0 to 9;
signal temp_CLR: std_logic:='0';
begin
top_cnt <= to_integer(unsigned(TOP_COUNT));
process (clk_5)
begin
if rising_edge(clk_5) then
if RST = '1' or CLR = '1' OR temp_CLR = '1' then -- CLR should rise for 1 clk_5 cycle
Q <= 0;
elsif EN = '1' then
Q <= Q + 1;
end if;
end if;
end process;
OUTPUT_UPDATES:
process(Q, top_cnt)
begin
if Q = top_cnt then
TOP_CNT_REACH <= '1';
else
TOP_CNT_REACH <= '0';
end if;
if Q = 9 then
REACH_9 <= '1';
temp_CLR <= '1';
else
REACH_9 <= '0';
temp_CLR <= '0';
end if;
end process;
The logic part that uses the component:
LSD: counter port map (en=>en(0), clr =>clr(0), clk_5=>clk5, rst=>reset, top_count=>top_count,
top_cnt_reach=>top_cnt_reach(0), reach_9=>reach_9(0), Q=>Q0);
ISD: counter port map (en=>en(1), clr =>clr(1), clk_5=>clk5, rst=>reset, top_count=>top_count,
top_cnt_reach=>top_cnt_reach(1), reach_9=>reach_9(1), Q=>Q1);
MSD: counter port map (en=>en(2), clr =>clr(2), clk_5=>clk5, rst=>reset, top_count=>top_count,
top_cnt_reach=>top_cnt_reach(2), reach_9=>reach_9(2), Q=>Q2);
LSD_LOGIC:
EN(0) <= '1';
process(clk5) -- REACH_9(0)
begin
if clk5 = '1' then
if REACH_9(0) = '1' then
CLR(0) <= '1';
EN(1) <= '1';
else
CLR(0) <= '0';
EN(1) <= '0';
end if;
end if;
end process;
ISD_LOGIC:
process(clk5) -- REACH_9(1)
begin
if clk5='1' then
if REACH_9(1) = '1' then
CLR(1) <= '1';
EN(2) <= '1';
else
CLR(1) <= '0';
EN(2) <= '0';
end if;
end if;
end process;
MSD_LOGIC:
process(clk5) -- TOP_CNT_REACH(0)
begin
if clk5 = '1' then
if (top_cnt_reach = "111") then
clr <= "111"; -- clr(2) <= '1';
else
clr(2) <= '0';
end if;
end if;
end process;
The simulation results:
I also tested the component with a testbench for one unit of the component and the results were good. But when I combined the 3 components under the main module problems appeared.
TLDR: Your signal CLR(2 downto 0) has multiple drivers on it.
Think of each independent assignment you do as the output of a hardware gate - in VHDL we also call this a driver. For a process each signal that you do an assignment to in that process has a single driver on it - even if there are multiple assignments to that signal in the process.
Your components each have CLR as an inout with the value initialized to '0'. Given that there are assignments to CLR inside that design they will drive a '0'. To fix this, make it an IN.
entity counter is
Port ( EN : in STD_LOGIC;
CLR : in STD_LOGIC :='0'; -- WAS INOUT
In the following process, you drive all elements of CLR in the first part of the if branch. This process will initially drive CLR(1 downto 0) to a U and then once top_cnt_reach = "111" it will drive them all to a '1'. You can fix this by only driving clr(2) in this process as shown below:
MSD_LOGIC:
process(clk5) -- TOP_CNT_REACH(0)
begin
if clk5 = '1' then
if (top_cnt_reach = "111") then
clr(2) <= '1';
else
clr(2) <= '0';
end if;
end if;
end process;
Are you trying to create registers (aka flip-flops) or latches? If you are intending to create registers, then code the rising edge of clock as one of the following:
-- preferred choice for readability
if rising_edge(Clk5) then
-- also correct
if Clk5 = '1' and Clk5'event then
If you are intending to create latches, you are missing a couple of signals from the sensitivity lists. Latches are rare for this sort of application so I will assume not.
You could put all three processes together as follows. This allows you to do an assignment to all 3 bits - but be careful as I did it first so it has lower priority to the assignments of clr(1 downto 0)
LSD_LOGIC:
EN(0) <= '1';
process(clk5) -- REACH_9(0)
begin
if rising_edge(clk5) then
if (top_cnt_reach = "111") then
clr <= "111"; -- clr(2) <= '1';
else
clr(2) <= '0';
end if;
if REACH_9(0) = '1' then
CLR(0) <= '1';
EN(1) <= '1';
else
CLR(0) <= '0';
EN(1) <= '0';
end if;
if REACH_9(1) = '1' then
CLR(1) <= '1';
EN(2) <= '1';
else
CLR(1) <= '0';
EN(2) <= '0';
end if;
end if;
end process;