Menu Close

Quartus 双口RAM例化详解

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

1.双口RAM的生成步骤

  • 在Quartus新建工程, 工程名为dpram,顶层实体为dpram,如图1, 器件选择Cyclone 10 LP 10CL006YE144C8G,仿真选择Modelsim_Altera

图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的数据端口宽度和深度。

图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位单元阵列。

图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; rden_b=1’b0; 因此在使用时一定要注意。
  • 这里勾选添加rden_a,rden_b两个读使能信号。

 

图4

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

 

图5

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

 

图6

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

 

图7

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

 

图8

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

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

a端口(verilog格式):
    data_a[15:0],   //a端口 输入数据
    address_a[8:0], //a端口 地址
    wren_a,         //a端口 写使能 
    rden_a,         //a端口 读使能 
    q_a[15:0],      //a端口 输出端口
    clock_a,        //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端口 时钟

 

2.双口RAM测试

  • 新建Verilog文件 dpram.v(模块名dpram,与工程的顶层实体名一致)
  • 例化新生成的双口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

 

后续课程将使用本节课生成的双端口RAM进行测试。

 

对应视频:

Posted in FPGA, FPGA 教材教案, FPGA硬件资源, Quartus II, Quartus II, Verilog, Verilog, Vivado, Vivado, 开发语言, 教材与教案, 文章, 编程语言

发表回复

相关链接