Author Topic: VHDL CODE QUESTION  (Read 7693 times)

0 Members and 1 Guest are viewing this topic.

Offline AustinTopic starter

  • Newbie
  • Posts: 4
  • Country: jp
VHDL CODE QUESTION
« on: April 03, 2024, 02:12:38 am »
Hi ! I'm new to the forum.If I'm doing something wrong,please tell me.

I'm trying to make a 32bit counter in a FPGA.
What I want to do is measure pulse with.
I wrote the code below and came up with a question.
When the rst is 1 FPGA circuitry will try to do TMP<=cnt; and cnt <=X"00000000"; at the same time.
At least that's what I thought.
Whill this code run stably and reliably ?



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Top is
    Port ( clk : in STD_LOGIC;
           rst : in STD_LOGIC;
           count : out STD_LOGIC_VECTOR(31 downto 0);
           hold : out STD_LOGIC_VECTOR(31 downto 0)
           );
end Top;

architecture Behavioral of Top is
    signal cnt : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
   signal  TMP : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
begin
    process(clk, rst)
    begin
        if rst = '1' then
        TMP<=cnt;
        cnt <=X"00000000";
        elsif rising_edge(clk) then
            cnt <= cnt + 1;
        end if;
    end process;

    count <= cnt;
    hold <= TMP;
end Behavioral;
 

Offline Daixiwen

  • Frequent Contributor
  • **
  • Posts: 367
  • Country: no
Re: VHDL CODE QUESTION
« Reply #1 on: April 03, 2024, 10:46:20 am »
This may work in a simulator at first, but on the next clock edge after you put rst to 1 the simulator will execute the process again, go into the if rst = '1' branch, and copy the value of cnt (now 0) into TMP.
In the actual implementation in an FPGA, TMP and cnt will be asynchronously connected together and TMP will continuously read cnt as long as rst = '1' so you will end up with TMP being 0 anyway.

The asynchronous branch with the if rst = '1' should only contain initial values for your signals, that should be applied during a reset. All the rest of the logic should be in the clock part of the process. I would suggest to have a separate 'load' signal to load the counter value, independently to the reset signal.
Code: [Select]
entity Top is
    Port ( clk : in STD_LOGIC;
           rst : in STD_LOGIC;
           load : in STD_LOGIC;
           count : out STD_LOGIC_VECTOR(31 downto 0);
           hold : out STD_LOGIC_VECTOR(31 downto 0)
           );
end Top;

architecture Behavioral of Top is
    signal cnt : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
   signal  TMP : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
begin
    process(clk, rst)
    begin
        if rst = '1' then
            TMP<=X"00000000";
            cnt <=X"00000000";
        elsif rising_edge(clk) then
            if load = '1' then
                TMP <= cnt;
                cnt <= X"00000000";
            else
                cnt <= cnt + 1;
            end if;
        end if;
    end process;

    count <= cnt;
    hold <= TMP;
end Behavioral;
A few other suggestions:
  • avoid using STD_LOGIC_ARITH and STD_LOGIC_UNSIGNED. Those are non standard packages, and will cause confusion if you ever need to mix unsigned and signed vector. Use NUMERIC_STD instead and the dedicated signed and unsigned types instead of std_logic_vector to make counters.
  • if your 'load' pulse signal is external to the FPGA and not synchronized with the clock, you will need to register it a couple of times to avoid metastability problems. If you google "metastability filter" you should find some good articles on why this is necessary and how to implement them.
EDIT: sorry I only noticed after I replied that the OP double posted his question
« Last Edit: April 03, 2024, 11:00:29 am by Daixiwen »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf