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

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

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

问题

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

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. entity ring_buffer is
  4. generic (
  5. RAM_WIDTH : natural;
  6. RAM_DEPTH : natural
  7. );
  8. port (
  9. clk : in std_logic;
  10. rst : in std_logic;
  11. -- Write port
  12. wr_en : in std_logic;
  13. wr_data : in std_logic_vector(RAM_WIDTH - 1 downto 0);
  14. -- Read port
  15. rd_en : in std_logic;
  16. rd_valid : out std_logic;
  17. rd_data : out std_logic_vector(RAM_WIDTH - 1 downto 0);
  18. -- Flags
  19. empty : out std_logic;
  20. empty_next : out std_logic;
  21. full : out std_logic;
  22. full_next : out std_logic;
  23. -- The number of elements in the FIFO
  24. fill_count : out integer range RAM_DEPTH - 1 downto 0
  25. );
  26. end ring_buffer;
  27. architecture rtl of ring_buffer is
  28. type ram_type is array (0 to RAM_DEPTH - 1) of
  29. std_logic_vector(wr_data'range);
  30. signal ram : ram_type;
  31. subtype index_type is integer range ram_type'range;
  32. signal head : index_type;
  33. signal tail : index_type;
  34. signal empty_i : std_logic;
  35. signal full_i : std_logic;
  36. signal fill_count_i : integer range RAM_DEPTH - 1 downto 0;
  37. -- Increment and wrap
  38. procedure incr(signal index : inout index_type) is
  39. begin
  40. if index = index_type'high then
  41. index <= index_type'low;
  42. else
  43. index <= index + 1;
  44. end if;
  45. end procedure;
  46. begin
  47. -- Copy internal signals to output
  48. empty <= empty_i;
  49. full <= full_i;
  50. fill_count <= fill_count_i;
  51. -- Set the flags
  52. empty_i <= '1' when fill_count_i = 0 else '0';
  53. empty_next <= '1' when fill_count_i <= 1 else '0';
  54. full_i <= '1' when fill_count_i >= RAM_DEPTH - 1 else '0';
  55. full_next <= '1' when fill_count_i >= RAM_DEPTH - 2 else '0';
  56. -- Update the head pointer in write
  57. PROC_HEAD : process(clk)
  58. begin
  59. if rising_edge(clk) then
  60. if rst = '1' then
  61. head <= 0;
  62. else
  63. if wr_en = '1' and full_i = '0' then
  64. incr(head);
  65. end if;
  66. end if;
  67. end if;
  68. end process;
  69. -- Update the tail pointer on read and pulse valid
  70. PROC_TAIL : process(clk)
  71. begin
  72. if rising_edge(clk) then
  73. if rst = '1' then
  74. tail <= 0;
  75. rd_valid <= '0';
  76. else
  77. rd_valid <= '0';
  78. if rd_en = '1' and empty_i = '0' then
  79. incr(tail);
  80. rd_valid <= '1';
  81. end if;
  82. end if;
  83. end if;
  84. end process;
  85. -- Write to and read from the RAM
  86. PROC_RAM : process(clk)
  87. begin
  88. if rising_edge(clk) then
  89. ram(head) <= wr_data;
  90. rd_data <= ram(tail);
  91. end if;
  92. end process;
  93. -- Update the fill count
  94. PROC_COUNT : process(head, tail)
  95. begin
  96. if head < tail then
  97. fill_count_i <= head - tail + RAM_DEPTH;
  98. else
  99. fill_count_i <= head - tail;
  100. end if;
  101. end process;
  102. end architecture;

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

英文:

Hi i have this block of code for a ring buffer

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. entity ring_buffer is
  4. generic (
  5. RAM_WIDTH : natural;
  6. RAM_DEPTH : natural
  7. );
  8. port (
  9. clk : in std_logic;
  10. rst : in std_logic;
  11. -- Write port
  12. wr_en : in std_logic;
  13. wr_data : in std_logic_vector(RAM_WIDTH - 1 downto 0);
  14. -- Read port
  15. rd_en : in std_logic;
  16. rd_valid : out std_logic;
  17. rd_data : out std_logic_vector(RAM_WIDTH - 1 downto 0);
  18. -- Flags
  19. empty : out std_logic;
  20. empty_next : out std_logic;
  21. full : out std_logic;
  22. full_next : out std_logic;
  23. -- The number of elements in the FIFO
  24. fill_count : out integer range RAM_DEPTH - 1 downto 0
  25. );
  26. end ring_buffer;
  27. architecture rtl of ring_buffer is
  28. type ram_type is array (0 to RAM_DEPTH - 1) of
  29. std_logic_vector(wr_data&#39;range);
  30. signal ram : ram_type;
  31. subtype index_type is integer range ram_type&#39;range;
  32. signal head : index_type;
  33. signal tail : index_type;
  34. signal empty_i : std_logic;
  35. signal full_i : std_logic;
  36. signal fill_count_i : integer range RAM_DEPTH - 1 downto 0;
  37. -- Increment and wrap
  38. procedure incr(signal index : inout index_type) is
  39. begin
  40. if index = index_type&#39;high then
  41. index &lt;= index_type&#39;low;
  42. else
  43. index &lt;= index + 1;
  44. end if;
  45. end procedure;
  46. begin
  47. -- Copy internal signals to output
  48. empty &lt;= empty_i;
  49. full &lt;= full_i;
  50. fill_count &lt;= fill_count_i;
  51. -- Set the flags
  52. empty_i &lt;= &#39;1&#39; when fill_count_i = 0 else &#39;0&#39;;
  53. empty_next &lt;= &#39;1&#39; when fill_count_i &lt;= 1 else &#39;0&#39;;
  54. full_i &lt;= &#39;1&#39; when fill_count_i &gt;= RAM_DEPTH - 1 else &#39;0&#39;;
  55. full_next &lt;= &#39;1&#39; when fill_count_i &gt;= RAM_DEPTH - 2 else &#39;0&#39;;
  56. -- Update the head pointer in write
  57. PROC_HEAD : process(clk)
  58. begin
  59. if rising_edge(clk) then
  60. if rst = &#39;1&#39; then
  61. head &lt;= 0;
  62. else
  63. if wr_en = &#39;1&#39; and full_i = &#39;0&#39; then
  64. incr(head);
  65. end if;
  66. end if;
  67. end if;
  68. end process;
  69. -- Update the tail pointer on read and pulse valid
  70. PROC_TAIL : process(clk)
  71. begin
  72. if rising_edge(clk) then
  73. if rst = &#39;1&#39; then
  74. tail &lt;= 0;
  75. rd_valid &lt;= &#39;0&#39;;
  76. else
  77. rd_valid &lt;= &#39;0&#39;;
  78. if rd_en = &#39;1&#39; and empty_i = &#39;0&#39; then
  79. incr(tail);
  80. rd_valid &lt;= &#39;1&#39;;
  81. end if;
  82. end if;
  83. end if;
  84. end process;
  85. -- Write to and read from the RAM
  86. PROC_RAM : process(clk)
  87. begin
  88. if rising_edge(clk) then
  89. ram(head) &lt;= wr_data;
  90. rd_data &lt;= ram(tail);
  91. end if;
  92. end process;
  93. -- Update the fill count
  94. PROC_COUNT : process(head, tail)
  95. begin
  96. if head &lt; tail then
  97. fill_count_i &lt;= head - tail + RAM_DEPTH;
  98. else
  99. fill_count_i &lt;= head - tail;
  100. end if;
  101. end process;
  102. 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

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

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. entity ringbuffer_tb is
  4. end entity;
  5. architecture foo of ringbuffer_tb is
  6. constant RAM_WIDTH: natural := 4;
  7. constant RAM_DEPTH: natural := 8;
  8. component ring_buffer is
  9. generic (
  10. RAM_WIDTH : natural;
  11. RAM_DEPTH : natural
  12. );
  13. port (
  14. clk: in std_logic;
  15. rst: in std_logic;
  16. wr_en: in std_logic;
  17. wr_data: in std_logic_vector(RAM_WIDTH - 1 downto 0);
  18. rd_en: in std_logic;
  19. rd_valid: out std_logic;
  20. rd_data: out std_logic_vector(RAM_WIDTH - 1 downto 0);
  21. empty: out std_logic;
  22. empty_next: out std_logic;
  23. full: out std_logic;
  24. full_next: out std_logic;
  25. fill_count: out integer range RAM_DEPTH - 1 downto 0
  26. );
  27. end component;
  28. signal clk: std_logic := &#39;0&#39;;
  29. signal rst: std_logic;
  30. signal wr_en: std_logic;
  31. signal wr_data: std_logic_vector (RAM_WIDTH - 1 downto 0);
  32. signal rd_en: std_logic;
  33. signal rd_valid: std_logic;
  34. signal rd_data: std_logic_vector (RAM_WIDTH - 1 downto 0);
  35. signal empty: std_logic;
  36. signal empty_next: std_logic;
  37. signal full: std_logic;
  38. signal full_next: std_logic;
  39. signal fill_count: integer range RAM_DEPTH - 1 downto 0;
  40. signal finished: boolean;
  41. begin
  42. CLOCK:
  43. process
  44. begin
  45. if not finished then
  46. clk &lt;= not clk;
  47. wait for 20 ns; -- 25 MHz
  48. else
  49. wait;
  50. end if;
  51. end process;
  52. DUT:
  53. ring_buffer
  54. generic map (
  55. RAM_WIDTH =&gt; RAM_WIDTH,
  56. RAM_DEPTH =&gt; RAM_DEPTH
  57. )
  58. port map (
  59. clk =&gt; clk,
  60. rst =&gt; rst,
  61. wr_en =&gt; wr_en,
  62. wr_data =&gt; wr_data,
  63. rd_en =&gt; rd_en,
  64. rd_valid =&gt; rd_valid,
  65. rd_data =&gt; rd_data,
  66. empty =&gt; empty,
  67. empty_next =&gt; empty_next,
  68. full =&gt; full,
  69. full_next =&gt; full_next,
  70. fill_count =&gt; fill_count
  71. );
  72. STIMULI:
  73. process
  74. use ieee.numeric_std.all;
  75. begin
  76. wr_en &lt;= &#39;0&#39;;
  77. rd_en &lt;= &#39;0&#39;;
  78. -- RESET:
  79. rst &lt;= &#39;1&#39;;
  80. wait until falling_edge(clk); -- center baud sampled rising edge;
  81. rst &lt;= &#39;0&#39;;
  82. -- STOP WHEN FULL TEST:
  83. wr_en &lt;= &#39;1&#39;;
  84. for i in 0 to RAM_DEPTH - 1 loop
  85. wr_data &lt;=
  86. std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
  87. wait until falling_edge(clk);
  88. end loop;
  89. -- ATTEMPT ONE MORE WRITE:
  90. wr_data &lt;= &quot;0101&quot;;
  91. wait until falling_edge(clk);
  92. wr_en &lt;= &#39;0&#39;;
  93. wait until falling_edge(clk);
  94. finished &lt;= TRUE;
  95. wait;
  96. end process;
  97. end architecture;

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

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

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

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

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

  1. -- Update the fill count
  2. PROC_COUNT : -- process(head, tail) -- 修改
  3. process (clk)
  4. begin
  5. if rising_edge (clk) then -- 添加,使fill count同步
  6. if head &lt; tail then
  7. fill_count_i &lt;= head - tail + RAM_DEPTH;
  8. else
  9. fill_count_i &lt;= head - tail;
  10. end if;
  11. end if;
  12. end process;

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

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

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

英文:

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

  1. library ieee;
  2. use ieee.std_logic_1164.all;
  3. entity ringbuffer_tb is
  4. end entity;
  5. architecture foo of ringbuffer_tb is
  6. constant RAM_WIDTH: natural := 4;
  7. constant RAM_DEPTH: natural := 8;
  8. component ring_buffer is
  9. generic (
  10. RAM_WIDTH : natural;
  11. RAM_DEPTH : natural
  12. );
  13. port (
  14. clk: in std_logic;
  15. rst: in std_logic;
  16. wr_en: in std_logic;
  17. wr_data: in std_logic_vector(RAM_WIDTH - 1 downto 0);
  18. rd_en: in std_logic;
  19. rd_valid: out std_logic;
  20. rd_data: out std_logic_vector(RAM_WIDTH - 1 downto 0);
  21. empty: out std_logic;
  22. empty_next: out std_logic;
  23. full: out std_logic;
  24. full_next: out std_logic;
  25. fill_count: out integer range RAM_DEPTH - 1 downto 0
  26. );
  27. end component;
  28. signal clk: std_logic := &#39;0&#39;;
  29. signal rst: std_logic;
  30. signal wr_en: std_logic;
  31. signal wr_data: std_logic_vector (RAM_WIDTH - 1 downto 0);
  32. signal rd_en: std_logic;
  33. signal rd_valid: std_logic;
  34. signal rd_data: std_logic_vector (RAM_WIDTH - 1 downto 0);
  35. signal empty: std_logic;
  36. signal empty_next: std_logic;
  37. signal full: std_logic;
  38. signal full_next: std_logic;
  39. signal fill_count: integer range RAM_DEPTH - 1 downto 0;
  40. signal finished: boolean;
  41. begin
  42. CLOCK:
  43. process
  44. begin
  45. if not finished then
  46. clk &lt;= not clk;
  47. wait for 20 ns; -- 25 MHz
  48. else
  49. wait;
  50. end if;
  51. end process;
  52. DUT:
  53. ring_buffer
  54. generic map (
  55. RAM_WIDTH =&gt; RAM_WIDTH,
  56. RAM_DEPTH =&gt; RAM_DEPTH
  57. )
  58. port map (
  59. clk =&gt; clk,
  60. rst =&gt; rst,
  61. wr_en =&gt; wr_en,
  62. wr_data =&gt; wr_data,
  63. rd_en =&gt; rd_en,
  64. rd_valid =&gt; rd_valid,
  65. rd_data =&gt; rd_data,
  66. empty =&gt; empty,
  67. empty_next =&gt; empty_next,
  68. full =&gt; full,
  69. full_next =&gt; full_next,
  70. fill_count =&gt; fill_count
  71. );
  72. STIMULI:
  73. process
  74. use ieee.numeric_std.all;
  75. begin
  76. wr_en &lt;= &#39;0&#39;;
  77. rd_en &lt;= &#39;0&#39;;
  78. -- RESET:
  79. rst &lt;= &#39;1&#39;;
  80. wait until falling_edge(clk); -- center baud sampled rising edge;
  81. rst &lt;= &#39;0&#39;;
  82. -- STOP WHEN FULL TEST:
  83. wr_en &lt;= &#39;1&#39;;
  84. for i in 0 to RAM_DEPTH - 1 loop
  85. wr_data &lt;=
  86. std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
  87. wait until falling_edge(clk);
  88. end loop;
  89. -- ATTEMPT ONE MORE WRITE:
  90. wr_data &lt;= &quot;0101&quot;;
  91. wait until falling_edge(clk);
  92. wr_en &lt;= &#39;0&#39;;
  93. wait until falling_edge(clk);
  94. finished &lt;= TRUE;
  95. wait;
  96. end process;
  97. 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:

  1. -- Write to and read from the RAM
  2. PROC_RAM : process(clk)
  3. begin
  4. if rising_edge(clk) then
  5. if wr_en = &#39;1&#39; and full_i = &#39;0&#39; then -- CHANGED ADDED write condition
  6. ram(head) &lt;= wr_data;
  7. end if;
  8. rd_data &lt;= ram(tail);
  9. end if;
  10. 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:

  1. -- Update the fill count
  2. PROC_COUNT : -- process(head, tail) -- CHANGED
  3. process (clk)
  4. begin
  5. if rising_edge (clk) then -- CHANGED ADDED, make fill count synchronous
  6. if head &lt; tail then
  7. fill_count_i &lt;= head - tail + RAM_DEPTH;
  8. else
  9. fill_count_i &lt;= head - tail;
  10. end if;
  11. end if;
  12. 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:

确定