FPGA RAM简介和使用案例

在fpga 逻辑设计中经常用到的数据存储方式有rom、ram和fifo,根据不同的应用场景选择不同的存储方式。xilinx 平台三种存储方式在使用过程中的区别如下:
1、rom按照地址读写,使用初始化.ceo文件将地址和对应的数据内容存入,读数据的时候给地址,输出地址中存储的数据。支持反复读取,读取过程中不会使数据减少;
2、ram按照地址读写数据,按照指定的地址写入数据,读数据的时候给地址,输出地址中存储的数据,支持反复读取,读取过程中不会使数据减少;
3、fifo没有地址参与,先写入的数据被先读出,就是先进先出,读取数据的过程中读一个少一个,就像鸡蛋放在篮子中取出一个少一个。
01 ram简介
ram,random access memory,是随机存取存储器的缩写,掉电后数据丢失。 这里使用简单双端口ram举例,即端口a写数据,端口b读数据。
端口a写入数据的过程中wea==1'b1 && ena==1'b1,条件同时满足的时候,dina的数据被写入到指定的内存地址中。
端口b读出数据的时候,读使能和读地址同时有效,读出数据需要延迟一个时钟周期。
1.1、vivado中添加ram-ip核
step1:在ip-catalog中搜索ram,找到 block memory generator
step2:在ip核配置
step3:端口a设置(写入数据位宽和深度)
step4:端口b设置(注意细节)
step5:其他设置
02 ram使用案例
2.1、简单双端口ram使用案例
简单双端口ram使用的案例有1、数据缓冲-实现位宽转化;2、对应连续待处理的数据流使用乒乓ram,实现数据流不间断的输入到处理模块。本文主要对乒乓ram做一个详细介绍和测试应用。
2.2、乒乓ram读写时序设计
乒乓ram读写时序设计波形图中读写时钟使用了相同的时钟信号,当读写数据的时钟不同时,就是异步乒乓ram。首先对rama写入数据,按地址写入数据结束以后读取rama的数据给数据处理模块,同时将外部输入的数据缓存到ramb中,保证同一时间内既有数据缓存又有数据输出,实现的效果就是外部不间断地输入数据,经过ram处理以后不间断地输出到下一级处理模块。
图2-2-1、乒乓ram读写时序设计
2.3、代码实现
根据时序设计波形图2-2-1,编写逻辑代码,`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// company: // engineer: // // create date: 2022/01/08 19:19:47// design name: // module name: pingpang_ram// project name: // target devices: // tool versions: // description: // // dependencies: // // revision:// revision 0.01 - file created// additional comments:// //////////////////////////////////////////////////////////////////////////////////module pingpang_ram(input wire sclk,input wire async_rst_n, input wire wr_valid, input wire [7:0] data_in,output wire [7:0] data_out );// 信号定义 localparam addr_max = 1024 - 1; // rama reg wr_en_a;reg [9 : 0] wr_addr_a; // 写地址 reg rd_en_a;reg [9 : 0] rd_addr_a; // 读地址 wire [7 : 0] rd_data_a; reg wr_en_a_dly;// ramb reg wr_en_b;reg [9 : 0] wr_addr_b; // 写地址 reg rd_en_b;reg [9 : 0] rd_addr_b; // 读地址 wire [7 : 0] rd_data_b; // wire sync_rst_n; reg sync_rst_n1; reg sync_rst_n2; assign sync_rst_n = sync_rst_n2 ;assign data_out = (wr_en_a_dly == 1'b0 ) ? rd_data_a : rd_data_b; // 符合条件后---立即响应 // 异步复位,同步释放,异步复位信号,同步处理always@(posedge sclk or negedge async_rst_n) begin if(!async_rst_n) begin sync_rst_n1 <= 1'b0; // 复位开始的时候 wr_en 就开始有效 sync_rst_n2 <= 1'b0; end else begin sync_rst_n1 <= 1'b1; sync_rst_n2 <= sync_rst_n1; end end // wr_en always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin wr_en_a <= 1'b0; end else if (wr_valid == 1'b1 ) begin wr_en_a <= 1'b1; end else if(wr_addr_a == addr_max) begin wr_en_a <= 1'b0; end else if(rd_addr_a == addr_max) begin wr_en_a <= 1'b1; end end // 写地址信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin wr_addr_a <= 16'd0; end else if(wr_addr_a == addr_max) begin wr_addr_a <= 16'd0; end else if(wr_en_a == 1'b1 ) begin wr_addr_a <= wr_addr_a + 1'b1; end end // 读使能信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin rd_en_a <= 1'b0; end else if(wr_addr_a == addr_max) begin rd_en_a <= 1'b1; end else if (rd_addr_a == addr_max) begin rd_en_a <= 1'b0; end end always@(posedge sclk or negedge sync_rst_n) begin wr_en_a_dly <= wr_en_a; end // 读地址信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin rd_addr_a <= 10'd0; end else if(rd_addr_a == addr_max) begin rd_addr_a <= 10'd0; end else if(rd_en_a == 1'b1) begin rd_addr_a <= rd_addr_a + 1'b1; end end // ---------ramb always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin wr_en_b <= 1'b0; end else if(wr_addr_b == addr_max) begin wr_en_b <= 1'b0; end else if(wr_addr_a == addr_max) begin // 写完rama -开始写ramb wr_en_b <= 1'b1; end end // 写地址信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin wr_addr_b <= 16'd0; end else if(wr_addr_b == addr_max) begin wr_addr_b <= 16'd0; end else if(wr_en_b == 1'b1 ) begin wr_addr_b <= wr_addr_b + 1'b1; end end // 读使能信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin rd_en_b <= 1'b0; end else if(wr_addr_b == addr_max) begin rd_en_b <= 1'b1; end else if (rd_addr_b == addr_max) begin rd_en_b <= 1'b0; end end // 读地址信号 always@(posedge sclk or negedge sync_rst_n) begin if(!sync_rst_n) begin rd_addr_b <= 10'd0; end else if(rd_addr_b == addr_max) begin rd_addr_b <= 10'd0; end else if(rd_en_b == 1'b1) begin rd_addr_b <= rd_addr_b + 1'b1; end end //----------- begin cut here for instantiation template ---// inst_tagram_8x1024 a_instance_name ( .clka(sclk), // input wire clka .ena(wr_en_a), // input wire ena .wea(wr_en_a), // input wire [0 : 0] wea .addra(wr_addr_a), // input wire [9 : 0] addra .dina(data_in), // input wire [7 : 0] dina .clkb(sclk), // input wire clkb .enb(rd_en_a), // input wire enb .addrb(rd_addr_a), // input wire [9 : 0] addrb .doutb(rd_data_a) // output wire [7 : 0] doutb);//----------- begin cut here for instantiation template ---// inst_tagram_8x1024 b_instance_name ( .clka(sclk), // input wire clka .ena(wr_en_b), // input wire ena .wea(wr_en_b), // input wire [0 : 0] wea .addra(wr_addr_b), // input wire [9 : 0] addra .dina(data_in), // input wire [7 : 0] dina .clkb(sclk), // input wire clkb .enb(rd_en_b), // input wire enb .addrb(rd_addr_b), // input wire [9 : 0] addrb .doutb(rd_data_b) // output wire [7 : 0] doutb);endmodule仿真激励文件
`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// company: // engineer: // // create date: 2022/01/08 20:24:11// design name: // module name: tb_pingpang_ram// project name: // target devices: // tool versions: // description: // // dependencies: // // revision:// revision 0.01 - file created// additional comments:// //////////////////////////////////////////////////////////////////////////////////module tb_pingpang_ram();reg sclk;reg async_rst_n;reg wr_valid;reg [7:0] data_in;wire [7:0] data_out;initial begin sclk = 0;forever #5sclk = ~sclk;end initial begin async_rst_n <= 0; wr_valid <= 0; #100 async_rst_n <= 1; #10 @(posedge sclk) @(posedge sclk) @(posedge sclk) @(posedge sclk) wr_valid <= 1; #10 wr_valid <= 0; gen_data( );end //@(posedge wr_valid)//gen_data( );//end task gen_data;integer i; begin for(i= 0; i < 12288; i = i + 1) begin @(posedge sclk) data_in = i[7:0]; end end endtask pingpang_ram u_pingpang_ram( .sclk ( sclk ), .async_rst_n ( async_rst_n ), .wr_valid ( wr_valid ), .data_in ( data_in ), .data_out ( data_out ));endmodule2.4、仿真验证结果
图2-2-1、乒乓ram仿真结果-输出数据连续
图2-2-2、乒乓ram仿真结果-输入-输出数据对应

CodeWeavers 宣布 CrossOver 20 可以在 Apple Silicon Mac 上运行
微雪电子智能车学习板蓝牙Arduino开发板介绍
UPS 常用电池种类优缺点分析
电磁兼容设计中有哪些接地技术
智能化消费级路由器——为家庭网络设备注入新活力
FPGA RAM简介和使用案例
联想小新蓝牙鼠标深色静音版正式上架京东
Mini LED背光显示:逆势成长,引领产业升级
LED技术让冰灯拆除 拒绝汞污染
无人值守智能化改造10kV配电室环境监控系统
未来满天无人机比满地汽车更安全
温控/光控集成块CA3059构成的温度控制电路
电源滤波器选型注意事项
小米生态链企业创米发布一款小白智能看护灯
哪一些因素架构工业物联网三大方面
用于交互式激光投影应用的MEMS扫描仪BML050
拆解USB无线网卡过程
常见流量仪表选型原则和方法
导电剂含量对电性能的影响
日美澳将展开合作以降低对锂电池原料的依赖