Zynq中PL讀寫PS端DDR數(shù)據(jù)
掃描二維碼
隨時隨地手機看文章
1. 讀寫DDR底層結(jié)構(gòu)
zynq 7000 SOC的HP口是High-Performance Ports的縮寫,如下圖所示,一共有4個HP接口,HP接口是AXI Slave設(shè)備,我們可以通過這4個HP接口實現(xiàn)高帶寬的數(shù)據(jù)交互。實現(xiàn)PL讀寫PS端掛載的DDR需要使用HP接口。
如下圖所示,選擇HP0 interface。
AXI4所采用的是一種READY,VALID握手通信機制,即主從模塊進(jìn)行數(shù)據(jù)通信前,先根據(jù)操作對各所用到的數(shù)據(jù)、地址通道進(jìn)行握手。主要操作包括傳輸發(fā)送者A等到傳輸接受者B的READY信號后,A將數(shù)據(jù)與VALID信號同時發(fā)送給B,這是一種典型的握手機制。
AXI總線分為五個通道:
?讀地址通道,包含ARVALID, ARADDR, ARREADY信號;
?寫地址通道,包含AWVALID,AWADDR, AWREADY信號;
?讀數(shù)據(jù)通道,包含RVALID, RDATA, RREADY, RRESP信號;
?寫數(shù)據(jù)通道,包含WVALID, WDATA,WSTRB, WREADY信號;
?寫應(yīng)答通道,包含BVALID, BRESP, BREADY信號;
?系統(tǒng)通道,包含:ACLK,ARESETN信號;
其中ACLK為axi總線時鐘,ARESETN是axi總線復(fù)位信號,低電平有效;讀寫數(shù)據(jù)與讀寫地址類信號寬度都為32bit;READY與VALID是對應(yīng)的通道握手信號;WSTRB信號為1的bit對應(yīng)WDATA有效數(shù)據(jù)字節(jié),WSTRB寬度是32bit/8=4bit;BRESP與RRESP分別為寫回應(yīng)信號,讀回應(yīng)信號,寬度都為2bit,‘h0代表成功,其他為錯誤。
讀操作順序為主與從進(jìn)行讀地址通道握手并傳輸?shù)刂穬?nèi)容,然后在讀數(shù)據(jù)通道握手并傳輸所讀內(nèi)容以及讀取操作的回應(yīng),時鐘上升沿有效。如圖所示:
寫操作順序為主與從進(jìn)行寫地址通道握手并傳輸?shù)刂穬?nèi)容,然后在寫數(shù)據(jù)通道握手并傳輸所讀內(nèi)容,最后再寫回應(yīng)通道握手,并傳輸寫回應(yīng)數(shù)據(jù),時鐘上升沿有效。如圖所示:
附錄代碼清單:
moduleaq_axi_master( Reset, Clock input ARESETN, input ACLK, Master 寫地址通道 output [0:0] M_AXI_AWID, output [31:0] M_AXI_AWADDR, output [7:0] M_AXI_AWLEN, // Burst Length:0-255 output [2:0] M_AXI_AWSIZE, // Burst Size:Fixed 2'b011 output [1:0] M_AXI_AWBURST, // Burst Type:Fixed 2'b01(Incremental Burst) output M_AXI_AWLOCK, // Lock: Fixed2'b00 output [3:0] M_AXI_AWCACHE, // Cache: Fiex2'b0011 output [2:0] M_AXI_AWPROT, // Protect: Fixed2'b000 output [3:0] M_AXI_AWQOS, // QoS: Fixed2'b0000 output [0:0] M_AXI_AWUSER, // User: Fixed32'd0 output M_AXI_AWVALID, input M_AXI_AWREADY, Master 寫數(shù)據(jù)通道 output [63:0] M_AXI_WDATA, output [7:0] M_AXI_WSTRB, output M_AXI_WLAST, output [0:0] M_AXI_WUSER, output M_AXI_WVALID, input M_AXI_WREADY, Master 寫響應(yīng)通道 input [0:0] M_AXI_BID, input [1:0] M_AXI_BRESP, input [0:0] M_AXI_BUSER, input M_AXI_BVALID, output M_AXI_BREADY, Master 讀地址通道 output [0:0] M_AXI_ARID, output [31:0] M_AXI_ARADDR, output [7:0] M_AXI_ARLEN, output [2:0] M_AXI_ARSIZE, output [1:0] M_AXI_ARBURST, output [1:0] M_AXI_ARLOCK, output [3:0] M_AXI_ARCACHE, output [2:0] M_AXI_ARPROT, output [3:0] M_AXI_ARQOS, output [0:0] M_AXI_ARUSER, output M_AXI_ARVALID, input M_AXI_ARREADY, Master 讀數(shù)據(jù)通道 input [0:0] M_AXI_RID, input [63:0] M_AXI_RDATA, input [1:0] M_AXI_RRESP, input M_AXI_RLAST, input [0:0] M_AXI_RUSER, input M_AXI_RVALID, output M_AXI_RREADY, Local Bus input MASTER_RST, input WR_START, input [31:0] WR_ADRS, input [31:0] WR_LEN, output WR_READY, output WR_FIFO_RE, input WR_FIFO_EMPTY, input WR_FIFO_AEMPTY, input [63:0] WR_FIFO_DATA, output WR_DONE, input RD_START, input [31:0] RD_ADRS, input [31:0] RD_LEN, output RD_READY, output RD_FIFO_WE, input RD_FIFO_FULL, input RD_FIFO_AFULL, output [63:0] RD_FIFO_DATA, output RD_DONE, output [31:0] DEBUG); localparam S_WR_IDLE = 3'd0; localparam S_WA_WAIT = 3'd1; localparam S_WA_START = 3'd2; localparam S_WD_WAIT = 3'd3; localparam S_WD_PROC = 3'd4; localparam S_WR_WAIT = 3'd5; localparam S_WR_DONE = 3'd6; reg [2:0] wr_state; reg [31:0] reg_wr_adrs; reg [31:0] reg_wr_len; reg reg_awvalid, reg_wvalid, reg_w_last; reg [7:0] reg_w_len; reg [7:0] reg_w_stb; reg [1:0] reg_wr_status; reg [3:0] reg_w_count, reg_r_count; reg [7:0] rd_chkdata, wr_chkdata; reg [1:0] resp; reg rd_first_data; reg rd_fifo_enable; :0] rd_fifo_cnt;assign WR_DONE =(wr_state == S_WR_DONE); assignWR_FIFO_RE = rd_first_data |(reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY & rd_fifo_enable);always @(posedgeACLK or negedge ARESETN)begin if(!ARESETN) rd_fifo_cnt <= 32'd0; else if(WR_FIFO_RE) rd_fifo_cnt <= rd_fifo_cnt +32'd1; else if(wr_state == S_WR_IDLE) rd_fifo_cnt <= 32'd0;end always @(posedgeACLK or negedge ARESETN)begin if(!ARESETN) rd_fifo_enable <= 1'b0; else if(wr_state == S_WR_IDLE &&WR_START) rd_fifo_enable <= 1'b1; else if(WR_FIFO_RE && (rd_fifo_cnt== RD_LEN[31:3] - 32'd1) ) rd_fifo_enable <= 1'b0; end Write State always @(posedge ACLK or negedge ARESETN)begin begin wr_state <= S_WR_IDLE; :0] <= 32'd0; :0] <= 32'd0; reg_awvalid <= 1'b0; reg_wvalid <= 1'b0; reg_w_last <= 1'b0; :0] <= 8'd0; :0] <= 8'd0; :0] <= 2'd0; :0] <= 4'd0; :0] <= 4'd0; wr_chkdata <= 8'd0; rd_chkdata <= 8'd0; resp <= 2'd0; rd_first_data <= 1'b0; end else begin begin wr_state <= S_WR_IDLE; end else begin case(wr_state) S_WR_IDLE: begin begin //外部開始寫地址 wr_state <= S_WA_WAIT; :0] <=WR_ADRS[31:0];//寫地址 :0] <= WR_LEN[31:0] -32'd1;//寫長度 rd_first_data <= 1'b1; end reg_awvalid <= 1'b0; reg_wvalid <= 1'b0; reg_w_last <= 1'b0; :0] <= 8'd0; :0] <= 8'd0; :0] <= 2'd0; end //寫地址等待 S_WA_WAIT: begin //外部FIFO不空或者長度為0則開始寫地址 |(reg_wr_len[31:11] == 21'd0)) begin wr_state <= S_WA_START; end rd_first_data <= 1'b0; end //寫地址開始 S_WA_START: begin wr_state <= S_WD_WAIT;//寫數(shù)據(jù)等待 reg_awvalid <= 1'b1; //寫長度減一 :11] <= reg_wr_len[31:11] - 21'd1; :11] != 21'd0) begin :0] <= 8'hFF;//每次寫256個數(shù)據(jù) reg_w_last <= 1'b0; :0] <= 8'hFF; end else begin//最后不足256個的數(shù)據(jù)寫入 :0] <= reg_wr_len[10:3]; reg_w_last <= 1'b1; :0] <= 8'hFF; end end S_WD_WAIT: begin //等待寫總線READY,進(jìn)入寫數(shù)據(jù)狀態(tài) begin wr_state <= S_WD_PROC; reg_awvalid <= 1'b0; //開始寫數(shù)據(jù) reg_wvalid <= 1'b1; end end //寫數(shù)據(jù) S_WD_PROC: begin & ~WR_FIFO_EMPTY)begin //一次突發(fā)寫完成 :0] == 8'd0) begin wr_state <= S_WR_WAIT; reg_wvalid <= 1'b0; :0] <= 8'h00; end else begin :0] <= reg_w_len[7:0] -8'd1; end end end //寫等待 S_WR_WAIT: begin //寫響應(yīng)完成 begin :0] <= reg_wr_status[1:0] | M_AXI_BRESP[1:0]; begin//寫完成 wr_state <= S_WR_DONE; end else begin//寫未完成 wr_state <= S_WA_WAIT; //地址每次遞增 :0] <=reg_wr_adrs[31:0] + 32'd2048; end end end S_WR_DONE: begin wr_state <= S_WR_IDLE; end default: begin wr_state <= S_WR_IDLE; end endcase end end end assign M_AXI_AWID = 1'b0; assign M_AXI_AWADDR[31:0] =reg_wr_adrs[31:0]; assign M_AXI_AWLEN[7:0] = reg_w_len[7:0]; assign M_AXI_AWSIZE[2:0] = 2'b011; assign M_AXI_AWBURST[1:0] = 2'b01; assign M_AXI_AWLOCK = 1'b0; assign M_AXI_AWCACHE[3:0] = 4'b0011; assign M_AXI_AWPROT[2:0] = 3'b000; assign M_AXI_AWQOS[3:0] = 4'b0000; assign M_AXI_AWUSER[0] = 1'b1; assign M_AXI_AWVALID = reg_awvalid; assign M_AXI_WDATA[63:0] = WR_FIFO_DATA[63:0]; assign M_AXI_WSTRB[7:0] = (reg_wvalid & ~WR_FIFO_EMPTY)?8'hFF:8'h00; assign M_AXI_WLAST = (reg_w_len[7:0] == 8'd0)?1'b1:1'b0; assign M_AXI_WUSER = 1; assign M_AXI_WVALID = reg_wvalid & ~WR_FIFO_EMPTY; assign M_AXI_BREADY = M_AXI_BVALID; assign WR_READY = (wr_state == S_WR_IDLE)?1'b1:1'b0; localparam S_RD_IDLE = 3'd0; localparam S_RA_WAIT = 3'd1; localparam S_RA_START = 3'd2; localparam S_RD_WAIT = 3'd3; localparam S_RD_PROC = 3'd4; localparam S_RD_DONE = 3'd5; reg [2:0] rd_state; :0] reg_rd_adrs; reg [31:0] reg_rd_len; reg reg_arvalid, reg_r_last; reg [7:0] reg_r_len; assign RD_DONE = (rd_state == S_RD_DONE) ; Read State always @(posedge ACLK or negedge ARESETN)begin begin rd_state <= S_RD_IDLE; :0] <= 32'd0; :0] <= 32'd0; reg_arvalid <= 1'b0; :0] <= 8'd0; end else begin case(rd_state) S_RD_IDLE: begin //讀開始 begin rd_state <= S_RA_WAIT; :0] <=RD_ADRS[31:0]; :0] <= RD_LEN[31:0] -32'd1; end reg_arvalid <= 1'b0; :0] <= 8'd0; end //讀通道等待 S_RA_WAIT: begin begin rd_state <= S_RA_START; end end //讀地址開始 S_RA_START: begin rd_state <= S_RD_WAIT; reg_arvalid <= 1'b1; :11] <=reg_rd_len[31:11] -21'd1; :11] != 21'd0) begin reg_r_last <= 1'b0; :0] <= 8'd255; end else begin reg_r_last <= 1'b1; :0] <= reg_rd_len[10:3]; end end //讀數(shù)據(jù)等待 S_RD_WAIT: begin begin rd_state <= S_RD_PROC; reg_arvalid <= 1'b0; end end //讀數(shù)據(jù)開始 S_RD_PROC: begin begin begin begin rd_state <= S_RD_DONE; end else begin rd_state <= S_RA_WAIT; :0] <=reg_rd_adrs[31:0] + 32'd2048; end end else begin :0] <=reg_r_len[7:0] -8'd1; end end end S_RD_DONE:begin rd_state <= S_RD_IDLE; end endcase end end Master Read Address assign M_AXI_ARID = 1'b0; assign M_AXI_ARADDR[31:0] =reg_rd_adrs[31:0]; assign M_AXI_ARLEN[7:0] = reg_r_len[7:0]; assign M_AXI_ARSIZE[2:0] = 3'b011; assign M_AXI_ARBURST[1:0] = 2'b01; assign M_AXI_ARLOCK = 1'b0; assign M_AXI_ARCACHE[3:0] = 4'b0011; assign M_AXI_ARPROT[2:0] = 3'b000; assign M_AXI_ARQOS[3:0] = 4'b0000; assign M_AXI_ARUSER[0] = 1'b1; assignM_AXI_ARVALID = reg_arvalid; assign M_AXI_RREADY = M_AXI_RVALID & ~RD_FIFO_FULL; assign RD_READY = (rd_state == S_RD_IDLE)?1'b1:1'b0; assign RD_FIFO_WE = M_AXI_RVALID; assign RD_FIFO_DATA[63:0] = M_AXI_RDATA[63:0]; assign DEBUG[31:0] = {reg_wr_len[31:8], wr_state[2:0],1'd0, rd_state[2:0]}; endmodule





