VHDL – Troubleshooting Wrong Outputs in VHDL Entity

programmable-logicsimulationvhdlxilinx

I have lessons about VHDL in one of my university class and I have to write simple entity which will generate clock from 1MHz source. I'm using CoolRunner-II CPLD Starter Kit with ISE Webpack 13.1.

When I run simulation of my code, I've got odd results. I have no idea, where the problem is. My VHDL entity looks like this:

entity clock is
  Port ( clk_in : in  STD_LOGIC;
    clk_1M : out  STD_LOGIC;
    clk_500k : out  STD_LOGIC;
    clk_100k : out  STD_LOGIC;
    clk_1k : out  STD_LOGIC;
    clk_1hz: out STD_LOGIC);
end clock;

Input is 1MHz signal from oscilator and I want to create 1MHz, 500kHz, 100kHz, 1kHz and 1Hz output signal. I defined several signals:

signal c100k: std_logic_vector(3 downto 0) := (others => '0' );
signal c1k:  std_logic_vector(9 downto 0) := (others => '0' );
signal c1hz: std_logic_vector(9 downto 0) := (others => '0' );
--
signal c500k_out: std_logic := '0';
signal c100k_out: std_logic := '0';
signal c1k_out: std_logic := '0';
signal c1hz_out: std_logic := '0';

And finally, my code is:

process (clk_in) begin
  if clk_in'event and clk_in = '1' then
    -- 500kHz
    c500k_out <= not c500k_out;
  end if;
end process;

process (clk_in) begin
  if clk_in'event and clk_in = '1' then
    -- 100kHz
    c100k <= c100k + '1';
    if c100k = X"A" then
      c100k <= (others => '0' );
      c100k_out <= '1';
    else
      c100k_out <= '0';
    end if;
  end if;
end process;

--
-- Code for 1kHz and 1Hz is same as 100kHz
--

clk_1M <= clk_in;           -- Clock source 1Mhz
clk_500k <= c500k_out;  -- Clock source 500kHz
clk_100k <= c100k_out;  -- Clock source 100kHz
clk_1k <= c1k_out;      -- Clock source 1kHz
clk_1hz <= c1hz_out;        -- Clock source 1Hz

When I run simulation, I got this odd results:

Clock simulation

What is wrong with my code?

Best Answer

The first thing I see, which isn't likely causing your problem, is a lack of any kind of reset. ModelSim does not automatically declare all signals to be '0', and trying to say s <= not s when s is not 1 or 0 is not going to give you what you want. I see you declaring them all '0' at the top but a proper circuit would have a reset input that you briefly drive at the start of your simulation.

Your basic counter process looks wrong; basically when the count reaches ten you're outputting a '1' and for the other 9/10ths of the time you're outputting a '0' (for the 100k example, the 1Hz example would be a 1us pulse high and a 999us low time. I think what you want is something like this:

gen_clk100: process(clk, rst)
begin
    if rising_edge(clk) then
        if count = 10 then
            clk100 <= not clk100;
            count <= 0;
        else
            count <= count + 1;
        end if;
    end if;

    if rst = '1' then
        clk100 <= '0';
        count <= 0;
    end if;
end process;

Note several things:

  • I'm not incrementing all the time. I increment if the count is not at its max, and increment otherwise.

  • I'm toggling the output clock when the maximum count is reached

  • I've included an asynchronous reset (with synchronous clear) -- this ensures that your signals initialize correctly and have no metastability problems when reset is released.

You also mention that the other sections are the same. I think you're having a problem with multiple drivers like Yann mentioned. Check and double-check your code to make sure you are not assigning the output in two different processes, because that is exactly what the simulation is saying you're doing. Better to either make a generic counter module or...

Why so many counters? All your frequency dividers can be handled with a single count and then "peeling off" the conditions to do the divisions you're interested in. You could also have a single counter and use the mod (modulus) operator to handle each divider case.

Finally, I'd also use real or integer types for the count instead of std_logic_vectors but that's just me.

Related Topic