Menu Close

Quartus II 双口RAM例化详解

Quartus II 双口RAM例化详解

上节内容讲解了单口RAM及使用,本节着重介绍双口RAM及使用。由于双口RAM作为FPGA片上RAM应用极其广泛,使用相对灵活,是FPGA学习中应重点掌握的内容。目前双口RAM在CPU内存,程序存储器,数据缓存,数字信号处理,图像处理,通信等领域几乎是必不可少的部件,他与FIFO在数据缓存处理方面是一把双刃剑,学好双口RAM和FIFO是FPGA进阶学习的必经之路。

  1. 双口RAM的生成步骤
    • 在Quartus II 新建工程, 工程名为dpram, 顶层实体为dpram,如图1, 器件选择Cyclone 10 LP 10CL006YE144C8G, 仿真选择Modelsim_Altera

%title插图%num 图1

    • 在新建的工程中添加双口RAM, 在IP Catalog区选择Install IP –>Libarary–>Basic Function–>On Chip Memory–>RAM :2-PORT, 双击,
    • 在弹出的对话框中输入将生成的双口RAM变体的名称d_p_ram.
    • 在图2中选择with two read /write ports,这是真正双口RAM的选择, 如果选择with one read port and one write port, 就是上节内容讲的单口RAM,双口RAM分为两个全功能端口,分别为a端口和b端口。a端口的接口为data_a, address_a,wren_a为输入端口,rden_a, q_a为输出端口。b端口同样也是data_b,address_b,wren_b为输入端口,rden_b,q_b为输出端口。
    • RAM尺寸选择,按字指定。也可以按 bit指定RAM的数据端口宽度和深度。

%title插图%num

图2

    • 图3中选择数据宽度(根据,需要可以选择8位,9位,16位,18位,32位,36位等),如果选择16位,数据端口即为q_a[15..0],q_b[15..0],data_a[15..0],data_b[15..0]都是16位。也可以选择a端口与b端口的数据宽度不等,例如会经常使用的情况a端口是16位写入,b端口32位输出的情况,具体怎么使用主要根据需求设置。
    • 根据工程的实际需求设置数据深度,这里数据深度选择512,即存储器阵列可以有512个16位单元阵列。

%title插图%num

图3

    • 图4中选择时钟的使用情况,可以使用单一时钟,也可以读、写分开使用不同时钟,但更多的是a,b端口使用不同的时钟。在a,b端口使用不同时钟时要注意在访问同一单元时亚稳态的情况,个与寄存器在不同时钟域的访问类似。后面会介绍在亚稳态的情况下,如何利用读写协议避免访问出错的情况。在a, b端口异步时钟的情况下,应避免使用数据拷贝的方式,也就是在读写时访问同一端口的情况下,避免使用new data选项。
    • 添加rden_a, rden_b端口,可以在在写过程中当地址变化时通过设置rden_a,rden_b禁止q_a,q_b的端口数据变化,从而降低功耗。
    • 如果数据连续读写,而且地址线与时钟同步,rden_a, rden_b端口可以设为常数1’b1;
    • 对于rden_a, rden_b也可以在生成的时候不选择该项,此时默认为rden_a=1’b1; rden_b=1’b1; 但是如果选择了生成该项,如果在例化中忽略该项则默认rden_a=1’b0;den_b=1’b0; 因此在使用时一定要注意。

%title插图%num

图4

    • 图5设置输入、输出端口寄存方式,与单口RAM一致,这里不在详细解释。

%title插图%num

图5

    • 图6中创建时钟使能信号端口,在非操作双口RAM时,可以降低功耗。如data_a或data_b以及address的变化可能还有其它操作会使用(共享的端口),如果添加时钟使能,并在这些端口变化时保持enable_a,enable_b为低电平,则保持生成的IPCore 内的这些寄存器不翻转,从而降低功耗。本节的测试例子中没有添加时钟使能端的情况。

%title插图%num

图6

    • 图中选项是当访问的存储器的内容恰好出现读、写同一单元的情况,这里有4中可能的情况,a端口出现读写同一单元,b端口出现读写同一单元, a端口写于b端口读同一单元,b端口写与a端口读同一单元。当出现这4中组合时,在读端口选择读存储器的已有的旧数据还是当前正在更新的数据。原则如下:当读写是同一个时钟时(时钟同步)可以选择是旧数据(old data),也可以选择新数据(new data),特别是在作为CPU内存使用时,会出现流水线中上次写的数据,在本次希望程序执行时要用到该数据,但由于写数据有延迟,如果读旧数据将会得到过时的数据,引起程序执行错误,可以参见RISC-V CPU IPcore设计部分。

%title插图%num

图7

    • 图8 设计双口RAM中的初始化文件* .mif或.hex文件,这里的设置与ROM初始化相同,参照ROM的.mif文件的设置与使用。

%title插图%num

图8

    •  点击finish,并将产生的双端口RAM添加到工程中进行测试。

总结:在上面的步骤中生成了名为d_p_ram的双口RAM,两个端口分别为:

a端口(verilog格式):
    data_a[15:0],
    address_a[8:0],
    wren_a,
    rden_a,
    q_a[15:0],
    clock_a,
b端口(verilog格式):
    data_b[15:0],   //b端口 输入数据
    address_b[8:0], //b端口地址
    wren_b,         //b端口写使能
    rden_b,         //b端口读使能
    q_b[15:0] ,     //b端口输出端口
    clock_b,        //b端口 时钟
  1. 双口RAM测试
  2. 新建verilog文件 dpram.v(模块名dpram,与工程的顶层实体名一致)
  3. 例化新生成的双口RAM,并将a,b端口重新整理,代码如下:

module dpram
(
//==================================a side
    input         inclka,
    input  [8:0]  address_a,
    input  [15:0] data_a,
    input         wren_a,
    input         rden_a,
    output [15:0] q_a, 

//==================================b side
    input         inclkb,
    input  [8:0]  address_b,
    input  [15:0] data_b,
    input         wren_b,
    input         rden_b,
    output [15:0] q_b
);

d_p_ram  d_p_ram_inst
(
    .clock_a   (inclka),
    .address_a (address_a),
    .data_a    (data_a),    //data --write to memory
    .rden_a    (rden_a),
    .wren_a    (wren_a),
    .q_a       (q_a),       //read, data out from memory

    .clock_b   (inclkb),
    .address_b (address_b),
    .data_b    (data_b),
    .rden_b    (rden_b),
    .wren_b    (wren_b),
    .q_b       (q_b)
);

endmodule


  

 

Posted in FPGA, Quartus II, Verilog, Verilog, Vivado, 开发语言, 教材与教案, 文章

发表评论

相关链接