Zynq中PL读写PS端DDR数据
扫描二维码
随时随地手机看文章
1. 读写DDR底层结构
zynq 7000 SOC的HP口是High-Performance Ports的缩写,如下图所示,一共有4个HP接口,HP接口是AXI Slave设备,我们可以通过这4个HP接口实现高带宽的数据交互。实现PL读写PS端挂载的DDR需要使用HP接口。
如下图所示,选择HP0 interface。
AXI4所采用的是一种READY,VALID握手通信机制,即主从模块进行数据通信前,先根据操作对各所用到的数据、地址通道进行握手。主要操作包括传输发送者A等到传输接受者B的READY信号后,A将数据与VALID信号同时发送给B,这是一种典型的握手机制。
AXI总线分为五个通道:
读地址通道,包含ARVALID, ARADDR, ARREADY信号;
写地址通道,包含AWVALID,AWADDR, AWREADY信号;
读数据通道,包含RVALID, RDATA, RREADY, RRESP信号;
写数据通道,包含WVALID, WDATA,WSTRB, WREADY信号;
写应答通道,包含BVALID, BRESP, BREADY信号;
系统通道,包含:ACLK,ARESETN信号;
其中ACLK为axi总线时钟,ARESETN是axi总线复位信号,低电平有效;读写数据与读写地址类信号宽度都为32bit;READY与VALID是对应的通道握手信号;WSTRB信号为1的bit对应WDATA有效数据字节,WSTRB宽度是32bit/8=4bit;BRESP与RRESP分别为写回应信号,读回应信号,宽度都为2bit,‘h0代表成功,其他为错误。
读操作顺序为主与从进行读地址通道握手并传输地址内容,然后在读数据通道握手并传输所读内容以及读取操作的回应,时钟上升沿有效。如图所示:
写操作顺序为主与从进行写地址通道握手并传输地址内容,然后在写数据通道握手并传输所读内容,最后再写回应通道握手,并传输写回应数据,时钟上升沿有效。如图所示:
附录代码清单:
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 写数据通道 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 写响应通道 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 读数据通道 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;//写数据等待 reg_awvalid <= 1'b1; //写长度减一 :11] <= reg_wr_len[31:11] - 21'd1; :11] != 21'd0) begin :0] <= 8'hFF;//每次写256个数据 reg_w_last <= 1'b0; :0] <= 8'hFF; end else begin//最后不足256个的数据写入 :0] <= reg_wr_len[10:3]; reg_w_last <= 1'b1; :0] <= 8'hFF; end end S_WD_WAIT: begin //等待写总线READY,进入写数据状态 begin wr_state <= S_WD_PROC; reg_awvalid <= 1'b0; //开始写数据 reg_wvalid <= 1'b1; end end //写数据 S_WD_PROC: begin & ~WR_FIFO_EMPTY)begin //一次突发写完成 :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 //写响应完成 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 //读数据等待 S_RD_WAIT: begin begin rd_state <= S_RD_PROC; reg_arvalid <= 1'b0; end end //读数据开始 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





