英文:
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'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;
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 := '0';
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 <= not clk;
wait for 20 ns; -- 25 MHz
else
wait;
end if;
end process;
DUT:
ring_buffer
generic map (
RAM_WIDTH => RAM_WIDTH,
RAM_DEPTH => RAM_DEPTH
)
port map (
clk => clk,
rst => rst,
wr_en => wr_en,
wr_data => wr_data,
rd_en => rd_en,
rd_valid => rd_valid,
rd_data => rd_data,
empty => empty,
empty_next => empty_next,
full => full,
full_next => full_next,
fill_count => fill_count
);
STIMULI:
process
use ieee.numeric_std.all;
begin
wr_en <= '0';
rd_en <= '0';
-- RESET:
rst <= '1';
wait until falling_edge(clk); -- center baud sampled rising edge;
rst <= '0';
-- STOP WHEN FULL TEST:
wr_en <= '1';
for i in 0 to RAM_DEPTH - 1 loop
wr_data <=
std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
wait until falling_edge(clk);
end loop;
-- ATTEMPT ONE MORE WRITE:
wr_data <= "0101";
wait until falling_edge(clk);
wr_en <= '0';
wait until falling_edge(clk);
finished <= TRUE;
wait;
end process;
end architecture;
验证了问题,您的FIFO在满时进行写入:
ringbuffer存在两个问题。对RAM的写入不受FIFO是否满的条件约束。这可以通过以下方式修复:
-- Write to and read from the RAM
PROC_RAM : process(clk)
begin
if rising_edge(clk) then
if wr_en = '1' and full_i = '0' then -- 添加写入条件
ram(head) <= wr_data;
end if;
rd_data <= 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 < tail then
fill_count_i <= head - tail + RAM_DEPTH;
else
fill_count_i <= head - tail;
end if;
end if;
end process;
尽管ringbuffer可能存在尚未经过测试的其他问题,但这些更改会使写入在FIFO满时停止:
测试用例可以扩展和/或适应其他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 := '0';
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 <= not clk;
wait for 20 ns; -- 25 MHz
else
wait;
end if;
end process;
DUT:
ring_buffer
generic map (
RAM_WIDTH => RAM_WIDTH,
RAM_DEPTH => RAM_DEPTH
)
port map (
clk => clk,
rst => rst,
wr_en => wr_en,
wr_data => wr_data,
rd_en => rd_en,
rd_valid => rd_valid,
rd_data => rd_data,
empty => empty,
empty_next => empty_next,
full => full,
full_next => full_next,
fill_count => fill_count
);
STIMULI:
process
use ieee.numeric_std.all;
begin
wr_en <= '0';
rd_en <= '0';
-- RESET:
rst <= '1';
wait until falling_edge(clk); -- center baud sampled rising edge;
rst <= '0';
-- STOP WHEN FULL TEST:
wr_en <= '1';
for i in 0 to RAM_DEPTH - 1 loop
wr_data <=
std_logic_vector (to_unsigned(RAM_DEPTH - 1 - i, RAM_WIDTH));
wait until falling_edge(clk);
end loop;
-- ATTEMPT ONE MORE WRITE:
wr_data <= "0101";
wait until falling_edge(clk);
wr_en <= '0';
wait until falling_edge(clk);
finished <= TRUE;
wait;
end process;
end architecture;
verifies the problem, your FIFO writes when full:
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 = '1' and full_i = '0' then -- CHANGED ADDED write condition
ram(head) <= wr_data;
end if;
rd_data <= 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 < tail then
fill_count_i <= head - tail + RAM_DEPTH;
else
fill_count_i <= 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:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论