一、双端口RAN简介与实验任务
1.1双端口RAM
简单双端口 RAM 的端口 A 只能写不能读,端口 B 只能读不能写。
与单端口不同的是,伪双端口RAM有两路时钟信号CLKA/CLKB。两个独立的地址ADDRA和ADDRB;PortA提供写数据总线,PortB提供读数据总线。
1.2实验任务
本章实验任务是将 Xilinx BMG IP 核配置成一个同步的伪双端口 RAM 并对其进行读写操作,然后通过仿真观察波形是否正确,最后将设计下载到 FPGA 开发板中,并通过在线调试工具对实验结果进行观察。
二、程序设计
2.1RAM IP核的配置
“Basic”选项卡配置界面如下图所示。
对“Port A Options”和“Port B Options”选项卡进行配置,如下图所示:
2.2 模块的设计
总体模块框图如下图所示:
RTL代码ip_2port_ram.v如下:
module ip_2port_ram(
input sys_clk ,
input sys_rst_n
);
wire rd_flag;
wire ram_rd_en;
wire [5:0] ram_rd_addr;
wire [7:0] ram_rd_data;
wire ram_wr_en;
wire ram_wr_we;
wire [5:0] ram_wr_addr;
wire [7:0] ram_wr_data;
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)
);
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)
);
blk_mem_gen_0 your_instance_name (
.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
);
endmodule
写数据模块框图如下图:
RTL代码ram_wr.v如下
module ram_wr(
input clk ,
input rst_n ,
output reg rd_flag,
output reg ram_wr_en,
output ram_wr_we,
output reg [5:0] ram_wr_addr,
output reg [7:0] ram_wr_data
);
assign ram_wr_we = ram_wr_en;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
ram_wr_en <= 1'b0;
end
else begin
ram_wr_en <= 1'b1;
end
end
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_en)
ram_wr_addr <= 6'd0;
else if(ram_wr_en)
ram_wr_addr <= ram_wr_addr + 6'b1;
else
ram_wr_addr <= ram_wr_addr;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rd_flag <= 1'b0;
else if(ram_wr_addr == 6'd32)
rd_flag <= 1'b1;
else
rd_flag <= rd_flag;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_wr_data <= 8'd0;
else if(ram_wr_data >= 8'd200 && ram_wr_en)
ram_wr_data <= 8'd0;
else if(ram_wr_en)
ram_wr_data <= ram_wr_data + 8'd2;
else
ram_wr_data <= ram_wr_data;
end
endmodule
读数据模块框图如下图:
RTL代码ram_rd.v如下:
module ram_rd(
input clk ,
input rst_n ,
input rd_flag,
output ram_rd_en,
output reg [5:0] ram_rd_addr,
input [7:0] ram_rd_data
);
assign ram_rd_en = rd_flag;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_rd_addr <= 6'd0;
else if(ram_rd_addr == 6'd63 && rd_flag)
ram_rd_addr <= 6'd0;
else if(rd_flag)
ram_rd_addr <= ram_rd_addr + 6'd1;
else
ram_rd_addr <= ram_rd_addr;
end
endmodule
2.3 通过Vivado 自带仿真器仿真
仿真代码:
`timescale 1ns/1ps
module tb_ip_2port_ram();
parameter CLK_PERIOD = 20;
reg sys_clk; //周期20ns
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
仿真结果: