FPGA--RAM

一、基本介绍

这一部分我在csdn找到了一篇计算机组成的文章,大家可以通过这个通俗易懂的文章进行学习

计算机组成与体系结构:RAM(随机存取存储器)

RAM:

单端口:只有一个端口,读写不能同时进行,共用数据通道

将单端口的写功能关闭,只用读端口,可以当作room使用,具体后续文章会补充

伪双端口(SDP):有两个端口,一个用来读,一个用来写,分工明确

真双端口:有两个端口,各自都能读或者写

二、实验部分(ip核配置)

1基本介绍

我们实验部分主要是用一个ram,0-31存数据,然后32-63将数据读出

2ip核配置(1)

创建好.v文件,点击IP catlog,搜索ram,选择block memory generator

对于第一个,interface type可以选native或者AXI4,我们选native(普通版)就行

对于第二个,memory type,我们可以选的类型就比较多了

从上到下依次是,单端口,伪双端口,真双端口,单端ROM,双端ROM

其中ROM就是把我们的RAM的写功能禁止了,只能用来读数据

第三个,ECC Options

这实现的是纠错功能(但是对于我们的单端口,是无法选中这个功能的),只有伪双端口才有这个纠错功能

第四个,write enable(写使能)

勾选之后,按照一字节一字节进行写数据(数据只能是8位或者9位的整数倍)

第五个,algorithm options

这一部分选择有三个,从上到下依次是最小面积,最低功耗,固定原语

primitive是他的默认容量,我这边是8kx2

3ip核配置(2)

首先memory width配置,我们需要配置写位宽,读位宽,写的数据量,读的数据量

operating mode里面用来选择我们是写优先/读优先

enable port type:使能功能,可选always enable(一直使能)或者use ENA pin(给一个信号来控制使能)

port A optional output register:输出寄存器,如果勾选之后,RAM的输出数据会在这个寄存器里面缓冲,然后释放数据,使得数据有延迟

但是这不意味着我们就一定不用勾选他,勾选不勾选都有各自的利弊

不勾选:造成时序的不严谨,造成错误的数据

port A output reset options:复位

接下来简单介绍一下现在的各个引脚:

从上到下依次是,地址位,时钟,数据输入,数据输出,使能,读写切换

4ip核配置(3)

这一部分我们用作RAM的直接默认即可,如果后续我们采用这个ip核配置ROM的话,我们需要在这里加载一个coe文件

三、IP核例化使用

1、例化ip核

首先,找到我们的例化模板,注意是veo文件

2、编写读写模块

我们需要一个读写模块来驱动这个ram的ip核,新建一个v文件,命名为ram_rw

这部分的数据和地址都是由计数器提供的

复制代码
module ram_rw(
input                     clk,
input                     rst_n,

//ram ip核需要一个使能信号,定义成reg型,后续用always进行赋值
output reg                ram_en,
//ram ip核需要读写切换,定义成reg型
output reg                rw,
//ram ip核需要地址信号,5位二进制数则是2^5=32位,定义成reg型
output reg [4:0]          ram_addr,
//ran ip核写数据,数据位宽8位
output reg [7:0]          ram_wr_data,
    );
endmodule

//定义一个计数器判断什么时候该读数据,什么时候写数据,由于我们题目说0-31写数据,32-63读数据,64个数字需要6位数据位宽
reg [5:0] rw_cnt;

//ram ip核使能部分
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        ram_en<=1'b0;
    else
        ram_en<=1'b1;
end

//1、读写计数器逻辑
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        rw_cnt<=6'd0;
    else if(rw_cnt==6'd63)
        rw_cnt<=6'd0;
    else 
        rw_cnt<=rw_cnt+6'd1;
end

//2、读写切换逻辑
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        rw<=1'b1;//默认写状态
    else if(rw_cnt<6'd31)
        rw<=1'b1;//写状态,由于读写数据处理考虑使能,这里可以不用考虑,直接切换读写状态
    else
        rw<=1'b0;//读状态
end
    


//3、读写数据处理
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        ram_wr_data<=8'd0;
        //写数据逻辑,注意需要使能
    else if((rw_cnt<=6'd31)&&ram_en)
        ram_wr_data<=ram_wr_data+8'd1;//由于题目中数据也是0-31,所以直接类似计数器即可
    else
        ram_wr_data<=ram_wr_data;//如果未使能/不在写数据阶段,就保存数据
end

//4、读写地址处理
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        ram_addr<=5'd0;
    else
        ram_addr<=rw_cnt[4:0];//地址同样由计数器决定,为了不超位数,只取计数器的低5位
end

四、编写代码

1、添加读写模块进入主文件

将ram和读写模块例化

复制代码
`timescale 1ns / 1ps


module ip_ram(
    input    sys_clk,
    input    sys_rst_n
  

    );

wire   ram_en;
wire   rw;
wire  [4:0] ram_addr;
wire  [7:0] ram_wr_data;
wire  [7:0] douta;

ram_rw ram_rw_inst(
    .clk(sys_clk),
    .rst_n(sys_rst_n),
    .ram_en(ram_en),
    .rw(rw),
    .ram_addr(ram_addr),
    .ram_wr_data(ram_wr_data)
    );


blk_mem_gen_0 ram_inst (
  .clka(sys_clk),    // input wire clka
  .ena(ram_en),      // input wire ena
  .wea(rw),      // input wire [0 : 0] wea
  .addra(ram_addr),  // input wire [4 : 0] addra
  .dina(ram_wr_data),    // input wire [7 : 0] dina
  .douta(douta)  // output wire [7 : 0] douta
);
endmodule

2、对引脚进行配置

点击右上方的I/O planing

注意检查一下约束文件对于时钟是否已经配置好50mhz了,我是经常配置出问题

复制代码
# 时钟物理约束
set_property PACKAGE_PIN N18 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]

# 复位物理约束
set_property PACKAGE_PIN D19 [get_ports sys_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]

# 关键:时钟时序约束(50MHz -> 20ns 周期)
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]

3、添加ila信号

在顶层模块连接好

复制代码
`timescale 1ns / 1ps


module ip_ram(
    input    sys_clk,
    input    sys_rst_n
  
    
    );

wire   ram_en;
wire   rw;
wire  [4:0] ram_addr;
wire  [7:0] ram_wr_data;
wire  [7:0] douta;

ram_rw ram_rw_inst(
    .clk(sys_clk),
    .rst_n(sys_rst_n),
    .ram_en(ram_en),
    .rw(rw),
    .ram_addr(ram_addr),
    .ram_wr_data(ram_wr_data)
    );


blk_mem_gen_0 ram_inst (
  .clka(sys_clk),    // input wire clka
  .ena(ram_en),      // input wire ena
  .wea(rw),      // input wire [0 : 0] wea
  .addra(ram_addr),  // input wire [4 : 0] addra
  .dina(ram_wr_data),    // input wire [7 : 0] dina
  .douta(douta)  // output wire [7 : 0] douta
);

ila_0 your_instance_name (
	.clk(sys_clk), // input wire clk


	.probe0(ram_en), // input wire [0:0]  probe0  
	.probe1(rw), // input wire [0:0]  probe1 
	.probe2(ram_addr), // input wire [4:0]  probe2 
	.probe3(ram_wr_data), // input wire [7:0]  probe3 
	.probe4(douta) // input wire [7:0]  probe4
);
endmodule
相关推荐
szxinmai主板定制专家2 小时前
储能 EMS、微网控制器选型:RK3588、RK3576、RK3568+FPGA 怎么选?多网、多 CAN、EMC 设计权衡
人工智能·深度学习·机器学习·fpga开发·工业网关·rk3576·电力网关
XMAIPC_Robot3 小时前
ARM+FPGA+AI船舶/工业自动化控制器EMC测试等级解析(IEC60533/IEC60945)
arm开发·人工智能·fpga开发·zynq·arm+fpga·rk3588+fpga
ALINX技术博客4 小时前
ALINX 亮相 2026 工博会,聚焦 FPGA 行业应用场景
ai·fpga开发·射频工程
星夜离尘5615 小时前
FPGA 复位回归实验:双时钟停钟、释放中重入与消费端首拍自检
fpga开发
szxinmai主板定制专家16 小时前
ZYNQ 数据采集方案踩坑总结:电力强电磁干扰、工业现场多协议适配优化
运维·人工智能·fpga开发·机器人·zynq
幻智星科技17 小时前
一个开源的纯FPGA网口采集卡
网络协议·fpga开发·udp
bobuddy17 小时前
硬件加速三件套:emulator-FPGA 原型-云仿真
fpga开发
szxinmai主板定制专家1 天前
软硬协同!ZYNQ 高速多通道同步采集,变电站 / 工厂设备状态监测方案详解
人工智能·深度学习·机器学习·fpga开发·zynq·rk3576
FPGA小徐1 天前
FPGA 8阶LFSR加扰/解扰器设计
fpga开发