uisrc 发表于 2023-12-30 15:15:34

2-3-04 AXI4总线axi-full-slave

软件版本:vitis2021.1(vivado2021.1)操作系统:WIN10 64bit硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!1概述使用XILINX 的软件工具VIVADO以及XILINX的7代以上的FPGA或者SOC掌握AXI-4总线结束,并且可以灵活使用AXI-4总线技术完成数据的交换,可以让我们在构建强大的FPGA内部总线数据互联通信方面取得高效、高速、标准化的优势。关于AXI4总线协议的部分介绍请阅读"01AXI4总线axi-lite-slave"。本文实验目的:1:掌握基于VIVADO工具产生AXI协议模板2:掌握通过VIVADO工具产生AXI-full-slave代码3:理解AXI-full-slave中自定义寄存器的地址分配4:掌握通过VIVADO封装AXI-full-slave图形化IP5:通过仿真验证AXI-full-slave IP的工作是否正常。2创建axi4-full-slave总线接口IP新建fpga工程,过程省略新建完成工程后,单击菜单栏Tools->Create and Package New IP,开始创建一个AXI4-Full接口总线IP选择使用vivado自带的AXI总线模板创建一个AXI4-FULL接口IP设置IP的名字为saxi_full模板支持3种协议,分别是AXI4-Full ,AXI4-Lite ,AXI4-Stream,这里选择full;总线包括Master和Slave两种模式,这里选择Slave模式
这里选择Verify Peripheral IP using AXI4 VIP 可以对AXI4-FULL快速验证单击Finish后展开VIVADO自动产生的demo,单击Block Design的工程,可以看到如下2个IP。其中saxi_full_0就是我们自定义的IP,另外一个master_0是用来读写我们自定义的saxi_full_0,以此验证我们的IP正确性。采用默认地址分配即可
继续再看代码看看里面有什么东西3程序分析1:axi-full-slave的axi_awready当满足条件(~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)=1的时候表示可以进行一次AXI-FULL的burst写操作了,这个时候AXI-FULL-SLAVE设置axi_awready <= 1'b1和axi_awv_awr_flag <= 1'b1
// axi_awready is asserted for one S_AXI_ACLK clock cycle when both    // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is    // de-asserted when reset is low.
    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_awready <= 1'b0;          axi_awv_awr_flag <= 1'b0;      end      else      begin              if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)            begin            // slave is ready to accept an address and            // associated control signals            axi_awready <= 1'b1;            axi_awv_awr_flag<= 1'b1;            // used for generation of bresp() and bvalid            end          else if (S_AXI_WLAST && axi_wready)                    // preparing to accept next address after current write burst tx completion            begin            axi_awv_awr_flag<= 1'b0;            end          else                  begin            axi_awready <= 1'b0;            end      end    end   


2:axi-full-slave的axi_awaddrAXI的burst模式包括3种:1:fixed burst这种模式下地址都是相同的2: incremental burst这种模式下地址递增3: Wrapping burst 这只模式下地址达到设置的最大地址边界后返回原来的地址。本文demo中以下三种模式的具体代码如下:
    //This process is used to latch the address when both    //S_AXI_ARVALID and S_AXI_RVALID are valid.    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_araddr <= 0;          axi_arlen_cntr <= 0;          axi_arburst <= 0;          axi_arlen <= 0;          axi_rlast <= 1'b0;          axi_ruser <= 0;      end      else      begin              if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)            begin            // address latching            axi_araddr <= S_AXI_ARADDR;            axi_arburst <= S_AXI_ARBURST;            axi_arlen <= S_AXI_ARLEN;                // start address of transfer            axi_arlen_cntr <= 0;            axi_rlast <= 1'b0;            end          else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)                  begin
            axi_arlen_cntr <= axi_arlen_cntr + 1;            axi_rlast <= 1'b0;
            case (axi_arburst)                2'b00: // fixed burst               // The read address for all the beats in the transaction are fixed                  begin                  axi_araddr       <= axi_araddr;                        //for arsize = 4 bytes (010)                  end                2'b01: //incremental burst                // The read address for all the beats in the transaction are increments by awsize                  begin                  axi_araddr <= axi_araddr + 1;                  //araddr aligned to 4 byte boundary                  axi_araddr<= {ADDR_LSB{1'b0}};                  //for awsize = 4 bytes (010)                  end                2'b10: //Wrapping burst                // The read address wraps when the address reaches wrap boundary                  if (ar_wrap_en)                  begin                      axi_araddr <= (axi_araddr - ar_wrap_size);                  end                  else                  begin                  axi_araddr <= axi_araddr + 1;                  //araddr aligned to 4 byte boundary                  axi_araddr<= {ADDR_LSB{1'b0}};                  end                                      default: //reserved (incremental burst for example)                  begin                  axi_araddr <= axi_araddr+1;                  //for arsize = 4 bytes (010)                  end            endcase                        end          else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )            begin            axi_rlast <= 1'b1;            end                    else if (S_AXI_RREADY)            begin            axi_rlast <= 1'b0;            end                end    end


3:axi-full-slave的axi_wready当满足条件( ~axi_wready && S_AXI_WVALID && axi_awv_awr_flag)==1 设置axi_wready为1.这里可以看出,S_AXI_WVALID必须在一次burst中持续有效,直到满足条件(S_AXI_WLAST && axi_wready),否则AXI-FULL-SLAVE会出错,这一点有别于AXI-LITE-SLAVE每次只读写一个数据。
    // axi_wready is asserted for one S_AXI_ACLK clock cycle when both    // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is    // de-asserted when reset is low.
    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_wready <= 1'b0;      end      else      begin              if ( ~axi_wready && S_AXI_WVALID && axi_awv_awr_flag)            begin            // slave can accept the write data            axi_wready <= 1'b1;            end          //else if (~axi_awv_awr_flag)          else if (S_AXI_WLAST && axi_wready)            begin            axi_wready <= 1'b0;            end      end    end      


4:axi-full-slave的axi_bvalid信号axi_bvalid用于告知axi master axi-slave端已经完成数据接收了给出ACK,写操作LAST信号的下一个时钟,AXI-SLAVE给出ACK信号
    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_bvalid <= 0;          axi_bresp <= 2'b0;          axi_buser <= 0;      end      else      begin              if (axi_awv_awr_flag && axi_wready && S_AXI_WVALID && ~axi_bvalid && S_AXI_WLAST )            begin            axi_bvalid <= 1'b1;            axi_bresp<= 2'b0;            // 'OKAY' response            end                            else            begin            if (S_AXI_BREADY && axi_bvalid)            //check if bready is asserted while bvalid is high)            //(there is a possibility that bready is always asserted high)                begin                  axi_bvalid <= 1'b0;                end            end      end   end


5:axi-full-slave的axi_arready信号当满足条件(~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)=1的时候表示可以进行一次AXI-FULL的burst读操作了,这个时候AXI -FULL-SLAVE设置axi_arready <= 1'b1和axi_arv_arr_flag <= 1'b1
// S_AXI_ARVALID is asserted. axi_awready is    // de-asserted when reset (active low) is asserted.    // The read address is also latched when S_AXI_ARVALID is    // asserted. axi_araddr is reset to zero on reset assertion.
    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_arready <= 1'b0;          axi_arv_arr_flag <= 1'b0;      end      else      begin              if (~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)            begin            axi_arready <= 1'b1;            axi_arv_arr_flag <= 1'b1;            end          else if (axi_rvalid && S_AXI_RREADY && axi_arlen_cntr == axi_arlen)          // preparing to accept next address after current read completion            begin            axi_arv_arr_flag<= 1'b0;            end          else                  begin            axi_arready <= 1'b0;            end      end    end      


6:axi-full-slave的axi_araddr信号AXI-的读写操作几乎是相对的代码,AXI的burst模式包括3种:1:fixed burst这种模式下地址都是相同的2: incremental burst这种模式下地址递增3: Wrapping burst 这只模式下地址达到设置的最大地址边界后返回原来的地址。本文demo种以下三种模式的具体代码如下:


//This process is used to latch the address when both    //S_AXI_ARVALID and S_AXI_RVALID are valid.    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_araddr <= 0;          axi_arlen_cntr <= 0;          axi_arburst <= 0;          axi_arlen <= 0;          axi_rlast <= 1'b0;          axi_ruser <= 0;      end      else      begin             if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)            begin            // address latching            axi_araddr <= S_AXI_ARADDR;            axi_arburst <= S_AXI_ARBURST;            axi_arlen <= S_AXI_ARLEN;               // start address of transfer            axi_arlen_cntr <= 0;            axi_rlast <= 1'b0;            end          else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)                  begin
            axi_arlen_cntr <= axi_arlen_cntr + 1;            axi_rlast <= 1'b0;
            case (axi_arburst)                2'b00: // fixed burst               // The read address for all the beats in the transaction are fixed                  begin                  axi_araddr       <= axi_araddr;                        //for arsize = 4 bytes (010)                  end                2'b01: //incremental burst                // The read address for all the beats in the transaction are increments by awsize                  begin                  axi_araddr <= axi_araddr + 1;                  //araddr aligned to 4 byte boundary                  axi_araddr<= {ADDR_LSB{1'b0}};                  //for awsize = 4 bytes (010)                  end                2'b10: //Wrapping burst                // The read address wraps when the address reaches wrap boundary                  if (ar_wrap_en)                  begin                      axi_araddr <= (axi_araddr - ar_wrap_size);                  end                  else                  begin                  axi_araddr <= axi_araddr + 1;                  //araddr aligned to 4 byte boundary                  axi_araddr<= {ADDR_LSB{1'b0}};                  end                                     default: //reserved (incremental burst for example)                  begin                  axi_araddr <= axi_araddr+1;                  //for arsize = 4 bytes (010)                  end            endcase                        end          else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )            begin            axi_rlast <= 1'b1;            end                   else if (S_AXI_RREADY)            begin            axi_rlast <= 1'b0;            end               end    end   




7:axi-full-slave的axi_rvalid信号在用VIVADO模板产生的demo中,读操作数据不是连续读的,通过axi_rvalid设置AXI-SLAVE FULL读数据有效。
    always @( posedge S_AXI_ACLK )    begin      if ( S_AXI_ARESETN == 1'b0 )      begin          axi_rvalid <= 0;          axi_rresp<= 0;      end      else      begin              if (axi_arv_arr_flag && ~axi_rvalid)            begin            axi_rvalid <= 1'b1;            axi_rresp<= 2'b0;            // 'OKAY' response            end          else if (axi_rvalid && S_AXI_RREADY)            begin            axi_rvalid <= 1'b0;            end                  end    end


8:数据保存到bock ram以下是利用block ram完成数据的保存和回读
    // implement Block RAM(s)    generate      for(i=0; i<= USER_NUM_MEM-1; i=i+1)      begin:BRAM_GEN          wire mem_rden;          wire mem_wren;
          assign mem_wren = axi_wready && S_AXI_WVALID ;
          assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
          for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)          begin:BYTE_BRAM_GEN            wire data_in ;            wire data_out;            reg byte_ram ;            integerj;
            //assigning 8 bit data            assign data_in= S_AXI_WDATA[(mem_byte_index*8+7) -: 8];            assign data_out = byte_ram;
            always @( posedge S_AXI_ACLK )            begin            if (mem_wren && S_AXI_WSTRB)                begin                  byte_ram <= data_in;                end            end   
            always @( posedge S_AXI_ACLK )            begin            if (mem_rden)                begin                  mem_data_out[(mem_byte_index*8+7) -: 8] <= data_out;                end            end   
      end      end          endgenerate


4实验结果仿真结果:
页: [1]
查看完整版本: 2-3-04 AXI4总线axi-full-slave