编写防止覆盖 RAM 中先前数据的模块
Writing a Module Which Prevent Overwriting Previous Data in RAM
问题
我有一个包含 512 深 RAM 的通道。我有一个控制块,它告诉这个通道什么时候写什么时候读。当它写入时,只要捕获标志保持高电平,写入指针就会在每个时钟周期内线性增加。
我不能为此使用 FIFO,因为我可能必须从同一地址读取两次。我只想在写入地址接近读取地址时举起一个标志(即某种 "high water mark" - 稍后将设置的值)。问题是环绕使这变得困难。因此,当我从地址 500 读取但写入地址 0 时,这将对下面的等号造成严重破坏。另一个糟糕的情况是,如果它从地址 0 读取,然后从 511 读取,然后再次从 0 读取,我不确定如何处理使标志翻转。我想不出解决这个问题的简单方法。
任何人都可以想出更有效的方法来处理这个问题吗?我确定以前有人这样做过?
我的尝试
SIGNAL actr, read_addr, s_hwm, s_lwm, hwm, lwm : unsigned(8 downto 0);
process(clk_p)
BEGIN
IF RISING_EDGE(clk_p) THEN
IF rst_i = '1' THEN
s_hwm <= (OTHERS => '0'); -- high water mark
s_lwm <= (OTHERS => '0'); -- low water mark
ELSE
s_hwm <= read_addr - hwm; -- when it reads, know the relative high water mark from the read pointer
s_lwm <= read_addr - lwm;
END IF;
END IF;
END PROCESS;
PROCESS(clk_p)
BEGIN
IF RISING_EDGE(clk_p) THEN
IF rst_i = '1' THEN
ram_state <= ST_IDLE;
ELSE
CASE ram_state IS
WHEN ST_IDLE =>
IF actr >= s_hwm then -- actr is the current write pointer
ram_state <= ST_WARN; -- WARN when it is close to the high water mark
END IF;
WHEN ST_WARN =>
IF actr >= read_addr THEN -- read_addr is the current address it is reading out from, if the write pointer goes over this, this it is overwriting old data
ram_state <= ST_FULL;
ELSIF actr <= s_lwm THEN -- exit the warn when it is below the low water mark and enough reads have been initiated
ram_state <= ST_IDLE;
END IF;
WHEN ST_FULL =>
ram_state <= ST_FULL;
END CASE;
END IF;
END IF;
END PROCESS;
END rtl;
既然你知道你的写指针总是领先于你的读,你可以用这样的代码轻松解决问题:
tmp := ('1' & write_ptr) - read_ptr;
count <= tmp(count 'range);
-- Alternate syntax without tmp variable using numeric_std
count <= resize(('1' & write_ptr) - read_ptr, count'length);
因此,如果读取为 500 并写入为 0,则得到 512-500 = 12
。如果写入为 500,读取为 0,它会为您提供 512+500-0 = 912 = 500
,因为您删除了 msb。
另一种方法是通过由您的 rd/wr 信号控制的计数器来跟踪占用情况。
if rd = '1' and wr = '0' then
count <= count - 1;
elsif wr = '1' and rd = '0' then
count <= count + 1;
end if;
这样,您就不必担心指针的实际值。
问题
我有一个包含 512 深 RAM 的通道。我有一个控制块,它告诉这个通道什么时候写什么时候读。当它写入时,只要捕获标志保持高电平,写入指针就会在每个时钟周期内线性增加。
我不能为此使用 FIFO,因为我可能必须从同一地址读取两次。我只想在写入地址接近读取地址时举起一个标志(即某种 "high water mark" - 稍后将设置的值)。问题是环绕使这变得困难。因此,当我从地址 500 读取但写入地址 0 时,这将对下面的等号造成严重破坏。另一个糟糕的情况是,如果它从地址 0 读取,然后从 511 读取,然后再次从 0 读取,我不确定如何处理使标志翻转。我想不出解决这个问题的简单方法。
任何人都可以想出更有效的方法来处理这个问题吗?我确定以前有人这样做过?
我的尝试
SIGNAL actr, read_addr, s_hwm, s_lwm, hwm, lwm : unsigned(8 downto 0);
process(clk_p)
BEGIN
IF RISING_EDGE(clk_p) THEN
IF rst_i = '1' THEN
s_hwm <= (OTHERS => '0'); -- high water mark
s_lwm <= (OTHERS => '0'); -- low water mark
ELSE
s_hwm <= read_addr - hwm; -- when it reads, know the relative high water mark from the read pointer
s_lwm <= read_addr - lwm;
END IF;
END IF;
END PROCESS;
PROCESS(clk_p)
BEGIN
IF RISING_EDGE(clk_p) THEN
IF rst_i = '1' THEN
ram_state <= ST_IDLE;
ELSE
CASE ram_state IS
WHEN ST_IDLE =>
IF actr >= s_hwm then -- actr is the current write pointer
ram_state <= ST_WARN; -- WARN when it is close to the high water mark
END IF;
WHEN ST_WARN =>
IF actr >= read_addr THEN -- read_addr is the current address it is reading out from, if the write pointer goes over this, this it is overwriting old data
ram_state <= ST_FULL;
ELSIF actr <= s_lwm THEN -- exit the warn when it is below the low water mark and enough reads have been initiated
ram_state <= ST_IDLE;
END IF;
WHEN ST_FULL =>
ram_state <= ST_FULL;
END CASE;
END IF;
END IF;
END PROCESS;
END rtl;
既然你知道你的写指针总是领先于你的读,你可以用这样的代码轻松解决问题:
tmp := ('1' & write_ptr) - read_ptr;
count <= tmp(count 'range);
-- Alternate syntax without tmp variable using numeric_std
count <= resize(('1' & write_ptr) - read_ptr, count'length);
因此,如果读取为 500 并写入为 0,则得到 512-500 = 12
。如果写入为 500,读取为 0,它会为您提供 512+500-0 = 912 = 500
,因为您删除了 msb。
另一种方法是通过由您的 rd/wr 信号控制的计数器来跟踪占用情况。
if rd = '1' and wr = '0' then
count <= count - 1;
elsif wr = '1' and rd = '0' then
count <= count + 1;
end if;
这样,您就不必担心指针的实际值。