基於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 - 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中讀出了數據,說明我們的設計的控制器已經正常工作了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM