上一節中,記錄到了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 |
1 |
當前寫入數據有效信號 |
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中讀出了數據,說明我們的設計的控制器已經正常工作了。