在上一篇中XilinxDDR3——MIGIP核的配置,已经观看了Xilinx官方提供的MIGIP核读写例程仿真波形,本着学习的目的,本篇开始自己编写MIGIP核读写程序,用于驱动MIGIP核进行DDR3数据的读写。由于没有DDR实物,这里直接借助官方提供的MIGIP核读写例程中的DDR3模拟程序,即直接在Xilinx官方提供的MIGIP核读写例程进行修改。
如下所示,新建一个ddr3_rw.v,用于编写控制DDR3读写的程序如下所示,首先定义输入输出MIGIP核有两组接口,一组是Memoryinterfaceports,它连接到DDR无需用户来操作,只需要连接好就行;另一组是Applicationinterfaceports,它是用户端的接口,供用户直接操作的。MIGIP会将从Applicationinterfaceports接收到的信号在内部进行时序转换,变成直接控制DDR的时序,由Memoryinterfaceports输出给DDR这个逻辑一定要清楚,因此要控制DDR的读写,只需控制好Applicationinterfaceports即可。
总体代码如下:
module ddr3_rw(
input ui_clk, // MIG IP核产生的用户时钟,用于
input ui_clk_sync_rst, // MIG IP核产生的复位信号,高有效
input init_calib_complete, // DDR3初始化完成初始化完成,高电平有效,
input app_rdy, // MIG IP核读写命令接收准备完成,高电平有效。
input app_wdf_rdy, // MIG IP核数据接收准备完成,高电平有效。
input app_rd_data_valid, // 读数据有效
input [127:0] app_rd_data, // 用户要读取的数据
output reg [28:0] app_addr, // 地址,该地址位宽ADDR_WIDTH = RANK位宽 + BANK位宽+ ROW位宽 + COL位宽
output reg app_en, // MIG IP核命令写入使能,高有效。写命令时需要拉高该信号
output app_wdf_wren, // 用户写数据使能
output app_wdf_end, // 突发写当前时钟最后一个数据
output [2:0] app_cmd, // MIG IP核读写控制命令,000位写,001为读。
output reg [127:0] app_wdf_data // 用户要写入的数据
);
//***************************************************** //
//** DDR3读写逻辑 **//
//*****************************************************//
reg [4:0] wr_data_cnt;
reg [4:0] rd_data_cnt;
reg [4:0] rd_addr_cnt;
reg error_flag;
wire error;
parameter TEST_LENGTH = 20;
localparam IDLE = 2'd0,
WRITE = 2'd1,
WAIT = 2'd2,
READ = 2'd3;
reg [1:0] cur_state;
reg [1:0] next_state;
assign rst_n = !ui_clk_sync_rst;
always @(*) begin
if ((cur_state == WRITE) && (app_rdy && app_wdf_rdy)) begin // 当处于写状态时,若app_rdy和app_wdf_rdy拉高,则将app_en拉高。
app_en = 1'd1;
end
else begin
if ((cur_state == READ) && app_rdy) begin // 当处于读状态时,若app_rdy拉高,则将app_en拉高。
app_en = 1'd1;
end
else begin
app_en = 1'd0;
end
end
end
// 在写状态,命令接收(app_rdy)和数据接收(app_wdf_rdy)都准备好,此时拉高写使能
assign app_wdf_wren = ((cur_state == WRITE) && (app_rdy) && (app_wdf_rdy)) ? 1'b1:1'b0;
// 由于DDR3芯片时钟和用户时钟的分频选择4:1,突发长度为8,故两个信号相同
assign app_wdf_end = app_wdf_wren;
// 当前处于读状态则为1,写状态则为0
assign app_cmd = (cur_state == READ) ? 3'd1 :3'd0;
always @(posedge ui_clk or negedge rst_n) begin
if (!rst_n) begin
cur_state <= IDLE;
end
else begin
cur_state <= next_state;
end
end
always @(*) begin
if (!rst_n) begin
next_state = IDLE;
end
else begin
case (cur_state)
IDLE: begin
if (init_calib_complete) begin
next_state = WRITE;
end
else begin
next_state = IDLE;
end
end
WRITE:begin
if (wr_data_cnt < TEST_LENGTH) begin
next_state = WRITE;
end
else begin
next_state = WAIT;
end
end
WAIT:begin
next_state = READ;
end
READ:begin
if (rd_addr_cnt < TEST_LENGTH) begin
next_state = READ;
end
else begin
next_state = IDLE;
end
end
default: begin
if (init_calib_complete) begin
next_state = WRITE;
end
else begin
next_state = IDLE;
end
end
endcase
end
end
always @(posedge ui_clk or negedge rst_n) begin
if (!rst_n) begin
app_addr <= 29'd0;
wr_data_cnt <= 5'd0;
end
else begin
case (next_state)
IDLE: begin
app_wdf_data <= 256'd0;
wr_data_cnt <= 0;
rd_addr_cnt <= 0;
app_addr <= 0;
end
WRITE:begin
if ((app_rdy)&&(app_wdf_rdy)&&(~app_cmd)) begin
app_addr <= app_addr + 8;
app_wdf_data <= app_wdf_data + 1;
wr_data_cnt <= wr_data_cnt + 1;
end
else begin
app_addr <= app_addr;
app_wdf_data <= app_wdf_data;
wr_data_cnt <= wr_data_cnt;
end
end
WAIT:begin
app_addr <= 0;
end
READ:begin
if ((app_rdy)&&(app_cmd)) begin
app_addr <= app_addr + 8;
rd_addr_cnt <= rd_addr_cnt + 1;
end
else begin
app_addr <= app_addr;
rd_addr_cnt <= rd_addr_cnt;
end
end
default: begin
app_wdf_data <= 256'd0;
wr_data_cnt <= 0;
app_addr <= 0;
end
endcase
end
end
always @(posedge ui_clk or negedge rst_n) begin
if (!rst_n) begin
rd_data_cnt <= 5'd0;
end
else begin
if (app_rd_data_valid) begin
if (rd_data_cnt == TEST_LENGTH) begin
rd_data_cnt <= 5'd0;
end
else begin
rd_data_cnt <= rd_data_cnt + 1;
end
end
else begin
rd_data_cnt <= rd_data_cnt;
end
end
end
//读信号有效,且读出的数不是写入的数时,将错误标志位拉高
assign error = (app_rd_data_valid && (rd_data_cnt!=app_rd_data));
//寄存状态标志位
always @(posedge ui_clk or negedge rst_n) begin
if(~rst_n)
error_flag <= 0;
else if(error)
error_flag <= 1;
end
endmodule
将ddr3_rw.v例化进example_top.v:同时将example_top.v中的mig_7series_v4_1_traffic_gen_top注释掉:
点击runsimulation仿真即可出现如下波形
如中紫线所示,error_flag一直为低,说明读出的数据与写入的数据一致。调试过程中遇到的问题。
如果app_rdy和app_en同时拉高后,app_wdf_rdy和app_wdf_wren没有拉高,则写入的数据和要写入的地址并不对应,最终取出的数据会出现问题。
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点
香蕉2023-02-07
全网最牛逼的股吧,操盘主力为了吸筹,可以一片片唱空,但分析看多会被攻击会被禁,居然不让股票发帖分析看多,发现600403吧里分析看多的帖子被主力庄家禁言压制隐藏的现象,从形态结构上看年线金叉的600403周线双底且月线第二浪主升浪要启动的样子。认真查了一下那公司资料发现是将重组整体上市预期,类似中航电测蛇吞象式重组整体上市,难怪在那吧里只能唱空不能分析看多