具有启动功能的 VHDL 有限状态机计数器

VHDL finite state machine counter with start

我对 vhdl 很陌生,我正在尝试学习如何使用 vhdl 进行 FSM。 目前我需要一个代码,在一个固定的计数值之后,它会给我一个脉冲,以便启动第二个 FSM 块。 (我每 100 kHz 有一个重复信号,我需要对它进行计数并在固定数量的计数后释放该信号)。 实际上它作为免费 运行 工作,每次它看到这个信号,它就开始计数,但实际上我想添加一个 "start" 信号,所以它必须在看到这个信号后开始计数这个信号开始信号。

目前我的工作代码是:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

entity counter is
Port (
    signal_in : in STD_LOGIC := '0'; --segnale di start
    clk : in  STD_LOGIC; --clock di ingresso
    reset  : in  STD_LOGIC; --ff reset
    signal_out: out STD_LOGIC; --gate in uscita
    count_val: in std_logic_vector (7 downto 0);
    start : in STD_LOGIC := '0'


   );
end counter;

architecture behavioral of counter is
type state_type is (idle, count_up);
signal state : state_type;

begin
process (reset, clk, signal_in, start)
variable index : integer :=0;
variable countlen: integer;
variable count_v: std_logic;
variable countlen2 : std_logic;

begin

 countlen := to_integer(unsigned(count_val))-1;



if reset = '1' then  
  count_v := '0';
  index := 0;
  state <= idle;

else
--if start = '1' and
    --if rising_edge(clk) then
    if rising_edge(signal_in) then
    case state is
      when idle =>
        count_v :='0';
        index := 0;
        if (signal_in = '1') then
          state <= count_up;
          else
          state <= idle;
        end if;


      when count_up =>
        if(index < countlen) then
        state <=count_up;
        index := index + 1;
       elsif
        index = countlen then
        count_v := '1';
        state <=idle; 
        end if;        



      when others => null;
    end case;



  end if;
   end if;  

  signal_out <= count_v;

  end process; 


  end Behavioral;

任何使用 cose 与 "start = 1" 的尝试都将停止计数。 请问有人有什么建议吗?

此致

富尔维奥

欢迎使用 Whosebug。您的规范不是 100% 清楚。 signal_instart 有什么区别?根据您的代码和您的解释,它们似乎都充当启动器。

此外,您的代码有几个奇怪的地方:

  1. 您的进程似乎是同步进程,具有异步重置。它的敏感度列表应该只包含时钟和复位。它的正文应该是:

    process(clk, reset)
        <variable declarations>
    begin
        <NOTHING HERE>
        if reset = '1' then
            <reset code>
        elsif rising_edge(clk) then
            <regular code>
        end if;
        <NOTHING HERE>
    end process;
    
  2. 您正在使用 signal_in 作为时钟和逻辑信号。这非常奇怪。此外,您的 if (signal_in = '1') then 始终为真(在综合语义中),因此无用。

  3. 您正在声明时初始化变量 (index)。这不受某些合成器和硬件目标的支持。此外,即使在支持的情况下,它也只能在开机时工作。如果:

    • 您打算综合您的代码,
    • 您希望它可以跨合成器和硬件目标移植,
    • 您不仅要在加电时重新初始化信号和变量,而且要在断言复位输入时重新初始化,

    更喜欢真正的显式复位,并保证在上电后(或模拟开始时)始终断言以进行正确的首次初始化。

  4. 您声明变量 index 具有完整的整数范围,即最少 32 位,而 8 位就足够了。这可能会浪费硬件资源。

如果没有清晰和完整的规范,很难提出解决方案,但假设您只想在断言 start 之后并且仅在断言 signal_in 时才计算,以下可能是起点:

process (clk, reset)
    variable index: natural range 0 to 255;
begin
    if reset = '1' then
        state      <= idle;   
        signal_out <= '0';
        index      := 0;
    elsif rising_edge(clk) then
        case state is
            when idle =>
                signal_out <= '0';
                index      := 0;
                if start = '1' then
                    state <= count_up;
                end if;
            when others =>
                if signal_in = '1' then
                    if index = to_integer(unsigned(count_val)) - 1 then
                        state      <= idle;
                        signal_out <= '1';
                    else
                        index := index + 1;
                    end if;
                end if;
        end case;
    end if;
end process;

请注意,这实际上与您的时钟同步 clk。我怀疑您犯了一个非常常见的错误:当您想要在断言 signal_in 时增加计数器,您决定或多或少地使用 signal_in 作为时钟。这不是真正的同步和安全设计。在真正安全的同步设计中,您不使用逻辑信号作为时钟。你有很好识别的时钟,你只使用这些作为时钟。在您的情况下,只有一个时钟:clk。如果您想在断言逻辑信号时同步执行某些操作,请等待时钟的上升沿,然后测试逻辑信号并采取适当的操作。

感谢您的支持。 是的,关键是我需要 "decimate"(或计数)一个信号。 该信号的宽度为 50-100ns,并以 100kHz 的频率重复自身。 所以在我看来,这个信号将进入 "signal in"。我的 FPGA 是 Actel proasic3,时钟频率为 40 MHz。 在我的设置中,此信号将始终打开,但我不希望我的 FSM 在看到第一个 "signal in" 时开始计数,但仅当我发送 "start" 信号时才开始计数我指出。 (实际上,他们问我是否有可能将这个信号抽取到 65000 计数,所以我肯定需要使用 16 位向量而不是 8 位)。 异步重置在这里 "just in case" 我需要在一些数据记录的中间重置整个 fsm。

希望现在能更清楚这段代码应该做什么。

对于老屁,是的,我所有来自 fpga 外部的信号都将首先与一个简单的 2 ff 同步器与 FPGA 时钟同步