编写防止覆盖 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;

这样,您就不必担心指针的实际值。