简化状态机以减少逻辑级别并满足时序要求

Simplifying A State Machine To Reduce Logic Levels and Meet Timing

我目前的设计不符合时序。我试过将它放在一个较慢的时钟上并对 inputs/outputs 进行流水线处理。问题总是一样的——逻辑层次太多。你们有没有关于让这个逻辑对时钟更友好的提示?

signal ctr : std_logic_vector(9 downto 0);
signal sig_bit_shift : std_logic_vector (15 downto 0);

begin

process(clk_p)
begin
    if rising_edge(clk_p) then
        if rst_i = '1' or nuke = '1' then
            ctr <= (others => '0'); 
            state <= ST_IDLE;
        elsif unsigned(event_settings) < 1 then -- disables
            state <= ST_IDLE;
        elsif unsigned(event_settings) = 1 then -- always on
            state <= ST_ENABLE;    
        else
            case state is
            when ST_IDLE =>
                if ctr = (unsigned(event)-2) then                     
                    state <= ST_ENABLE;
                elsif unsigned(ctr) = 1 and sig = '0' then --catches first word
                    state <= ST_ENABLE;                       
                elsif sig = '1' then
                    ctr <= ctr + 1;
                end if;
            when ST_ENABLE =>
                if s_sig = '1' then
                    state <= ST_IDLE;
                    if unsigned(s_evt) > 1 then
                        ctr <= (others => '0');
                    end if;
                end if;
            end case;
        end if;
    end if; 
end process;

更新:

process(clk_p)
begin
    if rising_edge(clk_p) then
        if rst_i = '1' or nuke = '1' then
            ctr <= x"00" & "10"; 
            state <= ST_IDLE;
        elsif settings = '1' then
            case state is
            when ST_IDLE =>
                if ctr = (unsigned(event)) then                     
                    state <= ST_ENABLE;
                elsif unsigned(ctr) = 1 and sig = '0' then --catches first word -- this is the part which when added, fails timing
                    state <= ST_ENABLE;                       
                elsif sig = '1' then
                    ctr <= ctr + 1;
                end if;
            when ST_ENABLE =>
                if s_sig = '1' then
                    state <= ST_IDLE;
                    if unsigned(s_evt) > 1 then
                        ctr <= X"00" & "10";
                    end if;
                end if;
            end case;
        end if;
    end if; 
end process;

我也认为它因信号来源而变慢:

sig <= sig_token when unsigned(SIG_DELAY) < 1 else (sig_bit_shift(to_integer(unsigned(SIG_DELAY)-1)));

process(clk_p) -- delays sig
begin
    if rising_edge(clk_p) then
        if rst = '1' then
            sig_bit_shift <= (others => '0');
        else
            sig_bit_shift <= l1a_bit_shift(sig_bit_shift'high-1 downto 0) & sig_token;
        end if;
    end if;
end process;

更新 2:

似乎一半的路由进入了上述延迟,所以我将尝试解决这个问题:

signal sig_del_en : std_logic;
signal sig_del_sel : integer; 

begin
process(clk_p)
begin
    if rising_edge(clk_p) then
        if unsigned(SIG_DELAY) = 0 then
            sig_del_en <= '0';
        else
            sig_del_en <= '1';
        end if;
        sig_del_sel <= to_integer(unsigned(SIG_DELAY)-1);
    end if;
end process;

   sig <= sig_token when sig_del_en = '0' else (sig_bit_shift(sig_del_sel));

一些 "slow" 操作是数组 = 需要比较参数中的所有位,以及 <> 需要对参数中的所有位进行减法论据。因此,如果在前一个循环中有足够的时间预先生成比较结果作为 std_logic,则您可以改进一个循环中的计时。它可能与这些相关:

  • unsigned(event_settings) < 1
  • unsigned(event_settings) = 1
  • ctr = (unsigned(event)-2)
  • unsigned(ctr) = 1
  • unsigned(s_evt) > 1

生成不同 std_logic 值的代码取决于相关信号的生成方式,但示例可以是:

process (clk) is
  variable event_settings_v : event_settings'range;
begin
  if rising_edge(clk) then
    ...
    event_settings_v := ... code for generating event_settings;  -- Variable with value
    event_settings <= event_settings_v;  -- Signal drive from variable
    if unsigned(event_settings_v) < 1 then
      unsigned_event_settings_tl_1 <= '1';
    else
      unsigned_event_settings_tl_1 <= '0';
    end if;
  end if;
end process;

然后可以将状态机中的代码 unsigned(event_settings) < 1 更改为 unsigned_event_settings_tl_1 = '1',如果此比较位于关键路径中,这可能会改善时序。

使用 rst_i = '1' 触发器上通常可用的异步复位也可以改善时序,因为它从同步部分移除了逻辑。它不太可能带来重大改进,但它通常是一个很好的设计实践,可以最大限度地延长同步逻辑的时间。异步复位通过如下编码风格使用:

process (rst_i, clk_p) is
begin
  if rst_i = '1' then
    ... Apply asynchronous reset value to signals
  elsif rising_edge(clk_p) then
    ... Synchronous update of signals