AXI外设IP的AXI-lite代码阅读记录

AXI lite 总线源码时碰见未见过的运算符,所以搜索记录下,此运算符在for语句用得多。

https://zhuanlan.zhihu.com/p/77528158

https://zhuanlan.zhihu.com/p/145936888

以上链接为AXI lite的代码分析

“+:”、"-:"语法
运算符,运用在多位的变量中,如下:
slv_reg0[(byte_index8) +: 8] <= S_AXI_WDATA[(byte_index8) +: 8];

"+:"
变量[起始地址 +: 数据位宽]
等价于
变量[(起始地址+数据位宽-1):起始地址]

data[0 +: 8]  //等价于--> data[7:0]
data[15 +: 2] //等价于--> data[16:15]

"-:"
变量[结束地址 -: 数据位宽]
等价于
变量[结束地址:(结束地址-数据位宽+1)]

data[7 -: 8]  //等价于--> data[7:0]
data[15 -: 2] //等价于--> data[15:14]

//

由FDMA代码里的AWSIZE引出是基本概念

参考:
https://zhuanlan.zhihu.com/p/96804919

AXI FULL、AXI Lite、AXI Stream

AXI FULL传输数据是全双工的。也就是说。读写是同时进行的。

一条AXI总线上有5个通道。两个用于读。三个用于写。

AXI是支持多个数据的。这种传输模式叫突发传输。至于为什么叫突发而不叫连续,自己品。

一个突发传输是靠几个信号来描述的。这些信号同在AXI总线里。

Burst length: ARLEN[7:0]和AWLEN[7:0]表示的就是这个。。。表示的是连续传输的周期数。一个burst内部是不可以被打断的。。所以data valid一旦高起来就要把一个burst传完再拉低,slave的ready信号可以中断,但是最终还是要高起来传完一个burst. 对于master来说,一旦开始传数,一个burst之间的valid应该是不会低的。

Burst size:
指的是 每一拍含有的 Byte数,而不是bit数,所以总线32位,每次只能传输32bit burst size = 32,也就是AWSIZE[2:0] = b101,那么每一拍含有 32 x8 bits

指的是一个burst里面有多少Byte. ARSIZE[2:0]和AWSIZE[2:0] 里就是这个。**为什么只有3bit呢?因为只有8种情况。1,2,4,8,16,32,64,128。(对应arsize/awsize的0,1,2,3,4,5,6,7)**这个里面其实有个非常小的问题。。一般来说。总线位宽和burst size一致的。。比如总线64bit, burst size是8Byte. 但是你要说我头铁非要给个不一样的值。。那也没问题。你总线是8BTYE, 你给了个2BYTE的Burst size, 那你就要指定,每次传输这个2BYTE要放到8BYTE的哪几个BTYE上去。所以没事儿别折腾自己。

那你说我非要折腾自己呢?也行。这种传输叫narrow transfers。往哪个地方上写,可以用WSTRB[N]这歌信号控制。数据会写到WDATA[(8n)+7: (8n)]
在这里插入图片描述
比如上面这个例子,32bit的地址总线。burst size给了个8bit. 那就靠WSTRB这个信号确定往哪儿写。比如上面。传输了5次。可以控制数据往不同地方写。

Burst type: 这个有三种。FIXED表示你一直往初始地址猛怼。INCR表示你从初始地址开始累加。WRAP表示加到某个值后返回初始地址。

另外要说的一点是。AXI是支持非对齐传输的。
在这里插入图片描述
例如上面这种情况。如果地址从7开始。传输5次。前三个BYTE是无效的,不会被传输。用WSTRB信号就可保证这一点。keep信号表示的是BTYE是否有效。
在这里插入图片描述
AXI-Lite:
AXI-LITE是Burst-length严格定于1, burst size严格定于总线位宽的AXI.
最明显的阉割就是不支持burst length, 只能一个数据一个数据读写,读写的位宽和总线位宽一致的。其他阉割可以自己看文档。

AXI-STREAM:
顾名思义,是stream。流的意思。视频流,数据流什么的。AXI-STREAM和AXI之间的关系不像是相互阉割的关系。而是各有所长。当然,他们用的握手协议还是一样的。

AXI-STREAM相比于AXI最显著的特点是,总线上没有数目。只用TLAST表示传输结束。这样导致AXI-STREAM的信号非常简单。

TLAST 由于总线上没有传输数目。所以最后一个数据时TLAST会高起,表明传输完成了。

TKEEP 这是一个多比特的信号。比如总线8个Byte. 这个信号8bit. 每一个bit对应的是总线上对应的BYTE是不是有效的。

TSTRB 这也是一个多比特信号。也是说明总线上的数据是不是有效的。

那这个地方你可能会问,TKEEP和TSTSTRB到底有啥区别?

区别是这样的。TKEEP要是为0。代表了这个数据完全没用,可以被扔掉了。

在TKEEP为1的前提下,表示这个信号不能扔掉。那TSTRB就起作用了。TSTRB为1,表示对应的数据有效,是个好数据。TSTRB为0时,表示这个是个占位数据,没啥意义,但是不能丢掉。为什么需要占位数据呢?是因为有时候需要AXISTREAM传输的数据队形不能乱。就像下图对应的情况。
在这里插入图片描述
其他细节处查手册

总结
AXI-FULL作用是给定地址与传输数量,进行burst传输。
AXI-LITE作用是给定地址,单个数据的读写。
AXI-STREAM作用是不给地址,不给数量,像水管一样靠last这个阀门传输数据。

//

FDMA代码分析AXI总线


`timescale 1 ns / 1 ps
/*
Company : Liyang Milian Electronic Technology Co., Ltd.
Brand: 米联客(msxbo)
Technical forum:uisrc.com
taobao: osrc.taobao.com
Create Date: 2019/12/17
Module Name: uiFDMA
Description: 
Copyright: Copyright (c) msxbo
Revision: 1.0
Signal description:
1) _i input
2) _o output
3) _n activ low
4) _dg debug signal 
5) _r delay or register
6) _s state mechine
*/

	module uiFDMA#
	(
		parameter  integer        C_M_AXI_BURST_LEN		    = 64			, 
		parameter  integer        C_M_AXI_ID_WIDTH			= 1				,
		parameter  integer        C_M_AXI_ID			        = 0				,
		parameter  integer        C_M_AXI_ADDR_WIDTH			= 32			,
		parameter  integer        C_M_AXI_DATA_WIDTH			= 32					
	)
	(

		//user logic 
		input   wire                               pkg_wr_areq         ,		
		output  wire                               pkg_wr_last			,
		input   wire [C_M_AXI_DATA_WIDTH-1 :0]     pkg_wr_data			,
		output	wire                               pkg_wr_en			,
		input   wire [C_M_AXI_ADDR_WIDTH-1 :0]     pkg_wr_addr			,
		input   wire [C_M_AXI_ADDR_WIDTH-1 :0]     pkg_wr_size         , 

        input   wire                               pkg_rd_areq         ,     
		output  wire                               pkg_rd_last			,
		output  wire [C_M_AXI_DATA_WIDTH-1 :0]     pkg_rd_data			,	
		output  wire                               pkg_rd_en           ,  	
		input   wire [C_M_AXI_ADDR_WIDTH-1 :0]     pkg_rd_addr			, 	
		input   wire [C_M_AXI_ADDR_WIDTH-1 :0]     pkg_rd_size         , 			
		//input  	wire  							INIT_AXI_TXN		,
		
		input 	wire  								M_AXI_ACLK			,
		input 	wire  								M_AXI_ARESETN		,
		output 	wire [C_M_AXI_ID_WIDTH-1 : 0]		M_AXI_AWID			,//写地址ID,用于写地址信号组的标记	 
		output 	wire [C_M_AXI_ADDR_WIDTH-1 : 0] 	M_AXI_AWADDR		,//    
		output 	wire [7 : 0]						M_AXI_AWLEN			,    
		output 	wire [2 : 0] 						M_AXI_AWSIZE		,    
		output 	wire [1 : 0] 						M_AXI_AWBURST		,    
		output 	wire  								M_AXI_AWLOCK		,    
		output 	wire [3 : 0] 						M_AXI_AWCACHE		,    
		output 	wire [2 : 0] 						M_AXI_AWPROT		,    
		output 	wire [3 : 0] 						M_AXI_AWQOS			,     
		output 	wire  								M_AXI_AWVALID		,    
		input	wire  								M_AXI_AWREADY		,    
		output  wire [C_M_AXI_DATA_WIDTH-1 : 0] 	M_AXI_WDATA			,	 
		output  wire [C_M_AXI_DATA_WIDTH/8-1 : 0] 	M_AXI_WSTRB			,	 
		output  wire  								M_AXI_WLAST			,	 			
		output  wire  								M_AXI_WVALID		,	 
		input   wire  								M_AXI_WREADY		,	 
		input   wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_BID			,		
		input   wire [1 : 0] 						M_AXI_BRESP			,		
		input   wire  								M_AXI_BVALID		,	
		output  wire  								M_AXI_BREADY		,	 
		                                                                     
		output  wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_ARID			,	 
		output  wire [C_M_AXI_ADDR_WIDTH-1 : 0] 	M_AXI_ARADDR		,	 	
		output  wire [7 : 0] 						M_AXI_ARLEN			,	 
		output  wire [2 : 0] 						M_AXI_ARSIZE		,	 
		output  wire [1 : 0] 						M_AXI_ARBURST		,	 
		output  wire  								M_AXI_ARLOCK		,	 
		output  wire [3 : 0] 						M_AXI_ARCACHE		,	 
		output  wire [2 : 0] 						M_AXI_ARPROT		,	 
		output  wire [3 : 0] 						M_AXI_ARQOS			,	 	   
		output  wire  								M_AXI_ARVALID		,	 
		input   wire  								M_AXI_ARREADY		,	 
		input   wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_RID			,	 
		input   wire [C_M_AXI_DATA_WIDTH-1 : 0] 	M_AXI_RDATA			,	 
		input   wire [1 : 0] 						M_AXI_RRESP			,	 
		input   wire  								M_AXI_RLAST			,	 
		input   wire  								M_AXI_RVALID		,    
		output  wire  								M_AXI_RREADY			 
	);
         
	  function integer clogb2 (input integer bit_depth);              
	  begin                                                           
	    for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                   
	      bit_depth = bit_depth >> 1;                                 
	    end                                                           
	  endfunction                                                     

	 localparam integer C_TRANSACTIONS_NUM = clogb2(C_M_AXI_BURST_LEN-1);	
	 localparam integer BURST_SIZE = C_M_AXI_BURST_LEN * C_M_AXI_DATA_WIDTH/8;	
	// AXI4LITE signals
	//AXI4 internal temp signals
//write

	reg 	[C_M_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr	;
	reg  						 		axi_awvalid	;
	wire 	[C_M_AXI_DATA_WIDTH-1 : 0] 	axi_wdata	;
	reg  								axi_wlast	;
	reg  								axi_wvalid	;
//read	
	reg 	[C_M_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr	;
	reg  								axi_arvalid	;
	reg  								axi_rready	;
	
//	wire [C_TRANSACTIONS_NUM+2 : 0] 	burst_size_bytes;

	
	assign M_AXI_AWID		= C_M_AXI_ID;
	assign M_AXI_AWADDR		= axi_awaddr;
	assign M_AXI_AWLEN		= C_M_AXI_BURST_LEN - 1;
	assign M_AXI_AWSIZE		= clogb2((C_M_AXI_DATA_WIDTH/8)-1);
	assign M_AXI_AWBURST	= 2'b01;
	assign M_AXI_AWLOCK		= 1'b0;
	assign M_AXI_AWCACHE	= 4'b0010;
	assign M_AXI_AWPROT		= 3'h0;
	assign M_AXI_AWQOS		= 4'h0;
	assign M_AXI_AWVALID	= axi_awvalid;
	assign M_AXI_WDATA		= axi_wdata;
	assign M_AXI_WSTRB		= {(C_M_AXI_DATA_WIDTH/8){1'b1}};
	assign M_AXI_WLAST		= axi_wlast;
	assign M_AXI_WVALID		= axi_wvalid;
	assign M_AXI_BREADY		= axi_bready;
		
	assign M_AXI_ARID		= C_M_AXI_ID;
	assign M_AXI_ARADDR		= axi_araddr;
	assign M_AXI_ARLEN		= C_M_AXI_BURST_LEN - 1;
	assign M_AXI_ARSIZE		= clogb2((C_M_AXI_DATA_WIDTH/8)-1);
	assign M_AXI_ARBURST	= 2'b01;
	assign M_AXI_ARLOCK		= 1'b0;
	assign M_AXI_ARCACHE	= 4'b0010;
	assign M_AXI_ARPROT		= 3'h0;
	assign M_AXI_ARQOS		= 4'h0;
	assign M_AXI_ARVALID	= axi_arvalid;
	assign M_AXI_RREADY		= axi_rready;

	
   	reg [7 :0 ]                      w_word_cnt   ; 
    reg [C_M_AXI_ADDR_WIDTH-1 : 0]   WR_BASE_ADDR  ;
    reg [C_M_AXI_ADDR_WIDTH-1 : 0]   RD_BASE_ADDR  ;
	reg [C_M_AXI_ADDR_WIDTH-1 : 0]   wr_data_cnt   ;
	reg [C_M_AXI_ADDR_WIDTH-1 : 0]   rd_data_cnt   ;  
    reg                              w_cycle_flag  ;
    reg                              r_cycle_flag ;
    reg                              read_data_flag;
    
	wire w_next = (axi_wvalid && M_AXI_WREADY);
	wire r_next = (M_AXI_RVALID && axi_rready);

    
	assign pkg_wr_en      =   w_next;   
	assign pkg_wr_last    =  (w_next && wr_data_cnt==pkg_wr_size-1);//user logic for addr update	
	assign axi_wdata      =  pkg_wr_data;
	
	assign pkg_rd_en      =  r_next;
	assign pkg_rd_last    =  (r_next && rd_data_cnt==pkg_rd_size-1);//user logic for addr update
	assign pkg_rd_data    =  M_AXI_RDATA;

//----------------------------------------------------------------------------	
//AXI4 FULL Write
//AXI4 data is ready for axi master write to slave	

reg w_fdma_locked;

always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		w_fdma_locked <= 1'b0;
	else if(w_fdma_locked==1'b0 && pkg_wr_areq== 1'b1) begin
		w_fdma_locked <= 1'b1; 		
	end                            
	else if(pkg_wr_last == 1'b1)    
		w_fdma_locked <= 1'b0;	
		
//AXI4 write burst lenth busrt addr --------------------------------------------
always @(posedge M_AXI_ACLK)
    if(M_AXI_ARESETN == 1'b0)
        axi_awaddr <= 'd0;
    else if(w_fdma_locked==1'b0 && pkg_wr_areq)    
        axi_awaddr <= pkg_wr_addr;
    else if(axi_awvalid == 1'b1 && M_AXI_AWREADY == 1'b1)
        axi_awaddr <= axi_awaddr + BURST_SIZE ;  	
                	
//AXI4 write cycle flag---------------------------------------------
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		w_cycle_flag <= 1'b0;
	else if(w_cycle_flag == 1'b0 && w_fdma_locked)
		w_cycle_flag <= 1'b1;                             
	else if(w_cycle_flag == 1'b1 && axi_wlast == 1'b1)    
		w_cycle_flag <= 1'b0;

//AXI4 write addr valid---------------------------------------------
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		axi_awvalid<= 1'b0;
	else if(w_cycle_flag == 1'b1 && M_AXI_AWREADY==1'b1)
		axi_awvalid <= 1'b0;
	else if(w_cycle_flag  == 1'b0 && w_fdma_locked == 1'b1)
		axi_awvalid <= 1'b1;     
		
//AXI4 write data---------------------------------------------------		
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN  == 1'b0)
		axi_wvalid <= 1'b0;
	else if(w_cycle_flag  == 1'b0 && w_fdma_locked == 1'b1)
		axi_wvalid <= 1'b1;
	else if(w_cycle_flag == 1'b1 && axi_wlast == 1'b1)
		axi_wvalid <= 1'b0;//

//AXI4 write data user counter for burst lenth----------------------
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		w_word_cnt <= 'd0;
	else if(w_word_cnt==C_M_AXI_BURST_LEN)
		w_word_cnt <= 'd0;
	else if(w_next)
		w_word_cnt <= w_word_cnt + 1'b1;            
	else 
		w_word_cnt <= w_word_cnt ;

//AXI4 write data user counter for frame space lenth----------------
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		wr_data_cnt <= 'd0;
	else if(w_next && wr_data_cnt== pkg_wr_size-1)
		wr_data_cnt <= 'd0;
	else if(w_next)
		wr_data_cnt <= wr_data_cnt + 1'b1;	
	else
		wr_data_cnt <= wr_data_cnt;
			
//AXI4 write data last data----------------------------------------- 
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		axi_wlast <= 1'b0;
	else if(w_word_cnt == M_AXI_AWLEN-1)
		axi_wlast <= 1'b1;
	else
		axi_wlast <= 1'b0;
 
assign  axi_bready = 1'b1;     		
		
//----------------------------------------------------------------------------	
//AXI4 FULL Read----------------------------------------- 	
reg r_fdma_locked;
    
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		r_fdma_locked <= 1'b0;
	else if(r_fdma_locked==1'b0 && pkg_rd_areq==1'b1) begin
		r_fdma_locked <= 1'b1; 		
	end                            
	else if(pkg_rd_last == 1'b1)    
		r_fdma_locked <= 1'b0;			
//AXI4 read addr read addr burst-------------------------
always @(posedge M_AXI_ACLK)
    if(M_AXI_ARESETN == 1'b0)
        axi_araddr <='d0;
    else if(r_fdma_locked==1'b0 && pkg_rd_areq==1'b1)//pkg_rd_ardy pkg read addr is ready 
        axi_araddr <= pkg_rd_addr;
     else if(axi_arvalid == 1'b1 && M_AXI_ARREADY == 1'b1)
        axi_araddr <= axi_araddr + BURST_SIZE;	
									        
//AXI4 r_cycle_flag------------------------------------- 	
always @(posedge M_AXI_ACLK)
		if(M_AXI_ARESETN == 0)
			r_cycle_flag <= 1'b0;
	   	else if(r_fdma_locked &&  M_AXI_ARREADY && axi_arvalid ) 
            r_cycle_flag <= 1'b0;
		else if(r_fdma_locked && read_data_flag == 1'b0 )//pkg_rd_dreq pkg request to read 
			r_cycle_flag <= 1'b1;			


//AXI4 read addr valid-----------------------------------
always @(posedge M_AXI_ACLK)
		if(M_AXI_ARESETN == 1'b0)
			axi_arvalid <= 1'b0;
		else if(r_cycle_flag && axi_arvalid && M_AXI_ARREADY ) 
            axi_arvalid <= 1'b0;
		else if(r_cycle_flag && axi_arvalid == 1'b0)
			axi_arvalid <= 1'b1;

				
//AXI4 read_data_flag ready for read data----------------
always @(posedge M_AXI_ACLK)
		if(M_AXI_ARESETN == 1'b0)
			read_data_flag <= 1'b0;
		else if(r_cycle_flag && axi_arvalid && M_AXI_ARREADY)
		begin
			read_data_flag <= 1'b1;
			axi_rready     <= 1'b1;
	    end
		else if(read_data_flag && r_next && M_AXI_RLAST)
		begin
			read_data_flag <= 1'b0;
			axi_rready     <= 1'b0;
	    end

	
//AXI4 data user counter for frame space lenth-----------	
always @(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		rd_data_cnt <= 'd0;
	else if(r_next && rd_data_cnt== pkg_rd_size-1)
		rd_data_cnt <= 'd0;
	else if(r_next)
		rd_data_cnt <= rd_data_cnt + 1'b1;	
	else
		rd_data_cnt <= rd_data_cnt;	
		              

			   
endmodule



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值