【问题标题】:VHDL - coding error of value outside the clock edgeVHDL - 时钟边沿之外的值编码错误
【发布时间】:2016-02-27 07:46:06
【问题描述】:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity RAM_controler is 
port(
      clk_50 : in std_logic;
      clk_baud : in std_logic;
      main_reset : in std_logic;
      enable: in std_logic; --active high write enable
      in_data : in std_logic_vector(7 downto 0);
      W_order : out std_logic; 
      R_order : out std_logic;
      Data_OUT : out std_logic_vector(7 downto 0);
      Write_Address_OUT: out std_logic_vector(7 downto 0);  
      Read_Address_OUT: out std_logic_vector(7 downto 0)          
      );
end entity RAM_controler;
architecture Behavioral of RAM_controler is
type state is (reset,operation);
signal state_reg,next_state_reg : state;
signal write_address : std_logic_vector(W-1 downto 0):="00000000"; 
signal next_write_address : std_logic_vector(W-1 downto 0):="00000000";         
begin   
state_change : process(clk_50, main_reset)
begin
    if (main_reset = '1') then
        state_reg <= reset;     
    elsif (rising_edge(clk_50)) then
        state_reg <= operation;
        read_counter <= next_read_counter;
        write_address<= next_write_address;
        read_address <= next_read_address;
    end if;     
end process;

writecounter : process(clk_baud, main_reset,enable) 
begin
    if (main_reset='1') then
        next_write_address <= "00000000";
        Data_OUT <= "ZZZZZZZZ";
        W_order <='0';
        Write_Address_OUT <="ZZZZZZZZ";
    elsif (rising_edge(clk_baud) and enable='1' ) then
        W_order <='1';
        Data_OUT <= in_data;            
        Write_Address_OUT <= write_address;
        if (write_address = "11111111") then
            next_write_address <= "00000000";
        else
            next_write_address <= write_address+1;
        end if;
    else 
        W_order <='0';
        Write_Address_OUT <= "ZZZZZZZZ";
        next_write_address <= write_address+1;
    end if;
end process;        
end Behavioral;

以上代码描述的是 RAM 控制器。

产生问题的部分是“elsif (rising_edge(clk_baud) and enable='1') then”。

错误:无法在 RAM_controler.vhd 中为“Write_Address_OUT”注册,因为它在时钟边沿之外没有保持其值

我不知道为什么那一点是错误的。

有人给我建议吗?

谢谢!

【问题讨论】:

  • 应该是最后一个else 中的分配也与时钟的上升沿同步?您使用的是哪种合成工具?
  • 您的代码不是Minimal, Complete, and Verifiable example,缺少Wread_addressnext_read_addressread_counternext_read_counter 的声明。请注意,例如,您在rising_edge(clk_50) 上分配write_address,而next_write_address 在rising_edge(clk_baud) 上分配。 Bill Lynch 指出,还有其他设计问题,例如在 clk_baud, main_resetenable 的任何事件上,您也在分配 Write_Address_OUT
  • 我正在使用 Quartus ii。实际上下面的答案对我有帮助。但我不知道为什么 last else 会像下面这样改变。
  • @Kim 如果您不明白答案,请在此下方发表评论,要求进一步解释。
  • 只是要知道:要做一个代码的最小示例,只需删除所有分配Write_Address_OUT的分配。然后删除所有不再需要的端口。这样,该问题将对遇到相同问题的其他读者有用。

标签: vhdl


【解决方案1】:

如果您要编写顺序逻辑代码,最好坚持使用模板。这是一个这样的模板,用于具有异步复位的时序逻辑,所有综合工具都应该理解:

process(clock, async_reset)  -- nothing else should go in the sensitivity list
begin
    -- never put anything here
    if async_reset ='1' then  -- or '0' for an active low reset
        -- set/reset the flip-flops here
        -- ie drive the signals to their initial values
    elsif rising_edge(clock) then  -- or falling_edge(clock)
        -- put the synchronous stuff here
        -- ie the stuff that happens on the rising or falling edge of the clock
    end if;
     -- never put anything here
end process;        

所以 enable 不应该在敏感列表中,也不应该在与异步重置和时钟测试相同的 if 语句中进行测试。

您收到此错误的原因:

错误:无法在“Write_Address_OUT”处注册 RAM_controler.vhd,因为它不在时钟之外保持其值 边缘

是因为代码中的最后三个赋值:

            W_order <='0';
            Write_Address_OUT <= "ZZZZZZZZ";
            next_write_address <= write_address+1;

可以发生在时钟的下降沿或(因为您的灵敏度列表中也有 enable)完全独立于任何时钟。逻辑合成器无法合成具有这种行为的逻辑。如果你坚持使用模板,你就不会遇到这种问题(它会让你更加仔细地思考你期望合成器合成什么逻辑)。

所以,我会将您的 writecounter 过程编码得更像这样:

writecounter : process(clk_baud, main_reset) 
begin
    if (main_reset='1') then
        next_write_address <= "00000000";
        Data_OUT <= "ZZZZZZZZ";
        W_order <='0';
        Write_Address_OUT <="ZZZZZZZZ";
    elsif rising_edge(clk_baud) then
        if enable='1' then
            W_order <='1';
            Data_OUT <= in_data;            
            Write_Address_OUT <= write_address;
            if (write_address = "11111111") then
                next_write_address <= "00000000";
            else
                next_write_address <= write_address+1;
            end if;
        else 
            W_order <='0';
            Write_Address_OUT <= "ZZZZZZZZ";
            next_write_address <= write_address+1;
        end if;
    end if;
end process;        

不过,我应该强调我的代码与您的代码不完全一样。我不知道你的设计意图,所以我只能猜测你的意图。如果您打算进行其他一些行为,那么您将不得不实现它。不管你的设计意图是什么,我关于坚持使用模板的建议仍然很重要。

【讨论】:

  • 代码模板很有帮助。但是,为了更好地理解,您还应该解释一下,为什么 OP 的代码没有描述寄存器。
  • @Martin Zabel 你是对的。在阅读了 Kim 在问题下的评论后,我在您评论时添加了该解释......
  • 谢谢。有用的评论。除了您指出的以外,是否还有其他原因导致 enable 不应出现在敏感度列表中?
  • @Kim 实现时序逻辑但没有同步复位的进程只有敏感列表中的时钟;使用异步复位实现时序逻辑的进程在敏感度列表中同时具有时钟和异步复位。任何顺序过程都不应该在敏感度列表中有任何其他输入,因为当任何其他输入发生变化时,顺序过程的输出不会改变(想想看 - 当触发器的 D 输入发生变化时,输出不会改变) .
  • @Kim ...虽然您可以在同一过程中混合组合和顺序,但这只有在组合逻辑将 D 输入驱动到任何触发器时才有可能;您不能在由触发器的 Q 输出驱动但不驱动触发器的 D 输入的顺序过程中使用组合逻辑。这是因为在时钟控制过程中驱动的任何信号都会推断出触发器。因此,如果您尝试在触发器的 Q 输出上实现逻辑,则会在该逻辑的输出处推断出另一个触发器...
【解决方案2】:

代码中最后的else 实际上应该是:

elsif (rising_edge(clk_baud) and enable='0' ) then

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多