双端口RAM IP核

双端口RAM IP核

双端口RAM IP核端口

端口A、端口B都是独立的使能端口、时钟

ADDRA:数据写入对应地址

WEA:读写控制信号

ENA:使能端口,高电平有效

RSTB:复位端口

REGCEB:寄存器使能端口

DOUTB:读出数据

红杠端口:ECC功能错误纠正,单比特纠正,双比特检错

双端口RAM IP核存在问题


实验任务

使用Vivado软件生成一个简单双端口的RAM并对其进行读写操作,然后通过仿真观察波形是否正确,最后通过在线调试工具对实验结果进行验证。如:将RAM设置的深度和宽度分别为64和8进行读写测试

系统框图
波形图
IP核配置


ram_rw读写模块代码

复制代码
module ram_wr(
    input            clk         , //时钟信号
    input            rst_n       , //复位信号,低电平有效
                                    
    //RAM写端口操作                
    output           ram_wr_we   , //ram写使能
    output reg       ram_wr_en   , //端口使能
    output reg       rd_flag     , //读启动信号
    output reg [5:0] ram_wr_addr , //ram写地址        
    output     [7:0] ram_wr_data   //ram写数据
);

//*****************************************************
//**                    main code
//*****************************************************

//ram_wr_we为高电平表示写数据
assign ram_wr_we = ram_wr_en ;

//写数据与写地址相同,因位宽不等,所以高位补0
assign ram_wr_data = {2'b0,ram_wr_addr} ;

//控制RAM使能信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        ram_wr_en <= 1'b0;
    else 
        ram_wr_en <= 1'b1;
end

//写地址信号 范围:0~63        
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)        
        ram_wr_addr <= 6'd0;
    else if(ram_wr_addr < 6'd63 && ram_wr_we)
        ram_wr_addr <= ram_wr_addr + 1'b1;
    else
        ram_wr_addr <= 6'd0;
end  

//当写入32个数据(0~31)后,拉高读启动信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        rd_flag <= 1'b0;
    else if(ram_wr_addr == 6'd31)  
        rd_flag <= 1'b1;
    else
        rd_flag <= rd_flag;
end             

endmodule

ram_rw读写模块代码

复制代码
module ram_rd(
    input            clk        ,   //时钟信号
    input            rst_n      ,   //复位信号,低电平有效
                                    
    //RAM读端口操作                 
    input            rd_flag    ,   //读启动标志
    input      [7:0] ram_rd_data,   //ram读数据
    output           ram_rd_en  ,   //端口使能
    output reg [5:0] ram_rd_addr    //ram读地址       
);
//*****************************************************
//**                    main code
//*****************************************************

//控制RAM使能信号
assign ram_rd_en = rd_flag;      

//读地址信号 范围:0~63        
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)        
        ram_rd_addr <= 6'd0;
    else if(ram_rd_addr < 6'd63 && ram_rd_en)
        ram_rd_addr <= ram_rd_addr + 1'b1;
    else
        ram_rd_addr <= 6'd0;
end

endmodule

顶层模块代码,例化ram_rw,ram_rd模块和IP核

复制代码
module ip_2port_ram(
    input       sys_clk    ,  //系统时钟
    input       sys_rst_n     //系统复位,低电平有效
    );

//wire define
wire             ram_wr_en  ; //端口A使能
wire             ram_wr_we  ; //ram端口A写使能
wire             ram_rd_en  ; //端口B使能
wire             rd_flag    ; //读启动标志
wire    [5:0]    ram_wr_addr; //ram写地址
wire    [7:0]    ram_wr_data; //ram写数据
wire    [5:0]    ram_rd_addr; //ram读地址
wire    [7:0]    ram_rd_data; //ram读数据
   
//*****************************************************
//**                    main code
//*****************************************************

//RAM写模块
ram_wr u_ram_wr(
    .clk           (sys_clk    ),
    .rst_n         (sys_rst_n  ),

    .rd_flag       (rd_flag    ),
    .ram_wr_en     (ram_wr_en  ),
    .ram_wr_we     (ram_wr_we  ),
    .ram_wr_addr   (ram_wr_addr),
    .ram_wr_data   (ram_wr_data)
    );

//简单双端口RAM
blk_mem_gen_0 u_blk_mem_gen_0 (
  .clka   (sys_clk    ), // input wire clka
  .ena    (ram_wr_en  ), // input wire ena
  .wea    (ram_wr_we  ), // input wire [0 : 0] wea
  .addra  (ram_wr_addr), // input wire [5 : 0] addra
  .dina   (ram_wr_data), // input wire [7 : 0] dina
  .clkb   (sys_clk    ), // input wire clkb
  .enb    (ram_rd_en  ), // input wire enb
  .addrb  (ram_rd_addr), // input wire [5 : 0] addrb
  .doutb  (ram_rd_data)  // output wire [7 : 0] doutb
);

//RAM读模块    
ram_rd u_ram_rd(
    .clk           (sys_clk    ),
    .rst_n         (sys_rst_n  ),

    .rd_flag       (rd_flag    ),
    .ram_rd_en     (ram_rd_en  ),
    .ram_rd_addr   (ram_rd_addr),
    .ram_rd_data   (ram_rd_data)
    ); 
   
ila_0 u_ila_0 (
    .clk    (sys_clk    ), // input wire clk
    
    .probe0 (ram_wr_en  ), // input wire [0:0]  probe0  
    .probe1 (ram_wr_we  ), // input wire [0:0]  probe1 
    .probe2 (ram_rd_en  ), // input wire [0:0]  probe2 
    .probe3 (rd_flag    ), // input wire [0:0]  probe3 
    .probe4 (ram_wr_addr), // input wire [5:0]  probe4 
    .probe5 (ram_wr_data), // input wire [7:0]  probe5 
    .probe6 (ram_rd_addr), // input wire [5:0]  probe6 
    .probe7 (ram_rd_data)  // input wire [7:0]  probe7
);

endmodule

FPGA激励文件(Testbench)编写,其用于验证FPGA设计功能正确性的测试脚本,通过模拟输入信号并检查输出响应,确保设计符合预期。

复制代码
`timescale 1ns / 1ps        //仿真单位/仿真精度

module tb_ip_2port_ram();

//parameter define
parameter  CLK_PERIOD = 20; //时钟周期 20ns

//reg define
reg     sys_clk;
reg     sys_rst_n;

//信号初始化
initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #200
    sys_rst_n = 1'b1;
end

//产生时钟
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;

ip_2port_ram u_ip_2port_ram(
    .sys_clk          (sys_clk        ),
    .sys_rst_n        (sys_rst_n      ) 
    );

endmodule
单端口RAM IP核的仿真

.xdc文件

复制代码
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
相关推荐
黄埔数据分析15 小时前
QDMA把描述符当数据搬移, 不用desc engine
fpga开发
南檐巷上学21 小时前
基于FPGA的正弦信号发生器、滤波器的设计(DAC输出点数受限条件下的完整正弦波产生器)
fpga开发·数字信号处理·dsp·dds
嵌入式-老费1 天前
Linux Camera驱动开发(fpga + csi rx/csi tx)
fpga开发
ALINX技术博客2 天前
【202601芯动态】全球 FPGA 异构热潮,ALINX 高性能异构新品预告
人工智能·fpga开发·gpu算力·fpga
JJRainbow2 天前
SN75176 芯片设计RS-232 转 RS-485 通信模块设计原理图
stm32·单片机·嵌入式硬件·fpga开发·硬件工程
s9123601012 天前
FPGA眼图
fpga开发
北京青翼科技2 天前
【PCIe732】青翼PCIe采集卡-优质光纤卡- PCIe接口-万兆光纤卡
图像处理·人工智能·fpga开发·智能硬件·嵌入式实时数据库
minglie12 天前
verilog信号命名规范
fpga开发
XINVRY-FPGA2 天前
中阶FPGA效能红线重新划定! AMD第2代Kintex UltraScale+登场,记忆体频宽跃升5倍
嵌入式硬件·fpga开发·硬件工程·dsp开发·fpga
南檐巷上学2 天前
基于FPGA的音频信号监测识别系统
fpga开发·音频·verilog·fpga·傅立叶分析·fft·快速傅里叶变换