基于MIG IP核的DDR3控制器(二)

上一节中,记录到了ddr控制器的整体架构,在本节中,准备把ddr控制器的各个模块完善一下。

可以看到上一节中介绍了DDR控制器的整体架构,因为这几周事情多,又要课设什么的麻烦,今天抽点时间把这个记录完了,不然以后都忘了DDR该咋去控制了。

从本次实验的整体功能模块可以看出,最终我们只需要用户操作的信号为用户写入的256bit数据wr_ddr_data,写开始信号wr_start,数据请求信号data_req,读开始信号rd_start,读出的数据rd_ddr_data,读数据有效信号rd_data_vld,读结束和写结束信号rd_done、wr_done,ddr忙碌信号ddr_busy;

接下来我们将从顶层模块开始介绍各个模块实现的功能。

1) 顶层模块:

在顶层模块中,我们主要介绍用户相关的接口,在DDR3 存储器一侧的信号不做过多介绍


端口名称


I/O


位宽


备注


wr_ddr_data


I


256


用户写入的256bit数据


data_req


O


1


向上游模块请求数据信号


wr_start


I


1


一次写ddr开始信号


wr_done


O


1


一次写ddr结束信号


rd_start


I


1


读开始信号


rd_data_vld


O


1


读出数据有效信号


rd_ddr_data


O


256


读出的有效数据


rd_done


O


1


一次突发读数据结束信号


ddr_busy


O


1


当前控制器处于忙碌状态

用户通过这些信号,能够较为简单地实现对DDR的访问。

2) 用户写控制模块

该模块的主要作用是,在接收到上游模块发送过来的写开始信号后,从上游模块将要写入DDR的数据请求而来,并将数据写入到DDR中。本模块的结构如下:

各个信号的作用如下表所示:


端口名称


I/O


位宽


备注


ui_clk


I


1


系统时钟100M


rst


I


1


系统复位,同步复位


wr_start


I


1


写开始信号


wr_ddr_data


I


256


用户写入的256bit数据


dta_req


O


1


向上游模块请求数据信号


wr_busy


O


1


当前模块正处于写忙碌状态


wr_done


O


1


一次写结束信号


wr_req


O


1


写请求信号,给到仲裁模块做总裁


wr_ack


I


1


写响应信号,仲裁模块给回的写响应


app_wdf_mask


O


32


32bit写入数据掩码


app_wdf_data


O


256


写入到DDR的数据


app_wdf_wren


O



当前写入数据有效信号


app_wdf_end


O


1


当前数据是ddr一次8突发的最后一个数据


app_wdf_rdy


I


1


当前MIG IP写数据通道处于空闲状态


app_rdy


I


1


当前MIG IP命令通道处于空闲状态


app_cmd


O


3


写数据命令3’b000


app_en


O


1


命令使能信号


app_addr


O


29


要访问的内存地址

关于本模块的代码设计,可以参考本模块的时序波形图,本模块状态跳转图如下,在IDLE状态下,若接收到写开始信号wr_start,则进入写请求状态,同时产生写请求wr_req给到仲裁模块,若当前可以进行写操作,则仲裁模块将会给出一个写响应信号wr_ack,接收到响应过后将跳转如写数据状态,从上游模块请求数据并给出写命令和地址,把数据写入到DDR中。

时序设计图如下:

对时序图做简单说明:进入写状态后,将使能app_wdf_wren信号,于此同时data_req信号在app_wdf_wren和app_wdf_rdy同时有效时才为有效,从而向上游模块请求数据,在写模块中,一次写操作需要向上游模块请求64个256bit数据。app_en在app_wdf_wren一个周期后拉高,然后再app_rdy和app_en同时有效的时候,需要给出写入ddr的地址,写入ddr的地址每次需要增加8,这是因为我们写入的数据是256bit,而ddr内存一个地址的容量是32bit,一次写入256bit地址正好增加8。当全部64个数据写入完成后,将产生一个写结束信号,指示本次写操作已经完成。在写状态时,拉高wr_busy指示当前模块正处于写忙碌的状态。

  1 /*=============================================================================
  2 #
  3 # Author: weichaochen - [email protected]
  4 #
  5 # QQ : 1530604142
  6 #
  7 # Last modified: 2019-12-29 19:28
  8 #
  9 # Filename: ddr_wr_ctrl.v
 10 #
 11 # Description:
 12 #
 13 =============================================================================*/
 14 `timescale 1ns / 1ps
 15
 16 module ddr_wr_ctrl(
 17     input    wire             ui_clk         ,//ddr3工作时钟
 18     input   wire            rst         ,//系统复位
 19     input    wire            wr_start    ,//写开始信号
 20     output    wire            data_req    ,//请求写数据信号
 21     input    wire    [255:0]    wr_ddr_data    ,//将要写入的数据
 22
 23     output    wire            wr_req        ,//写数据请求
 24     input    wire            wr_ack         ,//写响应
 25     output    wire            wr_done        ,//一次写结束
 26     output  wire            wr_busy     ,//当前处于忙碌状态
 27
 28     input    wire            app_rdy        ,//命令通道空闲
 29     output    wire    [2:0]    app_cmd     ,//输出的控制命令
 30     output    wire            app_en        ,//命令使能
 31     output    wire    [28:0]    app_addr    ,//输出的地址
 32
 33     input    wire            app_wdf_rdy    ,//写数据通道空闲信号
 34     output    wire    [255:0]    app_wdf_data,//写入的数据
 35     output    wire            app_wdf_wren,//写入数据使能
 36     output    wire            app_wdf_end    ,//当前数据是DDR一次突发的最后一个数据
 37     output    wire    [31:0]    app_wdf_mask //写入数据掩码
 38     );
 39
 40 //=============================================
 41 //parameter define
 42 //=============================================
 43 parameter   IDLE      = 3‘b001;
 44 parameter   WR_REQ     = 3‘b010;
 45 parameter   WRITE     = 3‘b100;
 46
 47 parameter   TOTAL_PIXEL = 1024 * 768 - 8;
 48 parameter   BURST_LEN   = 64 - 1;
 49
 50 //=============================================
 51 //internal siganl
 52 //=============================================
 53 reg     [2:0]   state           ;//状态寄存器
 54
 55 reg     [9:0]   cnt_data        ;//计数当前写入的数据
 56 wire            add_cnt_data    ;
 57 wire            end_cnt_data    ;
 58
 59 reg     [9:0]   cnt_cmd         ;//计数当前已经给出的命令
 60 wire            add_cnt_cmd     ;
 61 wire            end_cnt_cmd     ;
 62
 63 reg             app_wdf_wren_r  ;//写入数据有效
 64 reg             app_en_r        ;//命令有效信号
 65 reg     [28:0]  app_addr_r      ;//写入的地址
 66
 67 reg             wr_done_r       ;//一次写完成
 68 reg             wr_req_r        ;//写请求
 69
 70
 71
 72
 73 assign app_cmd = 3‘b000;        //写命令
 74 assign app_wdf_mask = 32‘d0;    //写数据掩码
 75 assign app_wdf_wren = app_wdf_wren_r;
 76 assign app_en = app_en_r ;
 77 assign app_addr= app_addr_r;
 78 assign app_wdf_data = wr_ddr_data;
 79 assign wr_done = wr_done_r;
 80 assign wr_busy = state==WRITE;
 81 assign wr_req = wr_req_r;
 82 assign app_wdf_end = app_wdf_wren_r;
 83
 84 assign data_req = app_wdf_wren_r & app_wdf_rdy;//向上游模块请求数据
 85
 86
 87 //--------------------state machine describe--------------------
 88 always @(posedge ui_clk)begin
 89     if(rst == 1‘b1)begin
 90         state <= IDLE;
 91     end
 92     else begin
 93         case(state)
 94             IDLE:begin
 95                 if(wr_start==1‘b1)
 96                     state <= WR_REQ;
 97                 else
 98                     state <= IDLE;
 99             end
100
101             WR_REQ:begin
102                 if(wr_ack)
103                     state <= WRITE;
104                 else
105                     state <= WR_REQ;
106             end
107
108             WRITE:begin
109                 if(end_cnt_cmd)
110                     state <= IDLE;
111                 else
112                     state <= WRITE;
113             end
114
115             default:begin
116                 state <= IDLE;
117             end
118         endcase
119     end
120 end
121
122
123 //--------------------app_wdf_wren_r--------------------
124 always @(posedge ui_clk)begin
125     if(rst == 1‘b1)begin
126         app_wdf_wren_r <= 1‘b0;
127     end
128     else if(end_cnt_data)begin
129         app_wdf_wren_r <= 1‘b0;
130     end
131     else if(state==WR_REQ && wr_ack==1‘b1)begin
132         app_wdf_wren_r <= 1‘b1;
133     end
134 end
135
136 //--------------------cnt_data--------------------
137 always @(posedge ui_clk)begin
138     if(rst==1‘b1)begin
139         cnt_data <= 0;
140     end
141     else if(add_cnt_data)begin
142         if(end_cnt_data)
143             cnt_data <= 0;
144         else
145             cnt_data <= cnt_data + 1‘b1;
146     end
147 end
148
149 assign add_cnt_data = data_req;
150 assign end_cnt_data = add_cnt_data && cnt_data== BURST_LEN;
151
152 //--------------------app_en_r--------------------
153 always @(posedge ui_clk)begin
154     if(rst == 1‘b1)begin
155         app_en_r <= 1‘b0;
156     end
157     else if(end_cnt_cmd)begin
158         app_en_r <= 1‘b0;
159     end
160     else if(app_wdf_wren_r==1‘b1)begin
161         app_en_r <= 1‘b1;
162     end
163 end
164
165 //--------------------cnt_cmd--------------------
166 always @(posedge ui_clk)begin
167     if(rst==1‘b1)begin
168         cnt_cmd <= 0;
169     end
170     else if(add_cnt_cmd)begin
171         if(end_cnt_cmd)
172             cnt_cmd <= 0;
173         else
174             cnt_cmd <= cnt_cmd + 1‘b1;
175     end
176 end
177
178 assign add_cnt_cmd = app_rdy & app_en_r;
179 assign end_cnt_cmd = add_cnt_cmd && cnt_cmd== BURST_LEN;
180
181 //--------------------app_addr_r--------------------
182 always @(posedge ui_clk)begin
183     if(rst == 1‘b1)begin
184         app_addr_r <= ‘d0;
185     end
186     else if(app_addr_r == TOTAL_PIXEL && app_en_r==1‘b1 && app_rdy==1‘b1)begin
187         app_addr_r <= ‘d0;
188     end
189     else if(app_en_r==1‘b1 && app_rdy==1‘b1)begin
190         app_addr_r <= app_addr_r + ‘d8;
191     end
192 end
193
194 //--------------------wr_done_r--------------------
195 always @(posedge ui_clk)begin
196     if(rst == 1‘b1)begin
197         wr_done_r <= 1‘b0;
198     end
199     else if(end_cnt_cmd==1‘b1)begin
200         wr_done_r <= 1‘b1;
201     end
202     else begin
203         wr_done_r <= 1‘b0;
204     end
205 end
206
207 //--------------------wr_req_r--------------------
208 always @(posedge ui_clk)begin
209     if(rst == 1‘b1)begin
210         wr_req_r <= 1‘b0;
211     end
212     else if(wr_ack==1‘b1)begin
213         wr_req_r <= 1‘b0;
214     end
215     else if(state==IDLE && wr_start==1‘b1)begin
216         wr_req_r <= 1‘b1;
217     end
218 end
219
220 endmodule

3) 用户读控制模块

本模块的作用是,当接收到读开始信号rd_start后,本模块产生读命令将数据从ddr中读出来,并将数据给到下游模块,本模块的结构图如下:

各个信号的作用如下表所示:


端口名称


I/O


位宽


备注


ui_clk


I


1


系统时钟100M


rst


I


1


系统复位,同步复位


rd_start


I


1


读开始信号


rd_ddra_data


O


256


从DDR中读出的数据


rd_data_vld


O


1


读出数据有效信号


rd_req


O


1


读请求信号,给到仲裁模块做判断


rd_ack


I


1


读响应信号,仲裁模块对读请求的响应


rd_done


O


1


一次读操作完成信号


rd_busy


O


1


当前模块正处于读忙碌状态


app_rdy


I


1


当前命令通道处于空闲状态


app_addr


O


29


读DDR的内存地址


app_en


O


1


读命令有效信号


app_cmd


O


3


读DDR的命令3’b001


app_rd_data


I


256


从DDR中读出的数据


app_rd_data_vld


I


1


从DDR中读出数据有效信号


app_rd_data_end


I


1


当前数据是DDR8突发的最后一个数据

本模块功能设计,可以参考用户读控制波形图,本模块的状态跳转图如下:若在空闲状态下接收到写开始信号rd_start则状态跳转到写请求状态,并给出写读请求信号rd_req,若接收到仲裁模块给出的读响应信号rd_ack,则跳转入读数据状态,将数据从ddr中读出。当读完64个数据后跳转回空闲状态。

本模块的时序设计如下:

在读状态下,将使能app_en信号,同时开始计数当前给出了多少个命令,在读模块中,一次读操作同样对应了64个数据,这样就与前面的写模块具有相同的长度,能够在读写速度上匹配,避免读写的冲突。当读完全部64个数据后,将给出读结束信号rd_done指示本次读操作已经完成,本模块处于读状态时,将使能rd_busy信号,指示本模块当前正忙碌。

  1 /*=============================================================================
  2 #
  3 # Author: weichaochen - [email protected]
  4 #
  5 # QQ : 1530604142
  6 #
  7 # Last modified: 2019-12-29 19:32
  8 #
  9 # Filename: ddr_rd_ctrl.v
 10 #
 11 # Description:
 12 #
 13 =============================================================================*/
 14
 15 `timescale 1ns / 1ps
 16 module ddr_rd_ctrl(
 17     input     wire            ui_clk             ,//系统时钟
 18     input    wire            rst             ,//系统复位
 19     input    wire            rd_start        ,//读开始
 20
 21     output     wire            rd_req             ,//读请求
 22     input     wire            rd_ack             ,//读响应
 23     output    wire            rd_done            ,//读完成
 24     output     wire            rd_busy            ,//读忙碌
 25
 26     output    wire     [2:0]    app_cmd            ,//读ddr命令
 27     output    wire            app_en            ,//读ddr命令使能
 28     output    wire    [28:0]    app_addr        ,//读ddr地址
 29     input     wire            app_rdy         ,//ddr命令通道空闲
 30
 31     input    wire            app_rd_data_vld    ,//ddr读出数据有效
 32     input    wire    [255:0]    app_rd_data     ,//从ddr中读出的数据
 33     output    wire            rd_ddr_data_vld ,//用户读出数据有效
 34     output    wire    [255:0]    rd_ddr_data      //用户读出的数据
 35   );
 36
 37 //=============================================
 38 //parameter define
 39 //=============================================
 40 parameter   IDLE      = 3‘b001;
 41 parameter   RD_REQ     = 3‘b010;
 42 parameter   READ     = 3‘b100;
 43
 44 parameter   TOTAL_PIXEL = 1024 * 768 - 8;
 45 parameter   BURST_LEN   = 64 - 1;
 46
 47 //=============================================
 48 //internal siganl
 49 //=============================================
 50 reg     [2:0]   state               ;//状态寄存器
 51
 52 reg     [9:0]   cnt_data            ;//计数当读出的数据
 53 wire            add_cnt_data        ;
 54 wire            end_cnt_data        ;
 55
 56 reg     [9:0]   cnt_cmd             ;//计数当前已经给出的命令
 57 wire            add_cnt_cmd         ;
 58 wire            end_cnt_cmd         ;
 59
 60 reg             app_en_r            ;//命令有效信号
 61 reg     [28:0]  app_addr_r          ;//写入的地址
 62
 63 reg                rd_done_r           ;//一次读完成
 64 reg                rd_req_r            ;//读请求
 65 reg                rd_ddr_data_vld_r    ;//读出数据有效
 66 reg     [255:0]    rd_ddr_data_r        ;//读出的数据
 67
 68 assign app_cmd = 3‘b001;        //读命令
 69 assign app_en = app_en_r ;
 70 assign app_addr= app_addr_r;
 71 assign rd_done = rd_done_r;
 72 assign rd_busy = state==READ;
 73 assign rd_req = rd_req_r;
 74 assign rd_ddr_data = rd_ddr_data_r;
 75 assign rd_ddr_data_vld = rd_ddr_data_vld_r;
 76
 77
 78 //--------------------state machine describe--------------------
 79 always @(posedge ui_clk)begin
 80     if(rst == 1‘b1)begin
 81         state <= IDLE;
 82     end
 83     else begin
 84         case(state)
 85             IDLE:begin
 86                 if(rd_start==1‘b1)
 87                     state <= RD_REQ;
 88                 else
 89                     state <= IDLE;
 90             end
 91
 92             RD_REQ:begin
 93                 if(rd_ack)
 94                     state <= READ;
 95                 else
 96                     state <= RD_REQ;
 97             end
 98
 99             READ:begin
100                 if(end_cnt_cmd)
101                     state <= IDLE;
102                 else
103                     state <= READ;
104             end
105
106             default:begin
107                 state <= IDLE;
108             end
109         endcase
110     end
111 end
112
113
114 //--------------------cnt_data--------------------
115 always @(posedge ui_clk)begin
116     if(rst==1‘b1)begin
117         cnt_data <= 0;
118     end
119     else if(add_cnt_data)begin
120         if(end_cnt_data)
121             cnt_data <= 0;
122         else
123             cnt_data <= cnt_data + 1‘b1;
124     end
125 end
126
127 assign add_cnt_data = app_rd_data_vld;
128 assign end_cnt_data = add_cnt_data && cnt_data== BURST_LEN;
129
130 //--------------------app_en_r--------------------
131 always @(posedge ui_clk)begin
132     if(rst == 1‘b1)begin
133         app_en_r <= 1‘b0;
134     end
135     else if(end_cnt_cmd)begin
136         app_en_r <= 1‘b0;
137     end
138     else if(state==RD_REQ && rd_ack==1‘b1)begin
139         app_en_r <= 1‘b1;
140     end
141 end
142
143 //--------------------cnt_cmd--------------------
144 always @(posedge ui_clk)begin
145     if(rst==1‘b1)begin
146         cnt_cmd <= 0;
147     end
148     else if(add_cnt_cmd)begin
149         if(end_cnt_cmd)
150             cnt_cmd <= 0;
151         else
152             cnt_cmd <= cnt_cmd + 1‘b1;
153     end
154 end
155
156 assign add_cnt_cmd = app_rdy & app_en_r;
157 assign end_cnt_cmd = add_cnt_cmd && cnt_cmd== BURST_LEN;
158
159 //--------------------app_addr_r--------------------
160 always @(posedge ui_clk)begin
161     if(rst == 1‘b1)begin
162         app_addr_r <= ‘d0;
163     end
164     else if(app_addr_r == TOTAL_PIXEL && app_en_r==1‘b1 && app_rdy==1‘b1)begin
165         app_addr_r <= ‘d0;
166     end
167     else if(app_en_r==1‘b1 && app_rdy==1‘b1)begin
168         app_addr_r <= app_addr_r + ‘d8;
169     end
170 end
171
172 //--------------------rd_done_r--------------------
173 always @(posedge ui_clk)begin
174     if(rst == 1‘b1)begin
175         rd_done_r <= 1‘b0;
176     end
177     else if(end_cnt_data==1‘b1)begin
178         rd_done_r <= 1‘b1;
179     end
180     else begin
181         rd_done_r <= 1‘b0;
182     end
183 end
184
185 //--------------------rd_req_r--------------------
186 always @(posedge ui_clk)begin
187     if(rst == 1‘b1)begin
188         rd_req_r <= 1‘b0;
189     end
190     else if(rd_ack==1‘b1)begin
191         rd_req_r <= 1‘b0;
192     end
193     else if(state==IDLE && rd_start==1‘b1)begin
194         rd_req_r <= 1‘b1;
195     end
196 end
197
198 //--------------------rd_ddr_data_r, rd_ddr_data_vld_r--------------------
199 always @(posedge ui_clk)begin
200     if(rst == 1‘b1)begin
201         rd_ddr_data_r <= ‘d0;
202         rd_ddr_data_vld_r <= 1‘b0;
203     end
204     else begin
205         rd_ddr_data_r <= app_rd_data;
206         rd_ddr_data_vld_r <= app_rd_data_vld;
207     end
208 end
209 endmodule

4) 读写仲裁模块

本模块的目的是为了来避免读写冲突的,在ddr进行写操作的同时,也有可能有读操作需要处理,这时候就会发生读写冲突,为了避免读写操作同时发生创建一个仲裁模块,模块的结构和信号列表如下:


端口名称


I/O


位宽


备注


wr_req


I


1


写数据请求,写控制模块给出的写请求


rd_req


I


1


读数据请求,读控制模块给出的读请求


ui_clk


I


1


系统时钟


rst


I


1


系统同步复位


wr_ack


O


1


写响应,用来响应本次写操作


wr_done


I


1


一次写操作完成


rd_ack


O


1


读响应,用来响应读操作


rd_done


I


1


一次读操作完成。

本模块的功能设计可以参考时序图,这里简单介绍以下本模块的工作方式,本模块的状态跳转入下图所示,在仲裁状态ARBIT下若接收到读请求,则进入读状态,若接收到写请求,则进入写状态,若读写请求同时出现则优先响应写请求进入写状态,当在读写状态中接收到读写结束信号wr_done或者rd_done时,状态将回到仲裁状态。

本模块的工作的时序设计如下:

本模块实现的功能比较简单,通过时序图能够很直观地就看出其功能,在这里不再赘述。至此我们完成了这些基础模块地创建,有了这些时序设计波形图,去设计代码就是十分简单地事情了。

/*=============================================================================
#
# Author: weichaochen - [email protected]
#
# QQ : 1530604142
#
# Last modified: 2019-12-29 19:35
#
# Filename: ddr_arbit.v
#
# Description:
#
=============================================================================*/

`timescale 1ns / 1ps
module ddr_arbit(
    input   wire            ui_clk  ,//系统时钟
    input   wire            rst     ,//系统复位
    input   wire            wr_req  ,//写请求
    output  wire            wr_ack  ,//写响应
    input   wire            wr_done ,//写完成

    input   wire            rd_req  ,//读请求
    output  wire            rd_ack  ,//读响应
    input   wire            rd_done  //读完成
    );

//==================================================
//parameter define
//==================================================
parameter   IDLE    = 4‘b0001;
parameter   ARBIT   = 4‘b0010;
parameter   WRITE   = 4‘b0100;
parameter   READ    = 4‘b1000;

//==================================================
//internal siganls
//==================================================
reg             wr_ack_r    ;
reg             rd_ack_r    ;
reg     [3:0]   state       ;

assign wr_ack = wr_ack_r    ;
assign rd_ack = rd_ack_r    ;

//--------------------state machine describe--------------------
always @(posedge ui_clk)begin
    if(rst == 1‘b1)begin
        state <= IDLE;
    end
    else begin
        case(state)
            IDLE:begin
                state <= ARBIT;
            end

            ARBIT:begin
                if(wr_req==1‘b1)//写的优先级高于读
                    state <= WRITE;
                else if(wr_req==1‘b0 && rd_req==1‘b1)
                    state <= READ;
            end

            WRITE:begin
                if(wr_done)
                    state <= ARBIT;
                else
                    state <= WRITE;
            end

            READ:begin
                if(rd_done)
                    state <= ARBIT;
                else
                    state <= READ;
            end

            default:begin
                state <= IDLE;
            end
        endcase
    end
end

//--------------------wr_ack_r--------------------
always @(posedge ui_clk)begin
    if(rst == 1‘b1)begin
        wr_ack_r <= 1‘b0;
    end
    else if(state==ARBIT && wr_req==1‘b1)begin
        wr_ack_r <= 1‘b1;
    end
    else begin
        wr_ack_r <= 1‘b0;
    end
end

//--------------------rd_ack_r--------------------
always @(posedge ui_clk)begin
    if(rst == 1‘b1)begin
        rd_ack_r <= 1‘b0;
    end
    else if(state==ARBIT && wr_req==1‘b0 && rd_req==1‘b1)begin
        rd_ack_r <= 1‘b1;
    end
    else begin
        rd_ack_r <= 1‘b0;
    end
end

endmodule

在有了这些模块后,接下来我们要进行对这些模块的功能测试,我们将对ddr3进行循环读写测试来验证其功能。接下来,我们就编写一个测试模块。

该模块负责对DDR进行循环读写,每次读写64个256bit数据,通过比较写入和读出的数据是否相同来判断ddr控制器是否正常工作.

该模块的状态跳转如下图所示,在arbit状态下判断当前是该进行写还是读,应该注意本次实验的读写是交替进行的.

  1 /*=============================================================================
  2 #
  3 # Author: weichaochen - [email protected]
  4 #
  5 # QQ : 1530604142
  6 #
  7 # Last modified: 2019-12-29 19:41
  8 #
  9 # Filename: gen_test_data.v
 10 #
 11 # Description:
 12 #
 13 =============================================================================*/
 14
 15 `timescale 1ns / 1ps
 16 module gen_test_data(
 17     input     wire            ui_clk         ,//系统时钟
 18     input    wire            rst         ,//系统复位
 19     input    wire            ddr_busy    ,//ddr控制器当前处于忙碌状态
 20
 21     output    wire            wr_start    ,//写开始信号
 22     input    wire            data_req    ,//数据请求信号
 23     output    wire    [255:0]    wr_ddr_data    ,//将要写入ddr的数据
 24     input    wire            wr_done        ,//一次写操作完成信号
 25
 26     output    wire            rd_start    ,//读开始信号
 27     input    wire            rd_data_vld    ,//读出数据有效信号
 28     input    wire    [255:0]    rd_ddr_data    ,//读出的有效数据
 29     input    wire            rd_done        ,//一次读完成信号
 30
 31     output    wire            error         //读写错误信号
 32     );
 33
 34 //==================================================
 35 //parameter define
 36 //==================================================
 37 parameter   IDLE    = 4‘b0001;
 38 parameter   ARBIT   = 4‘b0010;
 39 parameter   WRITE   = 4‘b0100;
 40 parameter   READ    = 4‘b1000;
 41
 42 parameter    CNT_MAX = 64 - 1;
 43
 44 //==================================================
 45 //internal siganls
 46 //==================================================
 47 reg     [3:0]    state        ;//状态寄存器
 48 reg     [7:0]    cnt_data    ;//数据计数
 49 reg             wr_start_r    ;//写开始信号
 50 reg             rd_start_r    ;//读开始信号
 51 reg             error_r     ;//错误指示信号
 52 reg             wr_rd_flag    ;//读写指示信号
 53
 54 assign wr_ddr_data = (wr_rd_flag==1‘b0)?{32{cnt_data}}:256‘d0;
 55 assign wr_start = wr_start_r;
 56 assign rd_start = rd_start_r;
 57 assign error = error_r;
 58 //--------------------state machine describe--------------------
 59 always @(posedge ui_clk)begin
 60     if(rst == 1‘b1)begin
 61         state <= IDLE;
 62     end
 63     else begin
 64         case(state)
 65             IDLE:begin
 66                 state <= ARBIT;
 67             end
 68
 69             ARBIT:begin
 70                 if(wr_start_r)//当前需要进行写操作
 71                     state <= WRITE;
 72                 else if(rd_start_r)//当前需要进行读操作
 73                     state <= READ;
 74             end
 75
 76             WRITE:begin
 77                 if(wr_done)
 78                     state <= ARBIT;
 79                 else
 80                     state <= WRITE;
 81             end
 82
 83             READ:begin
 84                 if(rd_done)
 85                     state <= ARBIT;
 86                 else
 87                     state <= READ;
 88             end
 89
 90             default:begin
 91                 state <= IDLE;
 92             end
 93         endcase
 94     end
 95 end
 96
 97 //--------------------wr_rd_flag--------------------
 98 always @(posedge ui_clk)begin
 99     if(rst == 1‘b1)begin
100         wr_rd_flag <= 1‘b0;
101     end
102     else if(wr_done==1‘b1)begin
103         wr_rd_flag <= 1‘b1;
104     end
105     else if(rd_done==1‘b1)begin
106         wr_rd_flag <= 1‘b0;
107     end
108 end
109
110 //--------------------wr_start_r,rd_start_r--------------------
111 always @(posedge ui_clk)begin
112     if(rst == 1‘b1)begin
113         wr_start_r <= 1‘b0;
114         rd_start_r <= 1‘b0;
115     end
116     else if(state==ARBIT && ddr_busy==1‘b0 && wr_rd_flag==1‘b0)begin
117         wr_start_r <= 1‘b1;
118     end
119     else if(state==ARBIT && ddr_busy==1‘b0 && wr_rd_flag==1‘b1)begin
120         rd_start_r <= 1‘b1;
121     end
122     else begin
123         rd_start_r <= 1‘b0;
124         wr_start_r <= 1‘b0;
125     end
126 end
127
128 //--------------------cnt_data--------------------
129 always @(posedge ui_clk)begin
130     if(rst == 1‘b1)begin
131         cnt_data <= ‘d0;
132     end
133     else if(data_req==1‘b1)begin
134         if(cnt_data==CNT_MAX)
135             cnt_data <= ‘d0;
136         else
137             cnt_data <= cnt_data + 1‘b1;
138     end
139     else if(rd_data_vld==1‘b1)begin
140         if(cnt_data==CNT_MAX)
141             cnt_data <= ‘d0;
142         else
143             cnt_data <= cnt_data + 1‘b1;
144     end
145 end
146
147 //--------------------error--------------------
148 always @(posedge ui_clk)begin
149     if(rst == 1‘b1)begin
150         error_r <= 1‘b0;
151     end
152     else if(rd_data_vld==1‘b1 && (rd_ddr_data !={32{cnt_data}}))begin
153             error_r <= 1‘b1;
154     end
155 end
156
157
158 endmodule

在接下来可以对对将整个工程进行仿真,通过仿真的结果来判断结构是否正确.

在产生循环读写的模块中,我们可以看到error信号一直保持为低,并且用户的确向DDR中写入了数据,并且也从DDR中读出了数据,说明我们的设计的控制器已经正常工作了。

原文地址:https://www.cnblogs.com/weicc/p/12051840.html

时间: 2024-08-08 06:13:59

基于MIG IP核的DDR3控制器(二)的相关文章

基于MIG IP核的DDR3控制器(一)

最近学习了DDR3控制器的使用,也用着DDR完成了一些简单工作,想着以后一段可能只用封装过后的IP核,可能会忘记DDR3控制器的一些内容,想着把这个DDR控制器的编写过程记录下来,便于我自己以后查看吧,哈哈哈,闲话少说开始工作.这个DDR3控制器分两节内容吧,第一节就是MIGIP核的简单介绍和生成这个IP核再介绍一下自己封装这个IP的整体架构,第二节就来介绍一下各个模块的内容. 1.1 MIG IP 核介绍 1) MIG IP核架构 通过查阅ug586_7Series_MIS,我们可以看到MIG

Xilinx 7系列例化MIG IP core DDR3读写

昨晚找了一下,发现DDR3读写在工程上多是通过例化MIG,调用生成IPcore的HDL Functional Model.我说嘛,自己哪能写出那么繁琐的,不过DDR读写数据可以用到状态机,后期再添砖加瓦吧,当下先对比一下网上找的一段程序和自己例化后的程序. 另外,仿真了十余分钟,最后的是什么鬼?一头雾水T.T.想着每一次要分析信号要等那么久就难受. 更重要的是分享一波关于"Xilinx平台下DDR3设计教程"的资料.就其中的"仿真篇"而言,亲测可行,还是中文版 da

基于Virtext6平台的GTX IP核基本设置说明

本工程基于以下条件使用: 板卡:DBF板v3.0 芯片型号:Virtex6 315T ISE版本:14.7 IP核版本: v6_gtxwizard : 1.12 一.IP核配置进行流程 第一页配置:线速率和编码 TX.RX的 Line Rate .Data Path Width .Reference Clock根据项目的实际情况进行选择 Reference Clock :表示 外界时钟输入给GTX模块的参考时钟 注: 红色框代表必须按照截图设置. 绿色框代表根据项目需求进行设置. 黄色框代表,可

Xilinx DDR3 IP核使用问题汇总(持续更新)和感悟

一度因为DDR3的IP核使用而发狂. 后来因为解决问题,得一感悟.后面此贴会完整讲述ddr3 ip的使用.(XILINX K7) 感悟:对于有供应商支持的产品,遇到问题找官方的流程.按照官方的指导进行操作.由于使用软件版本不同可能语法之间有出入或着不兼容,此时常识寻找下载版本最接近的官方Guide来操作,你就会发现解决那些莫名其妙问题的突破点. 问题: 1.综合 a.问题:Unable to set attribute "DQS_AUTO_RECAL" with value "

Vivado使用技巧(二):封装自己设计的IP核

由 judyzhong 于 星期五, 09/08/2017 - 14:58 发表 概述 ??Vivado在设计时可以感觉到一种趋势,它鼓励用IP核的方式进行设计."IP Integrator"提供了原理图设计的方式,只需要在其中调用设计好的IP核连线.IP核一部分来自于Xilinx官方IP:一部分来自于第三方IP,其中有的是在网络上开源的:另一部分就是自己设计的IP.有时候我们需要把自己的一个设计反复用到以后的工程中,利用Vivado的"IP Package"将其封

【OpenHW12参赛手记】ZedBoard-自定义IP核实现+PS成功调用【详细步骤+流程介绍+源码】 转载

文章来源 图片无法复制,请看原文 http://www.eefocus.com/jefby1990/blog/13-03/291975_490bc.html [OpenHW12参赛手记]ZedBoard-自定义IP核实现+PS成功调用[详细步骤+流程介绍+源码] 2013-03-07 17:56:30 分享: (图片请点击查看原图) 软件环境:WIN7_64 + ISE 14.4 (system_edition) 硬件:Zedboard.USB-Cable线 搭建图: 经过前几天的学习,查看数据

自定义AXI总线形式SPI接口IP核,点亮OLED

一.前言 最近花费很多精力在算法仿真和实现上,外设接口的调试略有生疏.本文以FPGA控制OLED中的SPI接口为例,重新夯实下基础.重点内容为SPI时序的RTL设计以及AXI-Lite总线分析.当然做些项目时可以直接调用Xilinx提供的SPI IP核,这里仅出于练习的目的考虑. 二.接口时序分析 本项目用的OLED型号为UG-2832HSWEG04,核心控制器是SSD1306.该芯片支持并口.I2C以及SPI接口,这里采用4线SPI作为数据总线.4线SPI接口包括: SCLK:串行时钟,SSD

明德扬至简设计法设计的IP核加法器

一.功能描述 在Quartus II 和ISE中都有加法器的IP core,可以完成无符号数和有符号数的加.减法,支持有符号数的补码.原码操作及无符号数的加.减操作,引入了最佳流水线操作,可以方便的为用户生成有效的加法器,用户可以根据自己的需要来完成配置加法器 ,本案例用Altera和Xilinx的IP核实现了26位加法器的功能. 二.平台效果图 Altera仿真效果图 Xilinx仿真效果图 三.实现过程 Xilinx输入输出信号列表如下: 信号名 I/O 位宽 说明 clk I 1 系统工作

调用altera IP核的仿真流程—上

调用altera IP核的仿真流程—上 在学习本节内容之后,请详细阅读<基于modelsim-SE的简单仿真流程>,因为本节是基于<基于modelsim-SE的简单仿真流程>的基础上进行设计的,关于设计仿真流程的过程所涉及到的重复内容将不再详述,将会一笔带过,如果深入学习了<基于modelsim-SE的简单仿真流程>这一小节,则下面的内容将会非常的简单. 编写RTL功能代码 本小节通过调用altera的ROM宏功能模块,FPGA的ROM模块主要用于存储数据,可以在上电的