ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2019-12-29 19:54:28  阅读:339  来源: 互联网

标签:wire IP app MIG rd ddr wr DDR3 data


上一节中,记录到了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 - 1530604142@qq.com
  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 - 1530604142@qq.com
  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 - 1530604142@qq.com
#
# 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 - 1530604142@qq.com
  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中读出了数据,说明我们的设计的控制器已经正常工作了。

标签:wire,IP,app,MIG,rd,ddr,wr,DDR3,data
来源: https://www.cnblogs.com/weicc/p/12051840.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有