IP核学习之自定义ram:参照IP核xilinx_dist_sdpram_0oregs_32x12

一、Distributed Memory Generator有什么用?

Distributed Memory Generator是Vivado中的IP核,即分布式存储器。
它可以生成只读存储器 (ROM),单端口、简单双端口和双端口随机存取存储器 (RAM),
且生成的存储器支持16-65536字的数据深度,和1-1024位的数据宽度。

xilinx_dist_sdpram_0oregs_32x12 似乎是指一个双端口的分布式存储器(SDPRAM),它具有32个地址和每个地址可以存储12位数据。在Xilinx FPGA中,分布式RAM(Distributed RAM)是利用查找表(LUTs)中的额外逻辑来实现的小型RAM,通常用于实现小规模的存储需求。

在Xilinx FPGA架构中,分布式RAM可以在SLICEM中的查找表(LUTs)实现,而SLICEL则不支持此功能。每个SLICEM可以配置为不同形式的RAM,例如单端口RAM、双端口RAM、简单双端口RAM或四端口RAM。对于简单双端口RAM,一个SLICEM可以提供最多256位的存储空间,即4个LUTs,每个LUT提供64位的存储能力。

二、端口说明

本次选择的设置是简单双端口,接口调用如下:

分布式ram代码:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity dist_sdpram is
    Port (
        a : in STD_LOGIC_VECTOR(4 downto 0); -- 5-bit address
        d : in STD_LOGIC_VECTOR(11 downto 0); -- 12-bit data input
        dpra : in STD_LOGIC_VECTOR(4 downto 0); -- 5-bit address for read
        clk : in STD_LOGIC; -- Clock input
        we : in STD_LOGIC; -- Write enable
        qdpo_ce : in STD_LOGIC; -- Output register clock enable
        qdpo : out STD_LOGIC_VECTOR(11 downto 0) -- 12-bit data output
    );
end dist_sdpram;

architecture Behavioral of dist_sdpram is
    type ram_type is array (0 to 31) of STD_LOGIC_VECTOR(11 downto 0);
    signal ram : ram_type := (others => (others => '0')); -- Initialize RAM
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if we = '1' then
                ram(conv_integer(a)) <= d; -- Write operation
            end if;
        end if;
    end process;

    -- Read operation
    process(clk)
    begin
        if rising_edge(clk) then
            if qdpo_ce = '1' then
                qdpo <= ram(conv_integer(dpra)); -- Read operation
            end if;
        end if;
    end process;
end Behavioral;

调用两次封装为更大的sdpram_32x24_0oregs_wrapper

​
entity sdpram_32x24_0oregs_wrapper is
        waddr : in STD_LOGIC_VECTOR(4 downto 0); -- 5-bit address
        wdata : in STD_LOGIC_VECTOR(11 downto 0); -- 12-bit data input
        raddr : in STD_LOGIC_VECTOR(4 downto 0); -- 5-bit address for read
        clk : in STD_LOGIC; -- Clock input
        wen : in STD_LOGIC; -- Write enable
        ren : in STD_LOGIC; -- Output register clock enable
        q : out STD_LOGIC_VECTOR(11 downto 0) -- 12-bit data output
end sdpram_32x24_0oregs_wrapper;

architecture testbench of sdpram_32x24_tb is
    
    component dist_sdpram_32x12
        port (
            clk : in std_logic;
            we : in std_logic;
            a : in std_logic_vector(4 downto 0);
            d : in std_logic_vector(11 downto 0);
            dpra : in std_logic_vector(4 downto 0);
            qdpo_ce : in std_logic;
            qdpo : out std_logic_vector(11 downto 0)
        );
    end component;
    
    -- 测试平台内部连接RAM实体
    begin
        sdpram_L_inst: dist_sdpram_32x12
        port map (
            clk => clk,
            we => wen,
            a => waddr,
            d => wdata (11 downto 0),
            dpra => raddr,
            qdpo_ce => ren,
            qdpo => q (11 downto 0)
        );
        sdpram_H_inst: dist_sdpram_32x12
        port map (
            clk => clk,
            we => wen,
            a => waddr,
            d => wdata (23 downto 12),
            dpra => raddr,
            qdpo_ce => ren,
            qdpo => q (23 downto 12)
        );

​

tb:

entity sdpram_32x24_tb is
-- 测试平台不需要端口
end sdpram_32x24_tb;

architecture testbench of sdpram_32x24_tb is
    signal clk : std_logic := '0';
    signal we : std_logic := '0';
    signal a : std_logic_vector(4 downto 0) := (others => '0'); -- 写/读地址
    signal d : std_logic_vector(23 downto 0) := (others => '0'); -- 数据输入
    signal dpra : std_logic_vector(4 downto 0) := (others => '0'); -- 读地址
    signal qdpo_ce : std_logic := '0'; -- 输出寄存器时钟使能
    signal qdpo : std_logic_vector(23 downto 0); -- 数据输出

    component sdpram_32x24
        port (
            clk : in std_logic;
            we : in std_logic;
            a : in std_logic_vector(4 downto 0);
            d : in std_logic_vector(23 downto 0);
            dpra : in std_logic_vector(4 downto 0);
            qdpo_ce : in std_logic;
            qdpo : out std_logic_vector(23 downto 0)
        );
    end component;

begin
    uut: sdpram_32x24
    port map (
        clk => clk,
        we => we,
        a => a,
        d => d,
        dpra => dpra,
        qdpo_ce => qdpo_ce,
        qdpo => qdpo
    );

    clock: process
    begin
        clk <= '0';
        wait for 10 ns;
        clk <= '1';
        wait for 10 ns;
    end process;

    test_proc: process
    begin
        -- 初始化
        we <= '0';
        wait for 40 ns;

        -- 写入24个数据到低位地址
        we <= '1';
        for i in 0 to 23 loop
            a <= std_logic_vector(to_unsigned(i, a'length));
            d <= std_logic_vector(to_unsigned(i, d'length)); -- 写入数据i
            wait for 20 ns;
        end loop;
        we <= '0'; -- 确保写完后禁用写使能

        -- 写入冲突数据
        we <= '1';
        a <= (others => '0'); -- 选择一个低位地址进行写入
        d <= "1111111111111111111111111"; -- 写入新的数据
        wait for 20 ns;
        we <= '0'; -- 禁用写使能

        -- 验证数据是否正确存储在低位
        qdpo_ce <= '1';
        for i in 0 to 23 loop
            dpra <= std_logic_vector(to_unsigned(i, dpra'length));
            wait for 20 ns;
            if i = 0 then
                assert qdpo = "1111111111111111111111111"
                report "测试失败:地址0处读出的数据不正确,存在冲突"
                severity error;
            else
                assert qdpo = std_logic_vector(to_unsigned(i, qdpo'length))
                report "测试失败:地址 " & integer'image(i) & " 处读出的数据不正确"    
                severity error;
            end if;
        end loop;

        -- 验证数据是否正确移位到高位
        for i in 0 to 11 loop
            dpra <= std_logic_vector(to_unsigned(23 - i, dpra'length));
            wait for 20 ns;
            assert qdpo = std_logic_vector(to_unsigned(23 - i, qdpo'length))
            report "测试失败:地址 " & integer'image(23 - i) & " 处读出的数据不正确"
            severity error;
        end loop;

        wait;
    end process test_proc;
end testbench;

功能列表省略

上述只是模拟移位,移位RAM(Shift Register RAM)是一种特殊的存储器,它按照特定的顺序存储数据,通常用于串行数据传输或数据缓冲。在移位RAM中,数据可以按照一定的顺序(如先进先出FIFO)进入存储器,并且可以在读取时按照相同的顺序或不同的顺序(如后进先出LIFO)出存储器。在某些应用中,数据会按照特定的模式移动,例如循环缓冲或双缓冲。要实现一个32x24位的简单双端口移位RAM(SDPRAM),我们需要定义一个VHDL架构,其中数据会按照写入的顺序存储在RAM的地址中,并且随着新数据的写入,旧数据会向更高地址移动。以下是一个简化的VHDL代码示例,它定义了一个具有移位功能的SDPRAM:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity shift_sdpram_32x24 is
    Port (
        clk : in STD_LOGIC;
        we : in STD_LOGIC;
        a : in STD_LOGIC_VECTOR(4 downto 0); -- 5-bit address for 32 locations
        d : in STD_LOGIC_VECTOR(23 downto 0); -- 24-bit data input
        dpra : in STD_LOGIC_VECTOR(4 downto 0); -- Read address
        qdpo_ce : in STD_LOGIC;
        qdpo : out STD_LOGIC_VECTOR(23 downto 0)
    );
end shift_sdpram_32x24;

architecture Behavioral of shift_sdpram_32x24 is
    type ram_type is array (0 to 31) of STD_LOGIC_VECTOR(23 downto 0);
    signal ram : ram_type := (others => (others => '0'));
    signal wr_ptr, rd_ptr : integer range 0 to 31 := 0; -- Write and read pointers
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if we = '1' then
                -- Write operation
                ram(wr_ptr) <= d;
                wr_ptr <= (wr_ptr + 1) mod 32; -- Increment write pointer with wrap-around
            end if;
            if qdpo_ce = '1' then
                -- Read operation
                qdpo <= ram(rd_ptr);
                rd_ptr <= (rd_ptr + 1) mod 32; -- Increment read pointer with wrap-around
            end if;
        end if;
    end process;
end Behavioral;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值