根据波形手撕AXI4-FULL协议(端口带注释)

本文主要目的是

1.手撕简易AXI4-FULL协议;

2. 通过反复查看spec加深对spec的理解,学习AXI4协议各个端口信号的意义,以及怎么定义该信号的拉高和拉低;

3.进一步学习xilinx的vivado中的AXI4-FULL IP核,逐行阅读代码,从而完全掌握AXI4-FULL协议的原理和实现过程(在下一篇博文会通过展现代码和注释来进一步解读AXI4-FULL协议)。

下面是rtl和tb文件代码展示:

分别为top_axi_full、axi_full_master、axi_full_slave、tb_top_axi_full

module top_axi_full(

	input	clk	,
	input	rst_n	,
	input	txn		


);


parameter  			C_M_TARGET_SLAVE_BASE_ADDR	= 32'h40000000	;
parameter integer 	C_M_AXI_BURST_LEN			= 16			;
parameter integer 	C_M_AXI_ID_WIDTH			= 1				;
parameter integer 	C_M_AXI_ADDR_WIDTH			= 32			;
parameter integer 	C_M_AXI_DATA_WIDTH			= 32			;
parameter integer 	C_M_AXI_AWUSER_WIDTH		= 0				;
parameter integer 	C_M_AXI_ARUSER_WIDTH		= 0				;
parameter integer 	C_M_AXI_WUSER_WIDTH			= 0				;
parameter integer 	C_M_AXI_RUSER_WIDTH			= 0				;
parameter integer 	C_M_AXI_BUSER_WIDTH			= 0				;

parameter integer C_S_AXI_ID_WIDTH		= 1					;
parameter integer C_S_AXI_DATA_WIDTH	= 32				;
parameter integer C_S_AXI_ADDR_WIDTH	= 16				;
parameter integer C_S_AXI_AWUSER_WIDTH	= 0					;
parameter integer C_S_AXI_ARUSER_WIDTH	= 0					;
parameter integer C_S_AXI_WUSER_WIDTH	= 0					;
parameter integer C_S_AXI_RUSER_WIDTH	= 0					;
parameter integer C_S_AXI_BUSER_WIDTH	= 0                 ;


wire  								INIT_AXI_TXN		;
assign								INIT_AXI_TXN	=	txn;

wire  								TXN_DONE			;
wire  								ERROR				;
                                                        
//全局信号                                              
wire  								M_AXI_ACLK			;
assign								M_AXI_ACLK		=	clk;
wire 								M_AXI_ARESETN		;
assign								M_AXI_ARESETN	=	rst_n;

//写地址通道		
wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_AWID			;	//写地址ID标签。地址组的识别标签。
//outstanding超前传输,带id连续传输写地址和写数据,写完数据第一个id回复后,再传输第二个地址的写数据。造成前向死锁
//out of order无序传输,带多个id写,不同id回复,如id=2先写,id=1后写,回复的可能是id=1的控制信号。造成反向死锁
wire [C_M_AXI_ADDR_WIDTH-1 : 0] 	M_AXI_AWADDR		;	//写地址。写突发事务中第一个传输的地址
wire [7 : 0] 						M_AXI_AWLEN			;	//突发长度。一个突发中传输的确切数量。此信息决定了与该地址关联的数据传输数
wire [2 : 0] 						M_AXI_AWSIZE		;	//突发大小。突发中每个传输的大小
wire [1 : 0] 						M_AXI_AWBURST		;	//突发类型。突发类型和大小信息,确定如何计算突发中每个传输的地址
wire  								M_AXI_AWLOCK		;	//*锁类型。AXI4没有
wire [3 : 0] 						M_AXI_AWCACHE		;	//*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
wire [2 : 0] 						M_AXI_AWPROT		;	//*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
wire [3 : 0] 						M_AXI_AWQOS			;	//*服务质量。为每个写事务发送的QoS标识符
//output 	wire [3 : 0] 					M_AXI_AWREGION		,	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
wire [C_M_AXI_AWUSER_WIDTH-1 : 0] 	M_AXI_AWUSER		;	//*用户信号。在写地址通道中,可选的用户自定义信号。
wire  								M_AXI_AWVALID		;	//写地址有效。该信号表示信道正在发出有效的写地址和控制信息
wire  								M_AXI_AWREADY		;	//写地址准备。该信号表示从设备已准备好接受地址和相关的控制信号

//写数据通道
//output 	wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WID			,	//写数据ID标签。写数据传输的识别标签。AXI3才有		
wire [C_M_AXI_DATA_WIDTH-1 : 0] 	M_AXI_WDATA			;	//写数据
wire [C_M_AXI_DATA_WIDTH/8-1 : 0] 	M_AXI_WSTRB			;	//*写入strobes。此信号指示哪些字节道保存了有效的数据。写数据总线的每8位都有一个写频闪位。
wire  								M_AXI_WLAST			;	//最后写入。该信号表示写突发中的最后一次传输
wire [C_M_AXI_WUSER_WIDTH-1 : 0] 	M_AXI_WUSER			;	//*用户信号。在写数据通道中,可选的用户自定义信号。
wire  								M_AXI_WVALID		;	//写数据有效。该信号表示有效的写入数据和strobes(M_AXI_WSTRB)可用。
wire  								M_AXI_WREADY		;	//写数据准备。该信号表示从设备已准备好接受写入数据

//写响应通道
wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_BID			;	//写响应ID标签。写响应的识别标签。
wire [1 : 0] 						M_AXI_BRESP			;	//写响应。该信号表示写事务的状态。
wire [C_M_AXI_BUSER_WIDTH-1 : 0] 	M_AXI_BUSER			;	//*用户信号。在写响应通道中,可选的用户自定义信号。
wire  								M_AXI_BVALID		;	//写响应有效。该信号表示信道正在发出有效的写响应信号
wire  								M_AXI_BREADY		;	//写响应准备。该信号表示主设备可以接受写响应。

//读地址通道
wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_ARID			;	//读地址ID。读地址组的识别标签。
wire [C_M_AXI_ADDR_WIDTH-1 : 0] 	M_AXI_ARADDR		;	//读地址。读突发事务中第一个传输的地址
wire [7 : 0] 						M_AXI_ARLEN			;	//突发长度。一个突发中传输的确切数量。此信息决定了与该地址关联的数据传输数
wire [2 : 0] 						M_AXI_ARSIZE		;   //突发大小。突发中每个传输的大小
wire [1 : 0] 						M_AXI_ARBURST		;   //突发类型。突发类型和大小信息,确定如何计算突发中每个传输的地址
wire  								M_AXI_ARLOCK		;	//*锁类型。AXI4没有
wire [3 : 0] 						M_AXI_ARCACHE		;   //*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
wire [2 : 0] 						M_AXI_ARPROT		;   //*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
wire [3 : 0] 						M_AXI_ARQOS			;   //*服务质量。为每个读事务发送的QoS标识符
//output 	wire [3 : 0] 					M_AXI_ARREGION		,	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
wire [C_M_AXI_ARUSER_WIDTH-1 : 0] 	M_AXI_ARUSER		;   //*用户信号。在读地址通道中,可选的用户自定义信号。
wire  								M_AXI_ARVALID		;   //读地址有效。该信号表示信道正在发出有效的读地址和控制信息
wire  								M_AXI_ARREADY		;   //读地址准备。该信号表示从设备已准备好接受地址和相关的控制信号
                                                                    
//读数据通道
wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_RID			;	//读数据ID标签。读数据传输的识别标签。		
wire [C_M_AXI_DATA_WIDTH-1 : 0] 	M_AXI_RDATA			;   //读数据
wire [1 : 0] 						M_AXI_RRESP			;   //读响应。该信号表示读传输的状态。
wire  								M_AXI_RLAST			;   //最后读取。该信号表示读突发中的最后一次传输
wire [C_M_AXI_RUSER_WIDTH-1 : 0] 	M_AXI_RUSER			;   //*用户信号。在读数据通道中,可选的用户自定义信号。
wire  								M_AXI_RVALID		;   //读数据有效。该信号表示信道正在发送所需的读取数据。
wire  								M_AXI_RREADY        ;   //读数据准备。该信号表示主设备可以接受读取的数据和响应信息

axi_full_master#
	(

		.C_M_TARGET_SLAVE_BASE_ADDR	(C_M_TARGET_SLAVE_BASE_ADDR	),
		.C_M_AXI_BURST_LEN		  	(C_M_AXI_BURST_LEN		  	),
		.C_M_AXI_ID_WIDTH		  	(C_M_AXI_ID_WIDTH		  	),
		.C_M_AXI_ADDR_WIDTH		  	(C_M_AXI_ADDR_WIDTH		  	),
		.C_M_AXI_DATA_WIDTH		  	(C_M_AXI_DATA_WIDTH		  	),
		.C_M_AXI_AWUSER_WIDTH	  	(C_M_AXI_AWUSER_WIDTH	  	),
		.C_M_AXI_ARUSER_WIDTH	  	(C_M_AXI_ARUSER_WIDTH	  	),
		.C_M_AXI_WUSER_WIDTH	  	(C_M_AXI_WUSER_WIDTH	  	),
		.C_M_AXI_RUSER_WIDTH	  	(C_M_AXI_RUSER_WIDTH	  	),
		.C_M_AXI_BUSER_WIDTH	  	(C_M_AXI_BUSER_WIDTH	  	)
	)
	u_axi_full_master(

		.INIT_AXI_TXN		(INIT_AXI_TXN		),
		.TXN_DONE			(TXN_DONE			),
		.ERROR				(ERROR				),

		.M_AXI_ACLK			(M_AXI_ACLK			),
		.M_AXI_ARESETN		(M_AXI_ARESETN		),

		.M_AXI_AWID			(M_AXI_AWID			),	//写地址ID标签。地址组的识别标签。

		.M_AXI_AWADDR		(M_AXI_AWADDR		),	//写地址。写突发事务中第一个传输的地址
		.M_AXI_AWLEN		(M_AXI_AWLEN		),	//突发长度。一个突发中传输的确切数量。此信息决定了与该地址关联的数据传输数
		.M_AXI_AWSIZE		(M_AXI_AWSIZE		),	//突发大小。突发中每个传输的大小
		.M_AXI_AWBURST		(M_AXI_AWBURST		),	//突发类型。突发类型和大小信息,确定如何计算突发中每个传输的地址

		.M_AXI_AWCACHE		(M_AXI_AWCACHE		),	//*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
		.M_AXI_AWPROT		(M_AXI_AWPROT		),	//*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
		.M_AXI_AWQOS		(M_AXI_AWQOS		),	//*服务质量。为每个写事务发送的QoS标识符
		//.M_AXI_AWREGION	(M_AXI_AWREGION		),	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
		.M_AXI_AWUSER		(M_AXI_AWUSER		),	//*用户信号。在写地址通道中,可选的用户自定义信号。
		.M_AXI_AWVALID		(M_AXI_AWVALID		),	//写地址有效。该信号表示信道正在发出有效的写地址和控制信息
		.M_AXI_AWREADY		(M_AXI_AWREADY		),	//写地址准备。该信号表示从设备已准备好接受地址和相关的控制信号

		//.M_AXI_WID			(M_AXI_WID			),	//写数据ID标签。写数据传输的识别标签。AXI3才有		
		.M_AXI_WDATA		(M_AXI_WDATA		)	,	//写数据
		.M_AXI_WSTRB		(M_AXI_WSTRB		)	,	//*写入strobes。此信号指示哪些字节道保存了有效的数据。写数据总线的每8位都有一个写频闪位。
		.M_AXI_WLAST		(M_AXI_WLAST		)	,	//最后写入。该信号表示写突发中的最后一次传输
		.M_AXI_WUSER		(M_AXI_WUSER		)	,	//*用户信号。在写数据通道中,可选的用户自定义信号。
		.M_AXI_WVALID		(M_AXI_WVALID		),	//写数据有效。该信号表示有效的写入数据和strobes(M_AXI_WSTRB)可用。
		.M_AXI_WREADY		(M_AXI_WREADY		),	//写数据准备。该信号表示从设备已准备好接受写入数据

		.M_AXI_BID			(M_AXI_BID			),	//写响应ID标签。写响应的识别标签。
		.M_AXI_BRESP		(M_AXI_BRESP		)	,	//写响应。该信号表示写事务的状态。
		.M_AXI_BUSER		(M_AXI_BUSER		)	,	//*用户信号。在写响应通道中,可选的用户自定义信号。
		.M_AXI_BVALID		(M_AXI_BVALID		),	//写响应有效。该信号表示信道正在发出有效的写响应信号
		.M_AXI_BREADY		(M_AXI_BREADY		),	//写响应准备。该信号表示主设备可以接受写响应。

		.M_AXI_ARID			(M_AXI_ARID			),	//读地址ID。读地址组的识别标签。
		.M_AXI_ARADDR		(M_AXI_ARADDR		),	//读地址。读突发事务中第一个传输的地址
		.M_AXI_ARLEN		(M_AXI_ARLEN		),	//突发长度。一个突发中传输的确切数量。此信息决定了与该地址关联的数据传输数
		.M_AXI_ARSIZE		(M_AXI_ARSIZE		),   //突发大小。突发中每个传输的大小
		.M_AXI_ARBURST		(M_AXI_ARBURST		),   //突发类型。突发类型和大小信息,确定如何计算突发中每个传输的地址

		.M_AXI_ARCACHE		(M_AXI_ARCACHE		),   //*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
		.M_AXI_ARPROT		(M_AXI_ARPROT		),   //*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
		.M_AXI_ARQOS		(M_AXI_ARQOS		),   //*服务质量。为每个读事务发送的QoS标识符
		//.M_AXI_ARREGION		(M_AXI_ARREGION		),	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
		.M_AXI_ARUSER		(M_AXI_ARUSER		),   //*用户信号。在读地址通道中,可选的用户自定义信号。
		.M_AXI_ARVALID		(M_AXI_ARVALID		),   //读地址有效。该信号表示信道正在发出有效的读地址和控制信息
		.M_AXI_ARREADY		(M_AXI_ARREADY		),   //读地址准备。该信号表示从设备已准备好接受地址和相关的控制信号

		.M_AXI_RID			(M_AXI_RID			),	//读数据ID标签。读数据传输的识别标签。		
		.M_AXI_RDATA		(M_AXI_RDATA		)	,   //读数据
		.M_AXI_RRESP		(M_AXI_RRESP		)	,   //读响应。该信号表示读传输的状态。
		.M_AXI_RLAST		(M_AXI_RLAST		)	,   //最后读取。该信号表示读突发中的最后一次传输
		.M_AXI_RUSER		(M_AXI_RUSER		)	,   //*用户信号。在读数据通道中,可选的用户自定义信号。
		.M_AXI_RVALID		(M_AXI_RVALID		),   //读数据有效。该信号表示信道正在发送所需的读取数据。
		.M_AXI_RREADY       (M_AXI_RREADY       )     //读数据准备。该信号表示主设备可以接受读取的数据和响应信息
);

axi_full_slave #
	(

		.C_S_AXI_ID_WIDTH		(C_S_AXI_ID_WIDTH		),
		.C_S_AXI_DATA_WIDTH		(C_S_AXI_DATA_WIDTH		),
		.C_S_AXI_ADDR_WIDTH		(C_S_AXI_ADDR_WIDTH		),
		.C_S_AXI_AWUSER_WIDTH	(C_S_AXI_AWUSER_WIDTH	),
		.C_S_AXI_ARUSER_WIDTH	(C_S_AXI_ARUSER_WIDTH	),
		.C_S_AXI_WUSER_WIDTH	(C_S_AXI_WUSER_WIDTH	),
		.C_S_AXI_RUSER_WIDTH	(C_S_AXI_RUSER_WIDTH	),
		.C_S_AXI_BUSER_WIDTH	(C_S_AXI_BUSER_WIDTH	)
	)
	u_axi_full_slave(
		.S_AXI_ACLK			(M_AXI_ACLK),
		.S_AXI_ARESETN		(M_AXI_ARESETN),
		.S_AXI_AWID			(M_AXI_AWID),
		.S_AXI_AWADDR		(M_AXI_AWADDR		),
		.S_AXI_AWLEN		(M_AXI_AWLEN		),
		.S_AXI_AWSIZE		(M_AXI_AWSIZE		),
		.S_AXI_AWBURST		(M_AXI_AWBURST		),
		.S_AXI_AWLOCK		(M_AXI_AWLOCK		),
		.S_AXI_AWCACHE		(M_AXI_AWCACHE		),
		.S_AXI_AWPROT		(M_AXI_AWPROT		),
		.S_AXI_AWQOS		(M_AXI_AWQOS		)	,
		.S_AXI_AWREGION		(4'b0),
		.S_AXI_AWUSER		(M_AXI_AWUSER		),
		.S_AXI_AWVALID		(M_AXI_AWVALID		),
		.S_AXI_AWREADY		(M_AXI_AWREADY		),
		.S_AXI_WDATA		(M_AXI_WDATA	)	,
		.S_AXI_WSTRB		(M_AXI_WSTRB	)	,
		.S_AXI_WLAST		(M_AXI_WLAST	)	,
		.S_AXI_WUSER		(M_AXI_WUSER	)	,
		.S_AXI_WVALID		(M_AXI_WVALID	),
		.S_AXI_WREADY		(M_AXI_WREADY	),
		.S_AXI_BID			(M_AXI_BID			),
		.S_AXI_BRESP		(M_AXI_BRESP		)	,
		.S_AXI_BUSER		(M_AXI_BUSER		)	,
		.S_AXI_BVALID		(M_AXI_BVALID		),
		.S_AXI_BREADY		(M_AXI_BREADY		),
		.S_AXI_ARID			(M_AXI_ARID			),
		.S_AXI_ARADDR		(M_AXI_ARADDR		),
		.S_AXI_ARLEN		(M_AXI_ARLEN		)	,
		.S_AXI_ARSIZE		(M_AXI_ARSIZE		),
		.S_AXI_ARBURST		(M_AXI_ARBURST		),
		.S_AXI_ARLOCK		(M_AXI_ARLOCK		),
		.S_AXI_ARCACHE		(M_AXI_ARCACHE		),
		.S_AXI_ARPROT		(M_AXI_ARPROT		),
		.S_AXI_ARQOS		(M_AXI_ARQOS		)	,
		.S_AXI_ARREGION		(4'b0),
		.S_AXI_ARUSER		(M_AXI_ARUSER	),
		.S_AXI_ARVALID		(M_AXI_ARVALID	),
		.S_AXI_ARREADY		(M_AXI_ARREADY	),
		.S_AXI_RID			(M_AXI_RID			),
		.S_AXI_RDATA		(M_AXI_RDATA		)	,
		.S_AXI_RRESP		(M_AXI_RRESP		)	,
		.S_AXI_RLAST		(M_AXI_RLAST		)	,
		.S_AXI_RUSER		(M_AXI_RUSER		)	,
		.S_AXI_RVALID		(M_AXI_RVALID		),
		.S_AXI_RREADY		(M_AXI_RREADY      )
	);


endmodule
module axi_full_master#
	(

		parameter  			C_M_TARGET_SLAVE_BASE_ADDR	= 32'h40000000	,
		parameter integer 	C_M_AXI_BURST_LEN			= 16			,
		parameter integer 	C_M_AXI_ID_WIDTH			= 1				,
		parameter integer 	C_M_AXI_ADDR_WIDTH			= 32			,
		parameter integer 	C_M_AXI_DATA_WIDTH			= 32			,
		parameter integer 	C_M_AXI_AWUSER_WIDTH		= 0				,
		parameter integer 	C_M_AXI_ARUSER_WIDTH		= 0				,
		parameter integer 	C_M_AXI_WUSER_WIDTH			= 0				,
		parameter integer 	C_M_AXI_RUSER_WIDTH			= 0				,
		parameter integer 	C_M_AXI_BUSER_WIDTH			= 0
	)
	(

		input 	wire  								INIT_AXI_TXN		,
		output 	wire  								TXN_DONE			,
		output 	reg  								ERROR				,
		
		//全局信号
		input 	wire  								M_AXI_ACLK			,
		input 	wire  								M_AXI_ARESETN		,
		
		//写地址通道		
		output 	wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_AWID			,	//写地址ID标签。地址组的识别标签。
		//outstanding超前传输,带id连续传输写地址和写数据,写完数据第一个id回复后,再传输第二个地址的写数据。造成前向死锁
		//out of order无序传输,带多个id写,不同id回复,如id=2先写,id=1后写,回复的可能是id=1的控制信号。造成反向死锁
		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		,	//*锁类型。AXI4没有
		output 	wire [3 : 0] 						M_AXI_AWCACHE		,	//*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
		output 	wire [2 : 0] 						M_AXI_AWPROT		,	//*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
		output 	wire [3 : 0] 						M_AXI_AWQOS			,	//*服务质量。为每个写事务发送的QoS标识符
		//output 	wire [3 : 0] 					M_AXI_AWREGION		,	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
		output 	wire [C_M_AXI_AWUSER_WIDTH-1 : 0] 	M_AXI_AWUSER		,	//*用户信号。在写地址通道中,可选的用户自定义信号。
		output 	wire  								M_AXI_AWVALID		,	//写地址有效。该信号表示信道正在发出有效的写地址和控制信息。当主机驱动有效的地址和控制信息时拉高,然后保持,直到检测到M_AXI_AWREADY为高电平拉低
																			//The master can assert the AWVALID signal only when it drives valid address and control information. When asserted, AWVALID must remain 
																			//asserted until the rising clock edge after the slave asserts AWREADY.
																			
		input 	wire  								M_AXI_AWREADY		,	//写地址准备。该信号表示从设备已准备好接受地址和相关的控制信号。规格书推荐默认为高电平,当从机的S_AXI_AWREADY拉高,必须要有有效的地址已提供
																			//The default state of AWREADY can be either HIGH or LOW. This specification recommends a default state of 
																			//HIGH. When AWREADY is HIGH the slave must be able to accept any valid address that is presented to it.

		//写数据通道
		//output 	wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WID			,	//写数据ID标签。写数据传输的识别标签。AXI3才有		
		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			,	//写入strobes。此信号指示哪些字节道保存了有效的数据。写数据总线的每8位都有一个写频闪位。
		output 	wire  								M_AXI_WLAST			,	//最后写入。该信号表示写数据通道正在传输最后一个写数据。当传输最后一个写数据时拉高一个时钟周期。
																			//The master must assert the WLAST signal while it is driving the final write transfer in the burst.
																			
		output 	wire [C_M_AXI_WUSER_WIDTH-1 : 0] 	M_AXI_WUSER			,	//*用户信号。在写数据通道中,可选的用户自定义信号。
		
		output 	wire  								M_AXI_WVALID		,	//写数据有效。该信号表示有效的写入数据和strobes(M_AXI_WSTRB)可用。当主机驱动有效的写数据时拉高,然后保持,直到检测到S_AXI_WREADY为高电平拉低
																			//During a write burst, the master can assert the WVALID signal only when it drives valid write data. When asserted, 
																			//WVALID must remain asserted until the rising clock edge after the slave asserts WREADY.
																			
		input 	wire  								M_AXI_WREADY		,	//写数据准备。该信号表示从设备已准备好接受写入数据。规格书推荐默认为高电平,前提从机必须在一个周期内接收有效的写数据。
																			//The default state of WREADY can be HIGH, but only if the slave can always accept write data in a single cycle.
		
		//写响应通道
		input 	wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_BID			,	//写响应ID标签。写响应的识别标签。
		input 	wire [1 : 0] 						M_AXI_BRESP			,	//写响应。该信号表示写事务的状态。
		input 	wire [C_M_AXI_BUSER_WIDTH-1 : 0] 	M_AXI_BUSER			,	//*用户信号。在写响应通道中,可选的用户自定义信号。
		input 	wire  								M_AXI_BVALID		,	//写响应有效。该信号表示信道正在发出有效的写响应信号。当从机驱动有效的写响应时拉高,然后保持,直到检测到S_AXI_BREADY为高电平拉低
																			//The slave can assert the BVALID signal only when it drives a valid write response. When asserted, BVALID must 
																			//remain asserted until the rising clock edge after the master asserts BREADY.
		output 	wire  								M_AXI_BREADY		,	//写响应准备。该信号表示主设备可以接受写响应。规格书推荐默认为高电平,前提主机必须在一个周期内接收有效的写响应。
																			//The default state of BREADY can be HIGH, but only if the master can always accept a write response in a single cycle.
		
		//读地址通道
		output 	wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_ARID			,	//读地址ID。读地址组的识别标签。
		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		,	//*锁类型。AXI4没有
		output 	wire [3 : 0] 						M_AXI_ARCACHE		,   //*存储器类型。此信号指示如何通过系统进行事务。Device Non-bufferable,还有很多模式
		output 	wire [2 : 0] 						M_AXI_ARPROT		,   //*保护类型。该信号指示事务的权限和安全级别,以及该事务是数据访问还是指令访问
		output 	wire [3 : 0] 						M_AXI_ARQOS			,   //*服务质量。为每个读事务发送的QoS标识符
		//output 	wire [3 : 0] 					M_AXI_ARREGION		,	//*区域标识符。允许从机上的单个物理接口用于多个逻辑接口。
		output 	wire [C_M_AXI_ARUSER_WIDTH-1 : 0] 	M_AXI_ARUSER		,   //*用户信号。在读地址通道中,可选的用户自定义信号。
		output 	wire  								M_AXI_ARVALID		,   //读地址有效。该信号表示信道正在发出有效的读地址和控制信息。当主机驱动有效的地址和控制信息时拉高,然后保持,直到检测到S_AXI_ARREADY为高电平拉低
																			//The master can assert the ARVALID signal only when it drives valid address and control information. When 
																			//asserted, ARVALID must remain asserted until the rising clock edge after the slave asserts the ARREADY signal.
																			
		input 	wire  								M_AXI_ARREADY		,   //读地址准备。该信号表示从设备已准备好接受地址和相关的控制信号。规格书推荐默认为高电平,当从机的S_AXI_ARREADY拉高,必须要有有效的地址已提供
																			//The default state of ARREADY can be either HIGH or LOW. This specification recommends a default state of HIGH. 
																			//If ARREADY is HIGH then the slave must be able to accept any valid address that is presented to it.
		
		                                                                    
		//读数据通道
		input 	wire [C_M_AXI_ID_WIDTH-1 : 0] 		M_AXI_RID			,	//读数据ID标签。读数据传输的识别标签。		
		input 	wire [C_M_AXI_DATA_WIDTH-1 : 0] 	M_AXI_RDATA			,   //读数据
		input 	wire [1 : 0] 						M_AXI_RRESP			,   //读响应。该信号表示读传输的状态。
		input 	wire  								M_AXI_RLAST			,   //最后读取。该信号表示读突发中的最后一次传输。当传输最后一个读数据时拉高一个时钟周期。
																			//The slave must assert the RLAST signal when it is driving the final read transfer in the burst.
																			
		input 	wire [C_M_AXI_RUSER_WIDTH-1 : 0] 	M_AXI_RUSER			,   //*用户信号。在读数据通道中,可选的用户自定义信号。
		
		input 	wire  								M_AXI_RVALID		,   //读数据有效。该信号表示信道正在发送所需的读取数据。当主机驱动有效的读数据时拉高,然后保持,直到检测到S_AXI_WREADY为高电平拉低
																			//The slave can assert the RVALID signal only when it drives valid read data. When asserted, RVALID must remain 
																			//asserted until the rising clock edge after the master asserts RREADY. Even if a slave has only one source of read 
																			//data, it must assert the RVALID signal only in response to a request for data.
																			
		output 	wire  								M_AXI_RREADY            //读数据准备。该信号表示主设备可以接受读取的数据和响应信息。规格书推荐默认为高电平,前提主机必须立即接收有效的读数据。assign语句?
																			//The master interface uses the RREADY signal to indicate that it accepts the data. The default state of RREADY
																			//can be HIGH, but only if the master is able to accept read data immediately, whenever it starts a read transaction.
);

/*******************************function*******************************/
function integer clog2(input integer number);
	for(clog2 = 0; number > 0; clog2 = clog2 + 1)
		number = number >> 1;
endfunction


/*********************************reg*********************************/
reg									r_txn_ff1								;
reg									r_txn_ff2								;
reg	[C_M_AXI_ADDR_WIDTH-1 : 0]		r_m_awaddr								;
reg									r_m_awvalid								;
reg	[C_M_AXI_DATA_WIDTH-1 : 0]		r_m_wdata								;
reg									r_m_wlast								;
reg									r_m_wvalid								;
reg									r_m_bready								;
reg									r_error									;
reg	[C_M_AXI_ADDR_WIDTH-1 : 0]		r_m_araddr								;
reg									r_m_arvalid								;
reg									r_m_rready								;
reg									r_read_ff1								;
reg									r_read_ff2								;


//写入数据计数器
reg [clog2(C_M_AXI_BURST_LEN - 1) : 0]	r_m_wdata_cnt					;


/********************************wire********************************/
wire							w_m_read_en								;


/******************************parameter******************************/
//写地址递增
parameter AWADDR_PLUS = C_M_AXI_BURST_LEN * (C_M_AXI_ADDR_WIDTH / 8);

/*********************************port*********************************/


/*******************************machine*******************************/


/*****************************component*****************************/


/*******************************assign*******************************/
assign M_AXI_AWID		=	'b0											;
assign M_AXI_AWADDR		= 	r_m_awaddr									;
assign M_AXI_AWLEN		= 	C_M_AXI_BURST_LEN							;	
assign M_AXI_AWSIZE		= 	3'b010										;	
assign M_AXI_AWBURST	= 	2'b01										;	
//00为固定。在一个固定的突发中:对于突发中的每个传输,地址都是相同的。有效的字节道对于突发中的所有节拍都是常量的。
//然而,在这些字节通道中,断言了WSTRB的实际字节可以因突发中的每个节拍而有所不同。
//这种突发类型用于重复访问相同的位置,例如在加载或清空FIFO时。

//01为增加。在递增突发中,突发中每个传输的地址是前一个传输地址的增量。增量值取决于传输的大小。
//例如,大小为4字节的突发中每个传输的地址是前一个地址加上4。此突发类型用于访问正常的顺序内存。

//02为包装。包装突发类似于递增突发,只是如果达到地址上限,则地址环绕到较低的地址。
//以下限制适用于包装突发:起始地址必须与每个传输的大小对齐,突发的长度必须为2、4、8或16次传输。
//包装突发的行为是:突发使用的最低地址与要传输的数据的总大小对齐,即((突发中每个传输的大小)×(突发中的传输数量))。
//此地址被定义为包装边界。每次传输后,地址以与INCR突发相同的方式递增。
//但是,如果此增量的地址为((行边界)+(要传输数据的总大小)),则地址将环绕到行边界。
//突发中的第一个传输可以使用高于包装边界的地址,这受适用于包装突发的限制。
//这意味着地址包装了第一个地址高于包装边界的任何WRAP突发。此突发类型用于高速缓存行访问。

assign M_AXI_AWCACHE	= 	'd2											;	
assign M_AXI_AWPROT		= 	'b0											;	
assign M_AXI_AWQOS		= 	'b0											;			
assign M_AXI_AWUSER		= 	'b1											;
assign M_AXI_AWVALID	= 	r_m_awvalid									;
	
assign M_AXI_WDATA		=	r_m_wdata									;
assign M_AXI_WSTRB		=	'1											;
assign M_AXI_WLAST		=	r_m_wlast									;
assign M_AXI_WUSER		=	'b1											;
assign M_AXI_WVALID		=	r_m_wvalid									;

assign M_AXI_BREADY		=	r_m_bready									;

assign M_AXI_ARID		=	'b0											;
assign M_AXI_ARADDR	    = 	r_m_araddr									;
assign M_AXI_ARLEN		= 	C_M_AXI_BURST_LEN							;
assign M_AXI_ARSIZE	    = 	3'b010										;
assign M_AXI_ARBURST	= 	2'b01										;
assign M_AXI_ARCACHE    = 	'd2											;
assign M_AXI_ARPROT		= 	'b0											;
assign M_AXI_ARQOS	    = 	'b0											;
assign M_AXI_ARUSER		= 	'b1							                ;
assign M_AXI_ARVALID	=	r_m_arvalid                                 ;
assign w_m_read_en		=	(M_AXI_BVALID && M_AXI_BREADY && (M_AXI_BRESP == 2'b00))? 1'b1 : 1'b0;	//改成状态机可变成多次读写,条件也需要适当做修改

assign M_AXI_RREADY		=	r_m_rready									;

/*******************************always*******************************/

/*******************************写地址通道*******************************/
//同步+延迟
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)begin
		r_txn_ff1 <= 'b0;
		r_txn_ff2 <= 'b0;
	end
	else begin
		r_txn_ff1 <= INIT_AXI_TXN;
		r_txn_ff2 <= r_txn_ff1;
	end

//写地址有效,该信号表示信道正在发出有效的写地址和控制信息。
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || (M_AXI_AWVALID && M_AXI_AWREADY))
		r_m_awvalid <= 'b0;
	else if(r_txn_ff2)
		r_m_awvalid <= 1'b1;	
	else
		r_m_awvalid <= r_m_awvalid;		

//写地址
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || r_txn_ff2)	//与写地址同一拍,符合信号定义
		r_m_awaddr <= C_M_TARGET_SLAVE_BASE_ADDR;
	else if(M_AXI_AWVALID && M_AXI_AWREADY)
		r_m_awaddr <= r_m_awaddr + AWADDR_PLUS;
	else
		r_m_awaddr <= r_m_awaddr;		

/*******************************写数据通道*******************************/
//写数据有效
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || r_m_wlast)
		r_m_wvalid <= 1'b0;
	else if(r_txn_ff2)
		r_m_wvalid <= 1'b1;
	else
		r_m_wvalid <= r_m_wvalid;

//写数据
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || r_txn_ff2)
		r_m_wdata <= 'd1;
	else if(M_AXI_WVALID && M_AXI_WREADY)
		r_m_wdata <= r_m_wdata + 1'b1;
	else
		r_m_wdata <= r_m_wdata;			
		
//C_M_AXI_BURST_LEN < 2需要另作处理
//最后写入
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		r_m_wlast <= 'd0;
	//倒数第二位,即提前一拍拉高,后一拍直接拉低有效信号
	else if(r_m_wdata_cnt == C_M_AXI_BURST_LEN - 2)
		r_m_wlast <= 1'b1;	
	else
		r_m_wlast <= 1'b0;			
		
//写入数据计数器
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		r_m_wdata_cnt <= 'b0;			
	else if(r_m_wdata_cnt == C_M_AXI_BURST_LEN - 1)
		r_m_wdata_cnt <= 1'b0;
	else if(M_AXI_WVALID && M_AXI_WREADY)
		r_m_wdata_cnt <= r_m_wdata_cnt + 1'b1;
	else
		r_m_wdata_cnt <= r_m_wdata_cnt;			

/*******************************写响应通道*******************************/
//写响应准备
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		r_m_bready <= 1'b0;
	else if(M_AXI_BVALID)
		r_m_bready <= 1'b1;	
	else
		r_m_bready <= 1'b0;			

//错误
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)
		ERROR <= 1'b0;
	else if(M_AXI_BVALID && M_AXI_BREADY && (M_AXI_BRESP != 2'b00))
		ERROR <= 1'b1;	
	else
		ERROR <= ERROR;

/*******************************读地址通道*******************************/
//同步+延迟
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0)begin
		r_read_ff1 <= 'b0;
		r_read_ff2 <= 'b0;
	end
	else begin
		r_read_ff1 <= w_m_read_en;
		r_read_ff2 <= r_read_ff1;
	end

//读地址有效
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || (M_AXI_ARVALID && M_AXI_ARREADY))
		r_m_arvalid <= 'b0;
	else if(r_read_ff2)
		r_m_arvalid <= 1'b1;	
	else
		r_m_arvalid <= r_m_arvalid;		

//读地址
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || r_read_ff2)
		r_m_araddr <= C_M_TARGET_SLAVE_BASE_ADDR;
	else if(M_AXI_ARVALID && M_AXI_ARREADY)
		r_m_araddr <= r_m_araddr + AWADDR_PLUS;
	else
		r_m_araddr <= r_m_araddr;

/*******************************读数据通道*******************************/
//读数据准备
always@(posedge M_AXI_ACLK)
	if(M_AXI_ARESETN == 1'b0 || M_AXI_RLAST)
		r_m_rready <= 1'b0;
	else if(M_AXI_RVALID)
		r_m_rready <= 1'b1;
	else
		r_m_rready <= r_m_rready;

endmodule
module axi_full_slave #
	(

		parameter integer C_S_AXI_ID_WIDTH		= 1					,
		parameter integer C_S_AXI_DATA_WIDTH	= 32				,
		parameter integer C_S_AXI_ADDR_WIDTH	= 16				,
		parameter integer C_S_AXI_AWUSER_WIDTH	= 0					,
		parameter integer C_S_AXI_ARUSER_WIDTH	= 0					,
		parameter integer C_S_AXI_WUSER_WIDTH	= 0					,
		parameter integer C_S_AXI_RUSER_WIDTH	= 0					,
		parameter integer C_S_AXI_BUSER_WIDTH	= 0
	)
	(
		input 	wire  										S_AXI_ACLK			,
		input 	wire  										S_AXI_ARESETN		,
		input 	wire [C_S_AXI_ID_WIDTH-1 : 0] 				S_AXI_AWID			,
		input 	wire [C_S_AXI_ADDR_WIDTH-1 : 0] 			S_AXI_AWADDR		,
		input 	wire [7 : 0] 								S_AXI_AWLEN			,
		input 	wire [2 : 0] 								S_AXI_AWSIZE		,
		input 	wire [1 : 0] 								S_AXI_AWBURST		,
		input 	wire  										S_AXI_AWLOCK		,
		input 	wire [3 : 0] 								S_AXI_AWCACHE		,
		input 	wire [2 : 0] 								S_AXI_AWPROT		,
		input 	wire [3 : 0] 								S_AXI_AWQOS			,
		input 	wire [3 : 0] 								S_AXI_AWREGION		,
		input 	wire [C_S_AXI_AWUSER_WIDTH-1 : 0] 			S_AXI_AWUSER		,
		input 	wire  										S_AXI_AWVALID		,
		output 	wire  										S_AXI_AWREADY		,
		
		input 	wire [C_S_AXI_DATA_WIDTH-1 : 0] 			S_AXI_WDATA			,
		input 	wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] 		S_AXI_WSTRB			,
		input 	wire  										S_AXI_WLAST			,
		input 	wire [C_S_AXI_WUSER_WIDTH-1 : 0] 			S_AXI_WUSER			,
		input 	wire  										S_AXI_WVALID		,
		output 	wire  										S_AXI_WREADY		,
		
		output 	wire [C_S_AXI_ID_WIDTH-1 : 0] 				S_AXI_BID			,
		output 	wire [1 : 0] 								S_AXI_BRESP			,
		output 	wire [C_S_AXI_BUSER_WIDTH-1 : 0] 			S_AXI_BUSER			,
		output 	wire  										S_AXI_BVALID		,
		input 	wire  										S_AXI_BREADY		,
		
		input 	wire [C_S_AXI_ID_WIDTH-1 : 0] 				S_AXI_ARID			,
		input 	wire [C_S_AXI_ADDR_WIDTH-1 : 0] 			S_AXI_ARADDR		,
		input 	wire [7 : 0] 								S_AXI_ARLEN			,
		input 	wire [2 : 0] 								S_AXI_ARSIZE		,
		input 	wire [1 : 0] 								S_AXI_ARBURST		,
		input 	wire  										S_AXI_ARLOCK		,
		input 	wire [3 : 0] 								S_AXI_ARCACHE		,
		input 	wire [2 : 0] 								S_AXI_ARPROT		,
		input 	wire [3 : 0] 								S_AXI_ARQOS			,
		input 	wire [3 : 0] 								S_AXI_ARREGION		,
		input 	wire [C_S_AXI_ARUSER_WIDTH-1 : 0] 			S_AXI_ARUSER		,
		input 	wire  										S_AXI_ARVALID		,
		output 	wire  										S_AXI_ARREADY		,
		
		output 	wire [C_S_AXI_ID_WIDTH-1 : 0] 				S_AXI_RID			,
		output 	wire [C_S_AXI_DATA_WIDTH-1 : 0] 			S_AXI_RDATA			,
		output 	wire [1 : 0] 								S_AXI_RRESP			,
		output 	wire  										S_AXI_RLAST			,
		output 	wire [C_S_AXI_RUSER_WIDTH-1 : 0] 			S_AXI_RUSER			,
		output 	wire  										S_AXI_RVALID		,
		input 	wire  										S_AXI_RREADY
);

/*******************************function*******************************/
function integer clog2(input integer number);
	for(clog2=0;number>0;clog2=clog2+1)
		number = number >> 1;
endfunction
/*********************************reg*********************************/
reg															r_s_awready			;

reg															r_s_wready			;
reg	[3:0]													data_cnt			;

reg	[1:0]													r_s_bresp			;
reg															r_s_bvalid			;

reg															r_s_arready			;

reg	[C_S_AXI_DATA_WIDTH-1 : 0]								r_s_rdata			;
reg															r_s_rlast			;
reg															r_s_rvalid			;

reg	[C_S_AXI_DATA_WIDTH-1 : 0]			mem		[0 : C_S_AXI_ADDR_WIDTH-1]		;

/********************************wire********************************/
	

/******************************parameter******************************/


/*********************************port*********************************/


/*******************************machine*******************************/


/*****************************component*****************************/
integer	i;

/*******************************assign*******************************/
assign S_AXI_AWREADY 	= 	r_s_awready;

assign S_AXI_WREADY	 	= 	r_s_wready;

assign S_AXI_BID		=	'b0;
assign S_AXI_BRESP		=	r_s_bresp;
assign S_AXI_BUSER		=	'b1;
assign S_AXI_BVALID		=	r_s_bvalid;

assign S_AXI_ARREADY	=	r_s_arready;

assign S_AXI_RID		=	'b0;
assign S_AXI_RDATA		=	r_s_rdata;		
assign S_AXI_RRESP		=	'b0;		
assign S_AXI_RLAST		=	r_s_rlast;
assign S_AXI_RUSER		=	'b1;	
assign S_AXI_RVALID		=	r_s_rvalid;	

/*******************************always*******************************/


/*****************************写地址通道*****************************/
always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0 || (S_AXI_AWREADY && S_AXI_AWVALID))
		r_s_awready <= 1'b0;
	else if(S_AXI_AWVALID == 1'b1)
		r_s_awready <= 1'b1;
	else
		r_s_awready <= 1'b0;		
		
/*****************************写数据通道*****************************/
always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0 || S_AXI_WLAST)
		r_s_wready <= 1'b0;
	else if(S_AXI_WVALID == 1'b1)
		r_s_wready <= 1'b1;
	else
		r_s_wready <= r_s_wready;		

always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0)
		data_cnt <= 'b0;
	else if(data_cnt == 15)
		data_cnt <= 'b0;
	else if((S_AXI_WREADY && S_AXI_WVALID) || (S_AXI_RVALID && S_AXI_RREADY))
		data_cnt <= data_cnt + 1'b1;
	else
		data_cnt <= data_cnt;

always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0)
		for(i=0;i<=(C_S_AXI_ADDR_WIDTH-1);i=i+1)
			mem[i] <= 'b0;
	else if(S_AXI_WREADY && S_AXI_WVALID)
		mem[data_cnt] <= S_AXI_WDATA;
			
/*****************************写响应通道*****************************/
always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0 || (S_AXI_BREADY && S_AXI_BVALID)) begin
		r_s_bresp <= 'b0;
		r_s_bvalid<= 'b0;
	end
	else if(S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST) begin
		r_s_bresp <= 'b0;
		r_s_bvalid<= 'b1;	
	end
	else begin
		r_s_bresp <= 'b0;
		r_s_bvalid<= r_s_bvalid;	
	end

/*****************************读地址通道*****************************/
always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0 || (S_AXI_ARREADY && S_AXI_ARVALID))
		r_s_arready <= 1'b0;
	else if(S_AXI_ARVALID == 1'b1)
		r_s_arready <= 1'b1;
	else
		r_s_arready <= 1'b0;		

/*****************************读数据通道*****************************/
always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0 || S_AXI_RLAST)
		r_s_rvalid <= 1'b0;
	else if(S_AXI_ARREADY && S_AXI_ARVALID)
		r_s_rvalid <= 1'b1;
	else
		r_s_rvalid <= r_s_rvalid;

always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0)
		r_s_rlast <= 1'b0;
	else if(data_cnt == 15)
		r_s_rlast <= 1'b1;
	else
		r_s_rlast <= 1'b0;		

always@(posedge S_AXI_ACLK)
	if(S_AXI_ARESETN == 1'b0)
		r_s_rdata <= 'b0;
	else if(S_AXI_RVALID && S_AXI_RREADY)
		r_s_rdata <= mem[data_cnt];
	else
		r_s_rdata <= r_s_rdata;		


		
endmodule
`timescale 1ns/1ns

module tb_top_axi_full();

reg	clk;
reg	rst_n;
reg	txn;

top_axi_full u_top_axi_full
(	.clk				(clk	),
    .rst_n			(rst_n	),
    .txn     (txn 	)
);



always #10 clk = ~clk;

initial begin

	rst_n = 1'b1;
	clk	  = 1'b0;
	txn   = 1'b0;
	
	#20
	rst_n = 1'b0;
	
	#20
	rst_n = 1'b1;
	
	#20
	txn   = 1'b1;
	
	#20
	txn   = 1'b0;	



end 

endmodule

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值