简化状态机以减少逻辑级别并满足时序要求
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
我目前的设计不符合时序。我试过将它放在一个较慢的时钟上并对 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