xpm_memory_tdpram原语的完整使用实例

9 篇文章 16 订阅
6 篇文章 2 订阅

参考UG573和UG974。

一、xpm_memory_tdpram原语介绍

xpm_memory_tdpram #(
      .ADDR_WIDTH_A(16),               // DECIMAL,A口地址[15:0]
      .ADDR_WIDTH_B(16),               // DECIMAL,B口地址[15:0]
      .AUTO_SLEEP_TIME(0),            // DECIMAL
      .BYTE_WRITE_WIDTH_A(72),        // DECIMAL A口写宽度为72,4个像素点
      .BYTE_WRITE_WIDTH_B(72),        // DECIMAL B口写宽度为72,4个像素点
      .CASCADE_HEIGHT(0),             // DECIMAL
      .CLOCKING_MODE("common_clock"), // String

      .ECC_MODE("no_ecc"),            // String
//      .MEMORY_INIT_FILE("none"),      // String
      .MEMORY_INIT_FILE("triangle_192_256.mem"),      // String
      .MEMORY_INIT_PARAM("0"),        // String
      .MEMORY_OPTIMIZATION("true"),   // String
      .MEMORY_PRIMITIVE("ultra"),      // String
      .MEMORY_SIZE(3538944),             // DECIMAL 内存bits数,192*1024*18=192*256*72=3538944,生成192行1024列的图像,18为图像颜色的深度
      .MESSAGE_CONTROL(0),            // DECIMAL 禁能消息报告
      .READ_DATA_WIDTH_A(72),         // DECIMAL A口读数据位宽[71:0],4个像素点
      .READ_DATA_WIDTH_B(72),         // DECIMAL B口读数据位宽[71:0],4个像素点
      .READ_LATENCY_A(1),           // DECIMAL 读延迟1个时钟 内存大于2MB时,延迟必须大于8
      .READ_LATENCY_B(1),           // DECIMAL 读延迟1个时钟 内存大于2MB时,延迟必须大于8
      .READ_RESET_VALUE_A("0"),       // String
      .READ_RESET_VALUE_B("0"),       // String
      .RST_MODE_A("SYNC"),            // String
      .RST_MODE_B("SYNC"),            // String
      .SIM_ASSERT_CHK(0),             // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
      .USE_EMBEDDED_CONSTRAINT(0),    // DECIMAL
      .USE_MEM_INIT(0),               // DECIMAL
      .USE_MEM_INIT_MMI(0),           // DECIMAL
      .WAKEUP_TIME("disable_sleep"),  // String
      .WRITE_DATA_WIDTH_A(72),        // DECIMAL A口读数据位宽[71:0],4个像素点
      .WRITE_DATA_WIDTH_B(72),        // DECIMAL B口读数据位宽[71:0],4个像素点
      .WRITE_MODE_A("no_change"),     // String
      .WRITE_MODE_B("no_change"),     // String
      .WRITE_PROTECT(1)               // DECIMAL,使用写使能信号
   )
ram_inst (
      .dbiterra(),// 1-bit output: 指示A口数据输出有双bits错误发生
      .dbiterrb(),// 1-bit output: 指示B口数据输出有双bits错误发生
      .sbiterra(),// 1-bit output: 指示A口数据输出有单bits错误发生
      .sbiterrb(), // 1-bit output: 指示B口数据输出有单bits错误发生
      .ena(1'b1), //RAM A口使能信号,高电平有效  
      .enb(1'b1), //RAM B口使能信号,高电平有效  
      .injectdbiterra(1'b0),//控制双bits错误注入 
      .injectdbiterrb(1'b0),//控制双bits错误注入 
      .injectsbiterra(1'b0),//控制单bits错误注入 
      .injectsbiterrb(1'b0),//控制单bits错误注入 
      .regcea(1'b1), //输入端口,输出数据路径的上一个寄存器阶段,时钟使能
      .regceb(1'b1), //输入端口,输出数据路径的上一个寄存器阶段,时钟使能
      .rsta(1'b0), //复位信号,高电平有效 
      .rstb(1'b0),//复位信号,高电平有效
      .sleep(1'b0), //高电平使能动态降低功耗功能,此处禁能 
      
      .douta(douta), //READ_DATA_WIDTH_A bits 输出,[71:0],B口读数据
      .doutb(doutb), //READ_DATA_WIDTH_B bits 输出,[71:0],B口读数据
      .addra(addra),//ADDR_WIDTH_A bits输入 [15:0]A口写地址
      .addrb(addrb),//ADDR_WIDTH_B bits输入 [15:0]B口写地址
      .clka(clk_300M), //A口输入时钟
      .clkb(clk_300M), //B口输入时钟
      .dina(dina), // WRITE_DATA_WIDTH_A bits A口数据输入[71:0]
      .dinb(dinb),  // WRITE_DATA_WIDTH_B bits B口数据输入[71:0]

      .wea(wea), //A口写使能信号,宽度为 WRITE_DATA_WIDTH_A / BYTE_WRITE_WIDTH_A  =72/72=1 
      .web(web) //B口写使能信号,宽度为 WRITE_DATA_WIDTH_B / BYTE_WRITE_WIDTH_B  =72/72=1 

   );

         当需要指定RAM内初始化数值时,可以使用原语中的参数MEMORY_INIT_FILE,指向一个尾缀为.mem的文件。该文件内的内容要求必须时十六进制的,与$readmemh函数读取的文件内容格式一致,用空格或者回车将数据隔开即可。

        另外需要注意的是,本着节约使用ultra RAM的想法,一个ultra RAM的数据位宽为72bits,因此72bits拆分为18bits,即ultra RAM的一个地址上,保存着4个18bits的像素数据。

 二、如何生成.mem文件

        借助于matlab,与生成.coe文件类似,matlabl示例程序如下:


M = 192;
N = 1024 ;
y = zeros(M , N) ;%生成192行1024列的矩阵
for i = 1:1:M
    for j = 1:1:N
        if(j <= N/2) %锯齿波,从0到512时,下降斜率直线
            if( i == round(191/512*j)) 
                y(i,j) = 255 ;%出现在斜率线附近的点赋值255
            else
                y(i,j) = 0 ;%不在斜率线附近的点赋值0
            end
        end
        if(j > N/2)%%锯齿波,从512到1024时,上升斜率直线
            if( i == round(382-191/511*j) ) 
                y(i,j) = 255 ;%出现在斜率线附近的点赋值255
            else
                y(i,j) = 0 ;%不在斜率线附近的点赋值0
            end
        end
    end
end   
imshow(y)

%  plot(y(i,j));%绘图预览

%y矩阵4个点拼成1个点
fpga_y_dec = zeros(M , N/4) ;
fpga_y_dec_49152=zeros(49152,1);%将矩阵变为1列
fpga_y_hex = zeros(M*N/4,8) ;
for i = 1:1:M
    for j = 1:1:N/4
        fpga_y_dec(i,j)=y(i,4*j-3)*256*256*256+y(i,4*j-2)*256*256+y(i,4*j-1)*256+y(i,4*j);
        fpga_y_dec_49152(i*256-256+j,1)=fpga_y_dec(i,j);
    end
end




fpga_y_hex= dec2hex(fpga_y_dec_49152);     

        
fid1 = fopen('triangle_192_256.mem','wt');    
%COE文件格式
% fprintf( fid1, 'MEMORY_INITIALIZATION_RADIX = 16;\n');                     
% fprintf( fid1, 'MEMORY_INITIALIZATION_VECTOR =\n');
%输出十进制数据,保存至文件
for i = 1:1:49152
    if(i == 49152)
        fprintf(fid1,'%s%c%c%c%c%c%c%c%c',"0000000000",fpga_y_hex(i,1),fpga_y_hex(i,2),fpga_y_hex(i,3),fpga_y_hex(i,4),fpga_y_hex(i,5),fpga_y_hex(i,6),fpga_y_hex(i,7),fpga_y_hex(i,8)); %最后一个点时,标点为分号,其余时候为逗号
    else
        fprintf(fid1,'%s%c%c%c%c%c%c%c%c\n',"0000000000",fpga_y_hex(i,1),fpga_y_hex(i,2),fpga_y_hex(i,3),fpga_y_hex(i,4),fpga_y_hex(i,5),fpga_y_hex(i,6),fpga_y_hex(i,7),fpga_y_hex(i,8));
    end
end
fclose(fid1);%关闭文件

        生成 如下图所示的三角波图像:

         生成的文件的部分内容如下:

 

 三、仿真xpm_memory_tdpram原语

         仿真xpm_memory_tdpram原语原语,将初始化文件内容读出,观察是否与文件内容一致。

`timescale 1ns/1ps
module	 top();

reg clk_100M = 1'b0;
reg rst = 1'b1;
reg rd_enable =1'b0;
//生成100M时钟
always 
begin
    #5
        clk_100M <= ~clk_100M;
end

//延迟100ns,复位拉高
initial
begin
    #100 rst <= 1'b0;
    #200 rd_enable <= 1'b1;
end

wire [71:0] douta;
wire [71:0] doutb;
reg [15:0] addra =0;
reg [15:0] addrb =0;

wire [71:0] dina;
wire [71:0] dinb;
wire  wea;
wire  web;

//不写入新的数据,仅读
assign dina = 72'b0;
assign dinb = 72'b0;
assign wea = 1'b0;
assign web = 1'b0;

always@(posedge clk_100M)
begin
    if(rd_enable) begin
        addra <= addra + 1'b1;
        addrb <= addrb + 1'b1;
    end
end


xpm_memory_tdpram #(
      .ADDR_WIDTH_A(16),               // DECIMAL,A口地址[15:0]
      .ADDR_WIDTH_B(16),               // DECIMAL,B口地址[15:0]
      .AUTO_SLEEP_TIME(0),            // DECIMAL
      .BYTE_WRITE_WIDTH_A(72),        // DECIMAL A口写宽度为72,4个像素点
      .BYTE_WRITE_WIDTH_B(72),        // DECIMAL B口写宽度为72,4个像素点
      .CASCADE_HEIGHT(0),             // DECIMAL
      .CLOCKING_MODE("common_clock"), // String

      .ECC_MODE("no_ecc"),            // String
//      .MEMORY_INIT_FILE("none"),      // String
      .MEMORY_INIT_FILE("triangle_192_256.mem"),      // String
      .MEMORY_INIT_PARAM("0"),        // String
      .MEMORY_OPTIMIZATION("true"),   // String
      .MEMORY_PRIMITIVE("ultra"),      // String
      .MEMORY_SIZE(3538944),             // DECIMAL 内存bits数,192*1024*18=192*256*72=3538944,生成192行1024列的图像,18为图像颜色的深度
      .MESSAGE_CONTROL(0),            // DECIMAL 禁能消息报告
      .READ_DATA_WIDTH_A(72),         // DECIMAL A口读数据位宽[71:0],4个像素点
      .READ_DATA_WIDTH_B(72),         // DECIMAL B口读数据位宽[71:0],4个像素点
      .READ_LATENCY_A(0),             // DECIMAL
      .READ_LATENCY_B(0),             // DECIMAL
      .READ_RESET_VALUE_A("0"),       // String
      .READ_RESET_VALUE_B("0"),       // String
      .RST_MODE_A("SYNC"),            // String
      .RST_MODE_B("SYNC"),            // String
      .SIM_ASSERT_CHK(0),             // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
      .USE_EMBEDDED_CONSTRAINT(0),    // DECIMAL
      .USE_MEM_INIT(0),               // DECIMAL
      .USE_MEM_INIT_MMI(0),           // DECIMAL
      .WAKEUP_TIME("disable_sleep"),  // String
      .WRITE_DATA_WIDTH_A(72),        // DECIMAL A口读数据位宽[71:0],4个像素点
      .WRITE_DATA_WIDTH_B(72),        // DECIMAL B口读数据位宽[71:0],4个像素点
      .WRITE_MODE_A("no_change"),     // String
      .WRITE_MODE_B("no_change"),     // String
      .WRITE_PROTECT(1)               // DECIMAL,使用写使能信号
   )
ram_inst (
      .dbiterra(),// 1-bit output: 指示A口数据输出有双bits错误发生
      .dbiterrb(),// 1-bit output: 指示B口数据输出有双bits错误发生
      .sbiterra(),// 1-bit output: 指示A口数据输出有单bits错误发生
      .sbiterrb(), // 1-bit output: 指示B口数据输出有单bits错误发生
      .ena(1'b1), //RAM A口使能信号,高电平有效  
      .enb(1'b1), //RAM B口使能信号,高电平有效  
      .injectdbiterra(1'b0),//控制双bits错误注入 
      .injectdbiterrb(1'b0),//控制双bits错误注入 
      .injectsbiterra(1'b0),//控制单bits错误注入 
      .injectsbiterrb(1'b0),//控制单bits错误注入 
      .regcea(1'b1), //输入端口,输出数据路径的上一个寄存器阶段,时钟使能
      .regceb(1'b1), //输入端口,输出数据路径的上一个寄存器阶段,时钟使能
      .rsta(rst), //复位信号,高电平有效 
      .rstb(rst),//复位信号,高电平有效
      .sleep(1'b0), //高电平使能动态降低功耗功能,此处禁能 
      
      .douta(douta), //READ_DATA_WIDTH_A bits 输出,[71:0],B口读数据
      .doutb(doutb), //READ_DATA_WIDTH_B bits 输出,[71:0],B口读数据
      .addra(addra),//ADDR_WIDTH_A bits输入 [15:0]A口写地址
      .addrb(addrb),//ADDR_WIDTH_B bits输入 [15:0]B口写地址
      .clka(clk_100M), //A口输入时钟
      .clkb(clk_100M), //B口输入时钟
      .dina(dina), // WRITE_DATA_WIDTH_A bits A口数据输入[71:0]
      .dinb(dinb),  // WRITE_DATA_WIDTH_B bits B口数据输入[71:0]

      .wea(wea), //A口写使能信号,宽度为 WRITE_DATA_WIDTH_A / BYTE_WRITE_WIDTH_A  =72/72=1 
      .web(web) //B口写使能信号,宽度为 WRITE_DATA_WIDTH_B / BYTE_WRITE_WIDTH_B  =72/72=1 

   );
   

endmodule



        另外,wea的信号宽度为WRITE_DATA_WIDTH_A / BYTE_WRITE_WIDTH_A。 当WRITE_DATA_WIDTH_A=72,BYTE_WRITE_WIDTH_A=9时,wea的信号宽度为72/9=8。

        可以通过wea的某一位或者某几位有效,控制72bits中对应的9bits数据写入到UltraRAM中。比如wea=8'b0000_0011,那么dina[71:0]中的低18bits写入到ultraRAM中,其余bits位不变。

        web同理。

        根据仿真结果,发现,设置READ_LATENCY_A和READ_LATENCY_B为0时,在地址有效后一个时钟后,ultraRAM数据输出。

四、其他需要注意的事项

         使用ultraRAM时,对xpm_memory_tdpram赋值初始化数据,仅可用于仿真,无法用于综合布局布线。(综合时会自动使用BRAM或者报错)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值