当前位置:首页 > > ZYNQ

1. 读写DDR底层结构

zynq 7000 SOCHP口是High-Performance Ports的缩写,如下图所示,一共有4HP接口,HP接口是AXI Slave设备,我们可以通过这4HP接口实现高带宽的数据交互。实现PL读写PS端挂载的DDR需要使用HP接口。

如下图所示,选择HP0 interface。

使用的时钟是150MhzHP的带宽是150Mhz * 64bit,对于视频处理,ADC数据采集等应用都有足够的带宽。如下图所示,配置完HP端口以后,zynq会多出一个AXI Slave端口,名称为S_AXI_HP0,不过这些端口都是AXI3标准的,我们常用的是AXI4协议,这里添加1AXI Interconnect IP,用于协议转换(AXI3AXI4)。设置S00_AXI端口为AXI4协议。

2. PLAXI   MASTER的机制

AXI4所采用的是一种READYVALID握手通信机制,即主从模块进行数据通信前,先根据操作对各所用到的数据、地址通道进行握手。主要操作包括传输发送者A等到传输接受者BREADY信号后,A将数据与VALID信号同时发送给B,这是一种典型的握手机制。


AXI总线分为五个通道:

读地址通道,包含ARVALID, ARADDR, ARREADY信号;

写地址通道,包含AWVALIDAWADDR, AWREADY信号;

读数据通道,包含RVALID, RDATA, RREADY, RRESP信号;

写数据通道,包含WVALID, WDATAWSTRB, WREADY信号;

写应答通道,包含BVALID, BRESP, BREADY信号;

系统通道,包含:ACLKARESETN信号;


其中ACLKaxi总线时钟,ARESETNaxi总线复位信号,低电平有效;读写数据与读写地址类信号宽度都为32bitREADYVALID是对应的通道握手信号;WSTRB信号为1bit对应WDATA有效数据字节,WSTRB宽度是32bit/8=4bitBRESPRRESP分别为写回应信号,读回应信号,宽度都为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; reg[31: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 if(!ARESETN) begin wr_state <= S_WR_IDLE; reg_wr_adrs[31:0]   <= 32'd0; reg_wr_len[31:0]    <= 32'd0; reg_awvalid <= 1'b0; reg_wvalid <= 1'b0; reg_w_last <= 1'b0; reg_w_len[7:0]      <= 8'd0; reg_w_stb[7:0]      <= 8'd0; reg_wr_status[1:0]  <= 2'd0; reg_w_count[3:0]    <= 4'd0; reg_r_count[3:0]  <= 4'd0; wr_chkdata <= 8'd0; rd_chkdata <= 8'd0; resp <= 2'd0; rd_first_data <= 1'b0; end else begin if(MASTER_RST) begin wr_state <= S_WR_IDLE; end else begin case(wr_state) S_WR_IDLE: begin if(WR_START) begin              //外部开始写地址 wr_state <= S_WA_WAIT; reg_wr_adrs[31:0] <=WR_ADRS[31:0];//写地址 reg_wr_len[31: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; reg_w_len[7:0]      <= 8'd0; reg_w_stb[7:0]      <= 8'd0; reg_wr_status[1:0]  <= 2'd0; end //写地址等待 S_WA_WAIT: begin //外部FIFO不空或者长度为0则开始写地址 if(!WR_FIFO_AEMPTY |(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; //写长度减一 reg_wr_len[31:11]    <= reg_wr_len[31:11] - 21'd1; if(reg_wr_len[31:11] != 21'd0) begin reg_w_len[7:0]  <= 8'hFF;//每次写256个数据 reg_w_last <= 1'b0; reg_w_stb[7:0]  <= 8'hFF; end else begin//最后不足256个的数据写入 reg_w_len[7:0]  <= reg_wr_len[10:3]; reg_w_last <= 1'b1; reg_w_stb[7:0]  <= 8'hFF; end end S_WD_WAIT: begin //等待写总线READY,进入写数据状态 if(M_AXI_AWREADY) begin wr_state <= S_WD_PROC; reg_awvalid <= 1'b0; //开始写数据 reg_wvalid <= 1'b1; end end //写数据 S_WD_PROC: begin if(M_AXI_WREADY & ~WR_FIFO_EMPTY)begin //一次突发写完成 if(reg_w_len[7:0] == 8'd0) begin wr_state <= S_WR_WAIT; reg_wvalid <= 1'b0; reg_w_stb[7:0]  <= 8'h00; end else begin reg_w_len[7:0]  <= reg_w_len[7:0] -8'd1; end end end //写等待 S_WR_WAIT: begin //写响应完成 if(M_AXI_BVALID) begin reg_wr_status[1:0]  <= reg_wr_status[1:0] | M_AXI_BRESP[1:0]; if(reg_w_last) begin//写完成 wr_state <= S_WR_DONE; end else begin//写未完成 wr_state <= S_WA_WAIT; //地址每次递增 reg_wr_adrs[31: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; reg[31: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 if(!ARESETN) begin rd_state <= S_RD_IDLE; reg_rd_adrs[31:0] <= 32'd0; reg_rd_len[31:0]  <= 32'd0; reg_arvalid <= 1'b0; reg_r_len[7:0]    <= 8'd0; end else begin case(rd_state) S_RD_IDLE: begin //读开始 if(RD_START) begin rd_state <= S_RA_WAIT; reg_rd_adrs[31:0] <=RD_ADRS[31:0]; reg_rd_len[31:0]  <= RD_LEN[31:0] -32'd1; end reg_arvalid <= 1'b0; reg_r_len[7:0]  <= 8'd0; end //读通道等待 S_RA_WAIT: begin if(~RD_FIFO_AFULL) begin rd_state <= S_RA_START; end end //读地址开始 S_RA_START: begin rd_state <= S_RD_WAIT; reg_arvalid <= 1'b1; reg_rd_len[31:11] <=reg_rd_len[31:11] -21'd1; if(reg_rd_len[31:11] != 21'd0) begin reg_r_last <= 1'b0; reg_r_len[7:0]  <= 8'd255; end else begin reg_r_last <= 1'b1; reg_r_len[7:0]  <= reg_rd_len[10:3]; end end //读数据等待 S_RD_WAIT: begin if(M_AXI_ARREADY) begin rd_state <= S_RD_PROC; reg_arvalid <= 1'b0; end end //读数据开始 S_RD_PROC: begin if(M_AXI_RVALID) begin if(M_AXI_RLAST) begin if(reg_r_last) begin rd_state <= S_RD_DONE; end else begin rd_state <= S_RA_WAIT; reg_rd_adrs[31:0] <=reg_rd_adrs[31:0] + 32'd2048; end end else begin reg_r_len[7: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], 1'd0, wr_state[2:0],1'd0, rd_state[2:0]}; endmodule
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭