1.很多情况下,fpga的内部ip ram的存储量较小,所以需要外挂容量大的芯片。内部的芯片ram称为静态ram,其读写简单,速率中等,缺点就是存储空间较小。spartan—6芯片的最小单元为9k;充电刷新保持数据的额sdram称为动态ram,其容量大,缺点就是高功耗,管脚多,操作时许复杂,占用面积大。无论是静态还是动态ram都是一种易失性器件。
2.当前比较常用的是ddr3,有关ddr3的介绍https://baike.baidu.com/item/DDR3/9505741?fr=aladdin;fpga的spartan6家族中,有一个IP称为MCB(存储控制模块),本文主要就是对控制模块的读写控制,然后通过读写模块对ddr3的数据进行写入与读取。
3.模块的数据流与读写时序如下:
整个模块的基本数据流就是图所示,本文设计一个display的控制模块,对整个模块进行一个数据验证。而ddr3_rd_ctrl的模块中,申请了一个fifo_2048的fifoIP核,来对ddr3存储的数据进行读取与显示。而frame_start的信号等同于显示器的行列驱动同步,pixel_vaild_o相当于有效显示区域。这个模块需要2个不同频率的时钟,对ddr3的读模块需要125M的时钟,显示模块为50M时钟。
这个ddr3的数据读取的模块控制时序,需要说明的是读模块要先发出读命令然后才可以读取数据,而写模块要写入数据才可以发出写命令。MCB的fifo的使能信号需要严格控制。
3.ddr3的读写主要控制模块程序
module wr_ddr3_ctrl(
input wire sclk,
input wire rst,
input wire P2_DATA_EMPTY,
input wire c3_calib_done,
output wire[31:0] P2_DATA, // P2_DATA
output wire P2_DATA_WR_EN, //P2_DATA_WR_EN
output wire[3:0] P2_data_mask,
output wire P2_CMD_WR_EN, //P2_CMD_WR_EN
output wire[2:0] P2_CMD_INSTR, //P2_CMD_INSTR
output wire[5:0] P2_CMD_BL, //P2_CMD_BL
output wire[29:0] P2_CMD_ADDR //P2_CMD_ADDR
);
reg wr_data_en;
reg [5:0] data_cnt=0;
reg [31:0] wr_data=0;
reg [5:0] burst_cnt=0;
reg done_dely;
wire wr_start_flag;
reg wr_cmd_en;
reg wr_cycle=0;
reg [29:0] wr_addr=0;
assign P2_CMD_BL=6'd63;
assign P2_CMD_INSTR=3'b000;
assign P2_data_mask=4'b0000;
assign P2_CMD_ADDR=wr_addr;
assign P2_CMD_WR_EN=wr_cmd_en;
assign P2_DATA_WR_EN=wr_data_en;
assign P2_DATA=wr_data;
always@(posedge sclk)
if(rst==1)
done_dely<=0;
else done_dely<=c3_calib_done;
assign wr_start_flag=~(done_dely)&(c3_calib_done);
always@(posedge sclk ) //
if(rst==1)
wr_data_en<=1'b0;
else if(wr_start_flag==1||(wr_cycle==1&&P2_DATA_EMPTY==1))
wr_data_en<=1'b1;
else if(data_cnt=='d63)
wr_data_en<=1'b0;
always@(posedge sclk ) //
if(rst==1)
data_cnt<='d0;
else if(wr_data_en==1)
data_cnt<=data_cnt+1'b1;
else data_cnt<='d0;
always@(posedge sclk) //
if(rst==1)
wr_data<='d0;
else if(wr_data_en==1&&data_cnt==63&&burst_cnt==63)
wr_data<='d0;
else if(wr_data_en==1)
wr_data<=wr_data+1;
always@(posedge sclk) //
if(rst==1)
burst_cnt<='d0;
else if(wr_data_en==1&&data_cnt==63)
burst_cnt<=burst_cnt+1'b1;
always@(posedge sclk) //
if(rst==1)
wr_cmd_en<=1'b0;
else if(wr_data_en==1&&data_cnt==63)
wr_cmd_en<=1'b1;
else wr_cmd_en<=1'b0;
always@(posedge sclk) //
if(rst==1)
wr_cycle<='d0;
else if(wr_data_en==1&&data_cnt==63&&burst_cnt==63)
wr_cycle<='d0;
else if(wr_start_flag==1)
wr_cycle<=1;
always@(posedge sclk) //
if(rst==1)
wr_addr<='d0;
else if(wr_cmd_en==1)
wr_addr<=wr_addr+256;
endmodule
module ddr3_rd(
input wire sclk,
input wire wr_sclk,
input wire rst,
input wire c3_calib_done,
input wire frame_start,
input wire pixel_vaild_o,
input wire p3_rd_full,
input wire [31:0] p3_rd_data,
output reg p3_cmd_en,
output wire [2:0] p3_cmd_inst,
output wire [5:0] p3_cmd_bl,
output reg [29:0] p3_cmd_byte_addr,
output reg p3_rd_fifo_en,
output wire [31:0] pixel_data
);
reg ddr3_ready;
wire [10:0] wr_f_cnt;
reg rd_ddr3_cycle;
reg [5:0] data_cnt;
reg user_fifo_wr_en;
wire [10:0] r_f_cnt;
reg fifo_enable_read;
wire user_fifo_rd_en;
assign p3_cmd_bl=63;
assign p3_cmd_inst=001;
always@(posedge wr_sclk)
if(rst==1)
ddr3_ready<=0;
else ddr3_ready<=c3_calib_done;
always@(posedge wr_sclk)
if(rst==1)
rd_ddr3_cycle<=0;
else if(data_cnt==63)
rd_ddr3_cycle<=0;
else if(ddr3_ready==1&&wr_f_cnt<1024)
rd_ddr3_cycle<=1;
always@(posedge wr_sclk)
if(rst==1)
p3_cmd_en<=0;
else if(ddr3_ready==1&&wr_f_cnt<1024&&rd_ddr3_cycle==0)
p3_cmd_en<=1;
else p3_cmd_en<=0;
always@(posedge wr_sclk)
if(rst==1)
p3_rd_fifo_en<=1'b0;
else if(data_cnt==63)
p3_rd_fifo_en<=1'b0;
else if(rd_ddr3_cycle==1&&p3_rd_full==1)
p3_rd_fifo_en<=1'b1;
always@(posedge wr_sclk)
if(rst==1)
p3_cmd_byte_addr<=30'd0;
else if(p3_cmd_en==1&&p3_cmd_byte_addr==30'h3f00)
p3_cmd_byte_addr<=30'd0;
else if(p3_cmd_en==1)
p3_cmd_byte_addr<=p3_cmd_byte_addr+256;
always@(posedge wr_sclk)
if(rst==1)
data_cnt<=6'd0;
else if(data_cnt==63)
data_cnt<=6'd0;
else if(rd_ddr3_cycle==1&&p3_rd_fifo_en==1)
data_cnt<=data_cnt+1'b1;
always@(posedge wr_sclk)
if(rst==1)
user_fifo_wr_en<=1'b0;
else if(rd_ddr3_cycle==1&&p3_rd_full==1)
user_fifo_wr_en<=1'b1;
else if(data_cnt==63)
user_fifo_wr_en<=1'b0;
always@(posedge sclk)
if(rst==1)
fifo_enable_read<=1'b0;
else if(r_f_cnt>1024&&frame_start==1)
fifo_enable_read<=1'b1;
assign user_fifo_rd_en=fifo_enable_read&pixel_vaild_o;
fifo_wr2048_32 fifo_wr2048_32_inst (
.wr_clk(wr_sclk), // input wr_clk *125M
.rd_clk(sclk), // input rd_clk *50M
.din(p3_rd_data), // input [31 : 0] din
.wr_en(user_fifo_wr_en), // input wr_en
.rd_en(user_fifo_rd_en), // input rd_en
.dout(pixel_data), // output [31 : 0] dout
.full(full), // output full
.empty(empty), // output empty
.rd_data_count(r_f_cnt), // output [10 : 0] rd_data_count
.wr_data_count(wr_f_cnt) // output [10 : 0] wr_data_count
);
endmodule
4.模块时序仿真需要很多时间,仿真才是关键。