亲宝软件园·资讯

展开

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

black_pigeon 人气:0

上一节中,记录到了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         ,/https://img.qb5200.com/download-x/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         ,/https://img.qb5200.com/download-x/ddr命令通道空闲
 30 
 31     input    wire            app_rd_data_vld    ,/https://img.qb5200.com/download-x/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    ,/https://img.qb5200.com/download-x/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中读出了数据,说明我们的设计的控制器已经正常工作了。

加载全部内容

相关教程
猜你喜欢
用户评论