为什么我的VHDL中的rptr信号会向前移动,即使它不应该?

huangapple go评论75阅读模式
英文:

Why does my rptr signal in vhdl move forward even tho it shouldn't?

问题

抱歉,您的代码有一些字符转义问题,其中的'字符应该是单引号(')而不是&#的组合。这些字符可能是由于复制和粘贴时格式不正确导致的。以下是修复后的代码:

library ieee;
use ieee.std_logic_1164.all;
 
entity ring_buffer is
  generic (
    RAM_WIDTH : natural;
    RAM_DEPTH : natural
  );
  port (
    clk : in std_logic;
    rst : in std_logic;
 
    -- Write port
    wr_en : in std_logic;
    wr_data : in std_logic_vector(RAM_WIDTH - 1 downto 0);
 
    -- Read port
    rd_en : in std_logic;
    rd_valid : out std_logic;
    rd_data : out std_logic_vector(RAM_WIDTH - 1 downto 0);
 
    -- Flags
    empty : out std_logic;
    empty_next : out std_logic;
    full : out std_logic;
    full_next : out std_logic;
 
    -- The number of elements in the FIFO
    fill_count : out integer range RAM_DEPTH - 1 downto 0
  );
end ring_buffer;
 
architecture rtl of ring_buffer is
 
  type ram_type is array (0 to RAM_DEPTH - 1) of
    std_logic_vector(wr_data'range);
  signal ram : ram_type;
 
  subtype index_type is integer range ram_type'range;
  signal head : index_type;
  signal tail : index_type;
 
  signal empty_i : std_logic;
  signal full_i : std_logic;
  signal fill_count_i : integer range RAM_DEPTH - 1 downto 0;
 
  -- Increment and wrap
  procedure incr(signal index : inout index_type) is
  begin
    if index = index_type'high then
      index <= index_type'low;
    else
      index <= index + 1;
    end if;
  end procedure;
 
begin
 
  -- Copy internal signals to output
  empty <= empty_i;
  full <= full_i;
  fill_count <= fill_count_i;
 
  -- Set the flags
  empty_i <= '1' when fill_count_i = 0 else '0';
  empty_next <= '1' when fill_count_i <= 1 else '0';
  full_i <= '1' when fill_count_i >= RAM_DEPTH - 1 else '0';
  full_next <= '1' when fill_count_i >= RAM_DEPTH - 2 else '0';
 
  -- Update the head pointer in write
  PROC_HEAD : process(clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        head <= 0;
      else
 
        if wr_en = '1' and full_i = '0' then
          incr(head);
        end if;
 
      end if;
    end if;
  end process;
 
  -- Update the tail pointer on read and pulse valid
  PROC_TAIL : process(clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        tail <= 0;
        rd_valid <= '0';
      else
        rd_valid <= '0';
 
        if rd_en = '1' and empty_i = '0' then
          incr(tail);
          rd_valid <= '1';
        end if;
 
      end if;
    end if;
  end process;
 
  -- Write to and read from the RAM
  PROC_RAM : process(clk)
  begin
    if rising_edge(clk) then
      ram(head) <= wr_data;
      rd_data <= ram(tail);
    end if;
  end process;
 
  -- Update the fill count
  PROC_COUNT : process(head, tail)
  begin
    if head < tail then
      fill_count_i <= head - tail + RAM_DEPTH;
    else
      fill_count_i <= head - tail;
    end if;
  end process;
 
end architecture;

上述代码已经修复了字符转义问题。如果您有关于代码功能的问题,可以继续提出。

英文:

Hi i have this block of code for a ring buffer

library ieee;
use ieee.std_logic_1164.all;
 
entity ring_buffer is
  generic (
    RAM_WIDTH : natural;
    RAM_DEPTH : natural
  );
  port (
    clk : in std_logic;
    rst : in std_logic;
 
    -- Write port
    wr_en : in std_logic;
    wr_data : in std_logic_vector(RAM_WIDTH - 1 downto 0);
 
    -- Read port
    rd_en : in std_logic;
    rd_valid : out std_logic;
    rd_data : out std_logic_vector(RAM_WIDTH - 1 downto 0);
 
    -- Flags
    empty : out std_logic;
    empty_next : out std_logic;
    full : out std_logic;
    full_next : out std_logic;
 
    -- The number of elements in the FIFO
    fill_count : out integer range RAM_DEPTH - 1 downto 0
  );
end ring_buffer;
 
architecture rtl of ring_buffer is
 
  type ram_type is array (0 to RAM_DEPTH - 1) of
    std_logic_vector(wr_data&#39;range);
  signal ram : ram_type;
 
  subtype index_type is integer range ram_type&#39;range;
  signal head : index_type;
  signal tail : index_type;
 
  signal empty_i : std_logic;
  signal full_i : std_logic;
  signal fill_count_i : integer range RAM_DEPTH - 1 downto 0;
 
  -- Increment and wrap
  procedure incr(signal index : inout index_type) is
  begin
    if index = index_type&#39;high then
      index &lt;= index_type&#39;low;
    else
      index &lt;= index + 1;
    end if;
  end procedure;
 
begin
 
  -- Copy internal signals to output
  empty &lt;= empty_i;
  full &lt;= full_i;
  fill_count &lt;= fill_count_i;
 
  -- Set the flags
  empty_i &lt;= &#39;1&#39; when fill_count_i = 0 else &#39;0&#39;;
  empty_next &lt;= &#39;1&#39; when fill_count_i &lt;= 1 else &#39;0&#39;;
  full_i &lt;= &#39;1&#39; when fill_count_i &gt;= RAM_DEPTH - 1 else &#39;0&#39;;
  full_next &lt;= &#39;1&#39; when fill_count_i &gt;= RAM_DEPTH - 2 else &#39;0&#39;;
 
  -- Update the head pointer in write
  PROC_HEAD : process(clk)
  begin
    if rising_edge(clk) then
      if rst = &#39;1&#39; then
        head &lt;= 0;
      else
 
        if wr_en = &#39;1&#39; and full_i = &#39;0&#39; then
          incr(head);
        end if;
 
      end if;
    end if;
  end process;
 
  -- Update the tail pointer on read and pulse valid
  PROC_TAIL : process(clk)
  begin
    if rising_edge(clk) then
      if rst = &#39;1&#39; then
        tail &lt;= 0;
        rd_valid &lt;= &#39;0&#39;;
      else
        rd_valid &lt;= &#39;0&#39;;
 
        if rd_en = &#39;1&#39; and empty_i = &#39;0&#39; then
          incr(tail);
          rd_valid &lt;= &#39;1&#39;;
        end if;
 
      end if;
    end if;
  end process;
 
  -- Write to and read from the RAM
  PROC_RAM : process(clk)
  begin
    if rising_edge(clk) then
      ram(head) &lt;= wr_data;
      rd_data &lt;= ram(tail);
    end if;
  end process;
 
  -- Update the fill count
  PROC_COUNT : process(head, tail)
  begin
    if head &lt; tail then
      fill_count_i &lt;= head - tail + RAM_DEPTH;
    else
      fill_count_i &lt;= head - tail;
    end if;
  end process;
 
end architecture;

I have no idea why it does that... but when I init it and write to it with a frequency 25MHz it owerites the first read bit for some reason
so instead of stopping at the 511 address in memory (that being RAM_DEPTH in my case) it goes to another one up so that it goes to 0
i tried changing it so that the if statement in PROC_HEAD has full_next = '1' instead of full_i and it still did the same thing...
thank you for helping

答案1

得分: 1

向代码添加一个测试台以提供一个最小、完整和可验证的示例:

library ieee;
use ieee.std_logic_1164.all;

entity ringbuffer_tb is
end entity;

architecture foo of ringbuffer_tb is
    constant RAM_WIDTH:     natural := 4;
    constant RAM_DEPTH:     natural := 8;
    component ring_buffer is
        generic (
            RAM_WIDTH : natural;
            RAM_DEPTH : natural
        );
        port (
            clk:        in  std_logic;
            rst:        in  std_logic;
            wr_en:      in  std_logic;
            wr_data:    in  std_logic_vector(RAM_WIDTH - 1 downto 0);
            rd_en:      in  std_logic;
            rd_valid:   out std_logic;
            rd_data:    out std_logic_vector(RAM_WIDTH - 1 downto 0);
            empty:      out std_logic;
            empty_next: out std_logic;
            full:       out std_logic;
            full_next:  out std_logic;
            fill_count: out integer range RAM_DEPTH - 1 downto 0
        );
    end component;
    signal clk:         std_logic := &#39;0&#39;;
    signal rst:         std_logic;
    signal wr_en:       std_logic;
    signal wr_data:     std_logic_vector (RAM_WIDTH - 1 downto 0);
    signal rd_en:       std_logic;
    signal rd_valid:    std_logic;
    signal rd_data:     std_logic_vector (RAM_WIDTH - 1 downto 0);
    signal empty:       std_logic;
    signal empty_next:  std_logic;
    signal full:        std_logic;
    signal full_next:   std_logic;
    signal fill_count:  integer range RAM_DEPTH - 1 downto 0;
    signal finished:    boolean;
begin
    CLOCK:
    process
    begin
        if not finished then
            clk &lt;= not clk;
            wait for 20 ns;  -- 25 MHz
        else
            wait;
        end if;
    end process;
DUT:
    ring_buffer
        generic map (
            RAM_WIDTH =&gt; RAM_WIDTH,
            RAM_DEPTH =&gt; RAM_DEPTH
        )
        port map (
            clk =&gt; clk,
            rst =&gt; rst,
            wr_en =&gt; wr_en,
            wr_data =&gt; wr_data,
            rd_en =&gt; rd_en,
            rd_valid =&gt; rd_valid,
            rd_data =&gt; rd_data,
            empty =&gt; empty,
            empty_next =&gt; empty_next,
            full =&gt; full,
            full_next =&gt; full_next,
            fill_count =&gt; fill_count
        );
STIMULI:
    process
        use ieee.numeric_std.all;
    begin
        wr_en &lt;= &#39;0&#39;;
        rd_en &lt;= &#39;0&#39;;
        -- RESET:
        rst &lt;= &#39;1&#39;;
        wait until falling_edge(clk);  -- center baud sampled rising edge;
        rst &lt;= &#39;0&#39;;
        -- STOP WHEN FULL TEST:
        wr_en &lt;= &#39;1&#39;;
        for i in 0 to RAM_DEPTH - 1 loop
            wr_data &lt;= 
                std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
                wait until falling_edge(clk);
        end loop;
        -- ATTEMPT ONE MORE WRITE:
        wr_data &lt;= &quot;0101&quot;;
        wait until falling_edge(clk);
        wr_en &lt;= &#39;0&#39;;
        wait until falling_edge(clk);
        finished &lt;= TRUE;
        wait;
    end process;
end architecture;

验证了问题,您的FIFO在满时进行写入:

为什么我的VHDL中的rptr信号会向前移动,即使它不应该?

ringbuffer存在两个问题。对RAM的写入不受FIFO是否满的条件约束。这可以通过以下方式修复:

  -- Write to and read from the RAM
  PROC_RAM : process(clk)
  begin
    if rising_edge(clk) then
        if wr_en = &#39;1&#39; and full_i = &#39;0&#39; then  -- 添加写入条件
            ram(head) &lt;= wr_data;
        end if;
      rd_data &lt;= ram(tail);
    end if;
  end process;

另一个问题是full (full_i) 和 full_next 信号提前一个时钟周期,这会阻止写入到最后一个位置。可以通过将fill_count_i变为同步来修复:

  -- Update the fill count
  PROC_COUNT : -- process(head, tail)  -- 修改
  process (clk)
  begin
        if rising_edge (clk) then  -- 添加,使fill count同步
          if head &lt; tail then
              fill_count_i &lt;= head - tail + RAM_DEPTH;
          else
              fill_count_i &lt;= head - tail;
          end if;
      end if;
  end process;

尽管ringbuffer可能存在尚未经过测试的其他问题,但这些更改会使写入在FIFO满时停止:

为什么我的VHDL中的rptr信号会向前移动,即使它不应该?

测试用例可以扩展和/或适应其他RAM_WIDTH和RAM_DEPTH值。只要它们不写入相同的信号,您还可以拥有单独的读取和写入刺激进程。这将允许读取和写入操作重叠。

英文:

Adding a testbench to provide a minimal, complete, and verifiable example:

library ieee;
use ieee.std_logic_1164.all;

entity ringbuffer_tb is
end entity;

architecture foo of ringbuffer_tb is
    constant RAM_WIDTH:     natural := 4;
    constant RAM_DEPTH:     natural := 8;
    component ring_buffer is
        generic (
            RAM_WIDTH : natural;
            RAM_DEPTH : natural
        );
        port (
            clk:        in  std_logic;
            rst:        in  std_logic;
            wr_en:      in  std_logic;
            wr_data:    in  std_logic_vector(RAM_WIDTH - 1 downto 0);
            rd_en:      in  std_logic;
            rd_valid:   out std_logic;
            rd_data:    out std_logic_vector(RAM_WIDTH - 1 downto 0);
            empty:      out std_logic;
            empty_next: out std_logic;
            full:       out std_logic;
            full_next:  out std_logic;
            fill_count: out integer range RAM_DEPTH - 1 downto 0
        );
    end component;
    signal clk:         std_logic := &#39;0&#39;;
    signal rst:         std_logic;
    signal wr_en:       std_logic;
    signal wr_data:     std_logic_vector (RAM_WIDTH - 1 downto 0);
    signal rd_en:       std_logic;
    signal rd_valid:    std_logic;
    signal rd_data:     std_logic_vector (RAM_WIDTH - 1 downto 0);
    signal empty:       std_logic;
    signal empty_next:  std_logic;
    signal full:        std_logic;
    signal full_next:   std_logic;
    signal fill_count:  integer range RAM_DEPTH - 1 downto 0;
    signal finished:    boolean;
begin
    CLOCK:
    process
    begin
        if not finished then
            clk &lt;= not clk;
            wait for 20 ns;  -- 25 MHz
        else
            wait;
        end if;
    end process;
DUT:
    ring_buffer
        generic map (
            RAM_WIDTH =&gt; RAM_WIDTH,
            RAM_DEPTH =&gt; RAM_DEPTH
        )
        port map (
            clk =&gt; clk,
            rst =&gt; rst,
            wr_en =&gt; wr_en,
            wr_data =&gt; wr_data,
            rd_en =&gt; rd_en,
            rd_valid =&gt; rd_valid,
            rd_data =&gt; rd_data,
            empty =&gt; empty,
            empty_next =&gt; empty_next,
            full =&gt; full,
            full_next =&gt; full_next,
            fill_count =&gt; fill_count
        );
STIMULI:
    process
        use ieee.numeric_std.all;
    begin
        wr_en &lt;= &#39;0&#39;;
        rd_en &lt;= &#39;0&#39;;
        -- RESET:
        rst &lt;= &#39;1&#39;;
        wait until falling_edge(clk);  -- center baud sampled rising edge;
        rst &lt;= &#39;0&#39;;
        -- STOP WHEN FULL TEST:
        wr_en &lt;= &#39;1&#39;;
        for i in 0 to RAM_DEPTH - 1 loop
            wr_data &lt;= 
                std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
                wait until falling_edge(clk);
        end loop;
        -- ATTEMPT ONE MORE WRITE:
        wr_data &lt;= &quot;0101&quot;;
        wait until falling_edge(clk);
        wr_en &lt;= &#39;0&#39;;
        wait until falling_edge(clk);
        finished &lt;= TRUE;
        wait;
    end process;
end architecture;

verifies the problem, your FIFO writes when full:

为什么我的VHDL中的rptr信号会向前移动,即使它不应该?

There are two issues with the ringbuffer. Writes to RAM are not conditional on the FIFO not being full. This can be fixed:

  -- Write to and read from the RAM
  PROC_RAM : process(clk)
  begin
    if rising_edge(clk) then
        if wr_en = &#39;1&#39; and full_i = &#39;0&#39; then  -- CHANGED ADDED write condition
            ram(head) &lt;= wr_data;
        end if;
      rd_data &lt;= ram(tail);
    end if;
  end process;

The other problem is that the full (full_i) and full_next signals are one clock early, it'd prevent writing to the last location. That can be fixed by making fill_count_i synchronous:

  -- Update the fill count
  PROC_COUNT : -- process(head, tail)  -- CHANGED
  process (clk)
  begin
        if rising_edge (clk) then  -- CHANGED ADDED, make fill count synchronous
          if head &lt; tail then
              fill_count_i &lt;= head - tail + RAM_DEPTH;
          else
              fill_count_i &lt;= head - tail;
          end if;
      end if;
  end process;

While there may be other as yet untested issues with your ringbuffer these changes make writes stop when the FIFO is full:

为什么我的VHDL中的rptr信号会向前移动,即使它不应该?

The testcases can be expanded and/or adapted for other RAM_WIDTH and RAM_DEPTH values. You could also have separate read and write stimuli processes as long as they don't write to the same signals. This would allow read and write operations to overlap.

huangapple
  • 本文由 发表于 2023年3月7日 22:52:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75663554.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定