【接口协议】FPGA AXI接口协议详解

0.序言

AXI是一种高频率,高带宽,低延迟的总线协议,是一种突发传输协议,即相邻存储器连续进行数据传输。是由ARM公司推出的,后被用于FPGA。主要分为三种类型:AXI_FULL(全功能版),AXI_LITE(简化版),AXI_STREAM(面向数据流的)。本文详细说明AXI_FULL类型,后面两种类型是FULL型的简化。

1.数据手册详解

(1)读写数据时序总图

AXI协议总共有5个数据通道:写数据地址通道写数据通道写应答通道读数据地址通道读数据通道
1)在进行写数据时:
在这里插入图片描述
主机先通过写数据地址通道给从机传输写数据的地址写数据模式等信息;
然后主机紧接着,通过写数据通道,给从机连续传输写入的数据
完成后,从机通过写应答通道,给主机反馈写完成应答信号
2)在进行读数据时:
在这里插入图片描述
主机先通过读数据地址通道给从机传输读数据的地址读数据模式等信息;
然后从机紧接着,通过读数据通道,给主机连续传输读出的数据

(2)5个通道

1)写数据地址通道
在这里插入图片描述
需要通过通过13个接口发送或接收13个数据:

信号说明
AWID[C_M_AXI_ID_WIDTH-1:0]主机写地址ID,这个信号是写地址信号组的ID tag
AWADDR[C_M_AXI_ADDR_WIDTH-1:0]主机数据的地址,当是突发传输时,只用给首地址,后面数据的地址存储时会自动累加;
AWLEN[7:0]主机突发传输长度,即单次连续写数据个数,实际的突发长度burst_len = AWLEN+1,所以AWLEN为连续写数据的个数减1。要求实际的突发长度burst_len应该为2的指数次幂,即1,2,4,8,16,32,64,128,256…;
AWSIZE[3:0]主机每次写入数据的字节宽度,数据的宽度为2(AWSIZE)个字节。例:AWSIZE=0,数据位宽为20字节,即8位宽;AWSIZE=1,数据位宽为21字节,即16位宽;
AWBURST[1:0]主机突发模式。FIXWED:固定模式,突发多次,每一次传输的地址都不变;ICCR:自增模式,突发多次,地址依次自增;WRAP:包装式突发读写跟增值式突发读写类似。包装式突发读写的地址是包数据的低地址当到达一个包边界。三种模式分别对应:0’b00,0’b01,0b10
AWLOCK主机AXI不支持锁,直接给0;
AWCACHE[3:0]主机缓存模式:有多种模式,一般使用无缓存模式;
AWPROT[2:0]主机保护编码(详见后图):有的AXI可以特权访问/安全访问/指明数据访问还是指令访问这里设置全零模式;
AWQOS[3:0]主机AXI协议这个信号没用,给全0;
AWREGION[3:0]主机AXI协议这个信号一般没用,给全0;
AWUSER[C_M_AXI_AWUSER_WIDTH-1 :0]主机AXI协议这个信号一般没用,给全0;
AWVALID主机重要,主机给从机的写数据地址准备好标志信号;
AWREADY从机重要,从机给主机反馈的接收数据地址准备好标志信号;

注意:当写数据地址信息准备好后,AWVALID和AWREADY同时有效时,从机才接收写数据地址信息。
下图是对数据手册中AWPROT信号部分的翻译:
在这里插入图片描述
2)写数据通道
在这里插入图片描述

信号说明
WID[C_M_AXI_ID_WIDTH-1:0]主机写数据ID,这个信号是时写地址信号组的ID tag,必须与AWID匹配;
WDATA[C_M_AXI_DATA_WIDTH-1 : 0]主机写的数据
WSTRB[C_M_AXI_DATA_WIDTH/8-1 : 0]主机指示写的数据哪些字节是有效的。例子:数据32‘H1234_5678; 掩码:4’b0111;表示第一个字节数据12无效,后三个字节数据34_5678有效;
WUSER[C_M_AXI_WUSER_WIDTH-1 : 0]主机一般不用,给默认0值
WLAST主机突发写数据最后一个数据的标志信号,在给最后一个数据时,要将此信号拉高一个时钟周期;
WVALID主机重要,主机给从机的写数据准备好标志信号;
WREADY从机重要,从机给主机反馈的接收数据准备好标志信号;

注意:当写数据信息准备好后,WVALID和WREADY同时有效时,从机才接收写数据信息。
3)写数据响应通道
在这里插入图片描述

信号说明
BID[C_M_AXI_ID_WIDTH-1:0]从机响应ID,这个信号是响应信号组的ID tag,必须与AWID匹配;
BRESP[1:0]从机写操作响应信号,指明写数据操作的状态,可能的响应有OKAY、EXOKAY、SLVERR、DECERR
BUSER[C_M_AXI_WUSER_WIDTH-1 : 0]从机一般不用,给默认0值
BVALID从机重要,从机给主机反馈的写操作响应准备好标志;
WREADY主机重要,主机给从机的接收写操作响应准备好信号;

注意:当从机的写数据响应信号准备好后,BVALID和BREADY同时有效时,主机才接收写数据响应信号。
4)读数据地址通道
基本同写数据地址通道一致,取值方式也一样。
在这里插入图片描述
5)读数据通道
在这里插入图片描述
基本信号同写数据通道一致,不同的是读数据通道数据基本是读入的,不用写,只需要在读数据准备好时给从机发送读数据准备好信号,即可读取数据。

信号说明
RID[C_M_AXI_ID_WIDTH-1:0]从机从机输入的读数据ID,这个信号是时写地址信号组的ID tag,必须与ARID匹配;
RDATA[C_M_AXI_DATA_WIDTH-1 : 0]从机从机输入的读取的数据;
RUSER[C_M_AXI_WUSER_WIDTH-1 : 0]从机从机输入的一般不用;
RLAST从机从机输入的突发读数据最后一个数据的标志信号,当此信号拉高时表示读到了最后一个数据;
RVALID从机重要从机给主机的读数据准备好标志信号;
RREADY主机重要主机给从机发送的接收数据准备好标志信号;

注意:当读数据信息准备好后,RVALID和RREADY同时有效时,从机才发送给主机读出的数据。

2.例子

(1)目标

基于AXI4协议向从机存入11到26共16个数据(突发长度为16),起始地址为11。然后,将16个数据,从从机中以突发的形式全部读出。

(2)实现步骤

A 写数据操作
发送写数据地址信息->突发写数据(最后一个数据要拉高写LAST信号)->接收从机应答信号
B 读数据操作
发送读数据地址信息->突发接收数据(输入最后一个数据时,读数据LAST信号会被拉高)

(3)具体实现

(A)AXI接口协议驱动模块
a 数据位宽计算:
在前面读/写数据地址通道时说道,AXI接口协议的主机给从机的数据位宽信息(M_AXI_AWSIZE)是以字节为单位的,比如:M_AXI_AWSIZE=0,表示传输的数据位宽为20个字节,即8位宽;M_AXI_AWSIZE=1,表示传输的数据位宽为21个字节,即16位宽。而在给参数时,我们传参的数据位宽用的是二进制位宽,所以在传给从机时,要将二进制位宽换算成以字节为单位的形式。使用了函数:

    function integer bit_wide;
        input integer data_in;
        for(bit_wide = 0;data_in > 0;bit_wide = bit_wide + 1'b1)
              data_in = data_in >> 1;      
    endfunction

调用函数计算位宽如下:

	M_AXI_AWSIZE		=	bit_wide((C_M_AXI_DATA_WIDTH/8)-1)	;

使用举例:
当数据实际位宽为32位,传参C_M_AXI_DATA_WIDTH=32,则(C_M_AXI_DATA_WIDTH/8)-1=3,在函数中会for循环两次,返回值为2,所以为22个字节位宽,所以给从机穿的位宽信息为M_AXI_AWSIZE,等于4个字节。

b 参数赋值
AXI4的工作模式一旦确定,很多接口的数据就会确定。对于需要变化的数据,我们在后续用端口名字_r的形式在后续进行产生,在这一部分也统一进行赋值。

	/*********************寄存器信号*********************/
	//
	//写地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_AWADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_AWVALID_r				;	//写地址有效标志寄存
	//写数据操作
	//reg 	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r				;	//写数据赋值寄存器
	reg 									M_AXI_WLAST_r 				;	//写数据最后一位标志寄存器
	reg 									M_AXI_WVALID_r				;	//写数据有效标志
	//读地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_ARADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_ARVALID_r				;	//写地址有效标志寄存
	//读数据操作
	reg 									M_AXI_RREADY_r				;	//主机读数据准备好信号
	
    /************************参数************************/
	//写地址参数的常量
	assign 	M_AXI_AWID			=	'd0									;	//写地址ID,一半不用,设为0
	assign 	M_AXI_AWLEN  		=   C_M_AXI_BURST_LEN					;	//突发长度,连续写数据的个数
	assign 	M_AXI_AWSIZE		=	bit_wide((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'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign 	M_AXI_AWQOS			= 	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign	M_AXI_AWREGION		=	4'b0000								;	//Axi4协议的REGION一般没用,默认4位0值
	assign 	M_AXI_AWUSER		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)    
	//写地址参数需要控制的量    
	//assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;	//写地址赋值,输出的地址=数据写地址+基址;
	assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r						;	//写地址赋值
	assign	M_AXI_AWVALID   	=	M_AXI_AWVALID_r						;	//写地址有效标志赋值

	//写数据参数的常量   
	assign 	M_AXI_WSTRB			= 	{(C_M_AXI_DATA_WIDTH/8){1'b1}}		;	//每8位数据一位掩码,拉高所有掩码,数据有效传输
	assign	M_AXI_WUSER			= 	'd0									;	//没有用户自定义信号,设为全0
   	//写数据需要控制的信号
	assign	M_AXI_WDATA 		= 	M_AXI_WDATA_r 						;	//写数据赋值
	assign	M_AXI_WLAST 		= 	M_AXI_WLAST_r & M_AXI_WREADY		; 	//最后一个写数据标志信号赋值
	assign	M_AXI_WVALID		= 	M_AXI_WVALID_r						; 	//写数据有效标志赋值

	//写响应参数的常量
	assign	M_AXI_BREADY		= 	1'b1								;	//直接拉高,表示主机一直准备接收从机的写响应信号
	
	//读地址通道参数的常量
	assign	M_AXI_ARID  		=	'd0									;   //读地址ID,一半不用,设为0
	assign	M_AXI_ARLEN    		=	C_M_AXI_BURST_LEN					;	//突发长度,连续读数据的个数
	assign	M_AXI_ARSIZE   		=	bit_wide((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'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign	M_AXI_ARQOS    		=	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign 	M_AXI_ARREGION		= 	4'b0000								;	//Axi4协议的REGION信号没用,默认4位0值	 
	assign	M_AXI_ARUSER   		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)
	//读地址参数需要控制的量  
	//assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;  	//读地址赋值,输出的地址=数据读取地址+基址;
	assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r						;	//读地址赋值
	assign 	M_AXI_ARVALID 		=	M_AXI_ARVALID_r						; 	//读地址有效标志赋值

	//读数据通道
	assign	M_AXI_RREADY		= 	M_AXI_RREADY_r						;	//主机准备好从从机读入数据

c 写数据地址通道数据产生

	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_AWVALID_r <= 1'b0;
		else if(write_flag)
			M_AXI_AWVALID_r <= 1'b1;
		else if(M_AXI_AWVALID_r&&M_AXI_AWREADY)
			M_AXI_AWVALID_r <= 1'b0;
		else
			M_AXI_AWVALID_r <=M_AXI_AWVALID_r;
	end

当读写控制模块(详见后续说明,用于产生AXI接口需要写的数据和地址,并接收AXI接口读出数据的模块)给了写操作开始标志(write_flag)时(同时会给数据存储的起始地址M_AXI_AWADDR_r),主机立刻产生写数据地址有效信号M_AXI_AWVALID_r,从机接收到这个有效信号一个时钟后,会反馈准备好接收写数据地址M_AXI_AWREADY信号,写数据地址有效信号M_AXI_AWVALID_r需要在准备好接收写数据地址M_AXI_AWREADY信号为高的情况下,保持一个时钟的高电平,所以在两个信号同时为高时,将写数据地址有效信号M_AXI_AWVALID_r拉低。
在这里插入图片描述

特别注意:5个通道在进行传输时,主机都会有一个有效信号,从机都会有一个准备好接收信号。在主机准备好数据后,都需要将有效信号拉高,从机一般会在收到有效信号一个时钟周期后反馈准备好接收信号。因为从机会在有效信号准备好就收信号同时为高的情况下采集数据,所以有效信号需要在准备好接收信号为高的情况下保持一个时钟的高电平。

d 写数据通道数据产生

	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WVALID_r <= 1'b0;
		else if(M_AXI_AWVALID_r && M_AXI_AWREADY)
			M_AXI_WVALID_r <= 1'b1;
		else if(M_AXI_WLAST_r)
			M_AXI_WVALID_r <= 1'b0;
		else
			M_AXI_WVALID_r <=M_AXI_WVALID_r;
	end

一般传输了地址后,立马开始突发传输数据。于是在写数据地址有效信号M_AXI_AWVALID_r拉低的同时,将写数据有效信号M_AXI_WVALID_r拉高,所以公用了同一个判断条件**(M_AXI_AWVALID_r && M_AXI_AWREADY),且这个写数据有效信号M_AXI_WVALID_r会一直保持到突发传输完成后再拉低,所以判断标志为写数据的LAST信号M_AXI_WLAST_r**为高。
注意:读/写操作都会有这个LAST标志信号,这个信号会在突发传输的最后一个数据进行拉高,即最后一个数据的标志信号。

	//LAST信号产生计数器
	reg [7:0]	W_LAST_cnt;
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			W_LAST_cnt <= 'd0;
		else if(M_AXI_WVALID_r && M_AXI_WREADY)
			if(W_LAST_cnt == C_M_AXI_BURST_LEN)
				W_LAST_cnt <= 'd0;
			else
				W_LAST_cnt <= W_LAST_cnt + 1'b1;
		else 
			W_LAST_cnt <= W_LAST_cnt;
	end

	//试配所有突发长度的写LAST信号
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WLAST_r <= 1'b0;
		else begin
			if(C_M_AXI_BURST_LEN == 0)					//突发长度为0+1=1,只写一个数据,跟随写数据地址有效且从机写数据地址准备好信号(因为突发长度只能是2的幂次方)
				M_AXI_WLAST_r <= M_AXI_WVALID;
			else if(C_M_AXI_BURST_LEN == 1)				//突发长度为1+1=2,只写2个数据,即写数据有效且从机写数据地址准备好信号
				M_AXI_WLAST_r <= M_AXI_WVALID_r & M_AXI_WREADY;
			else if(W_LAST_cnt == C_M_AXI_BURST_LEN - 1)
				M_AXI_WLAST_r <= 1'b1;
			else
				M_AXI_WLAST_r <= 1'b0;
		end
	end

在产生写数据LAST信号时需要分情况讨论:
a)第一种情况是突发长度n>2,所以我们会用一个n状态计数器,共存在0到n-1共n个状态,要保证LAST信号在最后一个状态(n-1)为高电平,所以每次计数到(n-2)时将写数据LAST信号M_AXI_WLAST_r拉高。
(显然,在突发长度n<=2时,每次计数到(n-2)时将写数据LAST信号M_AXI_WLAST_r拉高这种方式是不对的,所以需要额外讨论)
b)第二种情况是突发长度n=2,我们将第一个数据有效传输为标志,即写数据有效信号M_AXI_WVALID_r准备好接收写数据信号M_AXI_WREADY同时为高作为写数据LAST信号M_AXI_WLAST_r拉高的标志;
c)第三种情况是突发长度n=1,我们需要保证写数据LAST信号M_AXI_WLAST_r在从机反馈的准备好接收写数据信号M_AXI_WREADY为高时同时为高。我们知道,从机反馈的准备好接收写数据信号M_AXI_WREADY会在写数据有效信号M_AXI_WVALID_r拉高一个时钟周期后拉高,所以我们将写数据有效信号M_AXI_WVALID_r直接赋值给写数据LAST信号M_AXI_WLAST_r。因为写数据有效信号M_AXI_WVALID_r会比突发长度多一个时钟周期,所以此时写数据LAST信号M_AXI_WLAST_r会比正常情况多了一个周期,所以我们还在数据还在给端口赋值时,将写数据LAST信号M_AXI_WLAST_r与上了准备好接收写数据信号M_AXI_WREADY
注意:情况二和情况三只适用于,从机反馈的准备好信号相较于主机给的有效信号延迟一个时钟周期的情况,若不满足这种情况,这两种情况就还需要修改。
在这里插入图片描述
e 读数据地址通道数据产生

	//读地址有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_ARVALID_r <= 1'b0;
		else if(read_flag)
			M_AXI_ARVALID_r <= 1'b1;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_ARVALID_r <= 1'b0;
		else
			M_AXI_ARVALID_r <=M_AXI_ARVALID_r;
	end

同写数据地址通道一样,当读写控制模块给了读操作开始标志(read_flag)时(同时会给数据读取的起始地址M_AXI_ARADDR_r),主机立刻产生读数据地址有效信号M_AXI_ARVALID_r,从机接收到这个有效信号一个时钟后,会反馈准备好接收读数据地址M_AXI_ARREADY信号,读数据地址有效信号M_AXI_ARVALID_r需要在准备好接收读数据地址M_AXI_ARREADY信号为高的情况下,保持一个时钟的高电平,所以在两个信号同时为高时,将读数据地址有效信号M_AXI_ARVALID_r拉低。
在这里插入图片描述
f 读数据通道数据产生

	//读数据准备好标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_RREADY_r <= 1'b0;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_RREADY_r <= 1'b1;
		else if(M_AXI_RLAST)
			M_AXI_RREADY_r <= 1'b0;
		else
			M_AXI_RREADY_r <=M_AXI_RREADY_r;
	end

读数据通道的读入数据M_AXI_RDATA读数据LAST信号M_AXI_RLAST由从机产生,所以主机只需要在传输完读数据地址后,给从机一个读数据准备好信号M_AXI_RREADY_r。且在收到读数据LAST信号M_AXI_RLAST后将准备好信号拉低。

g AXI接口协议驱动模块完整代码

`timescale 1ns / 1ps
module AXI_full_M
    #(
		//parameter           C_M_TARGET_SLAVE_BASE_ADDR	= 32'h4000_0000 ,
		parameter integer   C_M_AXI_BURST_LEN	        = 15           ,
		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,一半不用
		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   ,	//突发模式选择,00为固定地址,01为自增地址突发
		output  wire                                    M_AXI_AWLOCK    ,	//锁信号一般不用,保持为0
		output  wire    [3 : 0]                         M_AXI_AWCACHE   ,	//缓存模式,有多种,这里使用无缓存模式
		output  wire    [2 : 0]                         M_AXI_AWPROT    ,	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		output  wire    [3 : 0]                         M_AXI_AWQOS     ,	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		output 	wire	[3 : 0]							M_AXI_AWREGION	,
		output  wire    [C_M_AXI_AWUSER_WIDTH-1 : 0]    M_AXI_AWUSER    ,	//区域标识符,这里没用,默认0值
		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     ,	//掩码信号,每8位数据就对应一位掩码信号,掩码信号为高时,数据才能正常传输
		output  wire                                    M_AXI_WLAST     ,	//写数据最后一个数据标志信号
		output  wire    [C_M_AXI_WUSER_WIDTH-1 : 0]     M_AXI_WUSER     ,	//用户自定义信号
		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    [C_M_AXI_BUSER_WIDTH-1 : 0]     M_AXI_BUSER     ,
		input   wire                                    M_AXI_BVALID    ,
		output  wire                                    M_AXI_BREADY    ,	//写响应信号,主机给从机的响应准备好信号
		//读地址通道
		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   ,	//突发模式选择,00为固定地址,01为自增地址突发
		output  wire                                    M_AXI_ARLOCK    ,	//锁信号一般不用,保持为0
		output  wire    [3 : 0]                         M_AXI_ARCACHE   ,	//缓存模式,有多种,这里使用无缓存模式
		output  wire    [2 : 0]                         M_AXI_ARPROT    ,	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		output  wire    [3 : 0]                         M_AXI_ARQOS     ,	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		output	wire	[3 : 0]							M_AXI_ARREGION	,	//REGION,一般不用,赋4'b0000
		output  wire    [C_M_AXI_ARUSER_WIDTH-1 : 0]    M_AXI_ARUSER    ,	//区域标识符,这里没用,默认0值
		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     ,	//从机数据的读数据LAST信号
		input   wire    [C_M_AXI_RUSER_WIDTH-1 : 0]     M_AXI_RUSER     ,
		input   wire                                    M_AXI_RVALID    ,	//从机输入的读数据准备好信号
		output  wire                                    M_AXI_RREADY	,	//读数据通道主机准备好信号
		//读写数据控制端口
		input	wire 									write_flag		,	//写操作标志信号	
		input	wire 									read_flag		,	//读操作标志信号
		input	wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_AWADDR_r	,	//写数据地址寄存
		input 	wire	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r	,	//写数据赋值寄存器
		input   wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_ARADDR_r		//读数据地址寄存
	);
	
    /***************计算输入数据的二进制位宽***************/
    function integer bit_wide;
        input integer data_in;
        for(bit_wide = 0;data_in > 0;bit_wide = bit_wide + 1'b1)
              data_in = data_in >> 1;      
    endfunction

	/*********************寄存器信号*********************/
	//
	//写地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_AWADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_AWVALID_r				;	//写地址有效标志寄存
	//写数据操作
	//reg 	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r				;	//写数据赋值寄存器
	reg 									M_AXI_WLAST_r 				;	//写数据最后一位标志寄存器
	reg 									M_AXI_WVALID_r				;	//写数据有效标志
	//读地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_ARADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_ARVALID_r				;	//写地址有效标志寄存
	//读数据操作
	reg 									M_AXI_RREADY_r				;	//主机读数据准备好信号

    /************************参数************************/
	//写地址参数的常量
	assign 	M_AXI_AWID			=	'd0									;	//写地址ID,一半不用,设为0
	assign 	M_AXI_AWLEN  		=   C_M_AXI_BURST_LEN					;	//突发长度,连续写数据的个数
	assign 	M_AXI_AWSIZE		=	bit_wide((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'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign 	M_AXI_AWQOS			= 	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign	M_AXI_AWREGION		=	4'b0000								;	//Axi4协议的REGION一般没用,默认4位0值
	assign 	M_AXI_AWUSER		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)    
	//写地址参数需要控制的量    
	//assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;	//写地址赋值,输出的地址=数据写地址+基址;
	assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r						;	//写地址赋值
	assign	M_AXI_AWVALID   	=	M_AXI_AWVALID_r						;	//写地址有效标志赋值

	//写数据参数的常量   
	assign 	M_AXI_WSTRB			= 	{(C_M_AXI_DATA_WIDTH/8){1'b1}}		;	//每8位数据一位掩码,拉高所有掩码,数据有效传输
	assign	M_AXI_WUSER			= 	'd0									;	//没有用户自定义信号,设为全0
   	//写数据需要控制的信号
	assign	M_AXI_WDATA 		= 	M_AXI_WDATA_r 						;	//写数据赋值
	assign	M_AXI_WLAST 		= 	M_AXI_WLAST_r & M_AXI_WREADY		; 	//最后一个写数据标志信号赋值
	assign	M_AXI_WVALID		= 	M_AXI_WVALID_r						; 	//写数据有效标志赋值

	//写响应参数的常量
	assign	M_AXI_BREADY		= 	1'b1								;	//直接拉高,表示主机一直准备接收从机的写响应信号
	
	//读地址通道参数的常量
	assign	M_AXI_ARID  		=	'd0									;   //读地址ID,一半不用,设为0
	assign	M_AXI_ARLEN    		=	C_M_AXI_BURST_LEN					;	//突发长度,连续读数据的个数
	assign	M_AXI_ARSIZE   		=	bit_wide((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'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign	M_AXI_ARQOS    		=	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign 	M_AXI_ARREGION		= 	4'b0000								;	//Axi4协议的REGION信号没用,默认4位0值	 
	assign	M_AXI_ARUSER   		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)
	//读地址参数需要控制的量  
	//assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;  	//读地址赋值,输出的地址=数据读取地址+基址;
	assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r						;	//读地址赋值
	assign 	M_AXI_ARVALID 		=	M_AXI_ARVALID_r						; 	//读地址有效标志赋值

	//读数据通道
	assign	M_AXI_RREADY		= 	M_AXI_RREADY_r						;	//主机准备好从从机读入数据

    /******************AXI_读写数据实现******************/
	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 	else 
	// end
	//写地址通道:写地址有效标志,写地址
	//写地址有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_AWVALID_r <= 1'b0;
		else if(write_flag)
			M_AXI_AWVALID_r <= 1'b1;
		else if(M_AXI_AWVALID_r&&M_AXI_AWREADY)
			M_AXI_AWVALID_r <= 1'b0;
		else
			M_AXI_AWVALID_r <=M_AXI_AWVALID_r;
	end
	//写地址:由控制模块产生
	/*
			实现的功能是向11地址写入数据11~20,起始地址为11
	*/
	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 		M_AXI_AWADDR_r <= 'd0;
	// 	else if(write_flag)
	// 		M_AXI_AWADDR_r <= 'd11;
	// 	else
	// 		M_AXI_AWADDR_r <= M_AXI_AWADDR_r;
	// end

	//写数据通道:写数据有效标志,写数据,最后一个写数据标志信号
	//写数据有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WVALID_r <= 1'b0;
		else if(M_AXI_AWVALID_r && M_AXI_AWREADY)
			M_AXI_WVALID_r <= 1'b1;
		else if(M_AXI_WLAST_r)
			M_AXI_WVALID_r <= 1'b0;
		else
			M_AXI_WVALID_r <=M_AXI_WVALID_r;
	end
	// //写的数据
	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 		M_AXI_WDATA_r <= 'd0;
	// 	else if(M_AXI_AWVALID_r && M_AXI_AWREADY)	//给第一个数据
	// 		M_AXI_WDATA_r <= 'd11;
	// 	else if((M_AXI_WVALID_r && M_AXI_WREADY) && (!M_AXI_WLAST_r))
	// 		M_AXI_WDATA_r <= M_AXI_WDATA_r+1'b1;
	// 	else 
	// 		M_AXI_WDATA_r <= 'd0;
	// end
	//LAST信号产生计数器
	reg [7:0]	W_LAST_cnt;
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			W_LAST_cnt <= 'd0;
		else if(M_AXI_WVALID_r && M_AXI_WREADY)
			if(W_LAST_cnt == C_M_AXI_BURST_LEN)
				W_LAST_cnt <= 'd0;
			else
				W_LAST_cnt <= W_LAST_cnt + 1'b1;
		else 
			W_LAST_cnt <= W_LAST_cnt;
	end

	//试配所有突发长度的写LAST信号
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WLAST_r <= 1'b0;
		else begin
			if(C_M_AXI_BURST_LEN == 0)					//突发长度为0+1=1,只写一个数据,跟随写数据地址有效且从机写数据地址准备好信号(因为突发长度只能是2的幂次方)
				M_AXI_WLAST_r <= M_AXI_WVALID;
			else if(C_M_AXI_BURST_LEN == 1)				//突发长度为1+1=2,只写2个数据,即写数据有效且从机写数据地址准备好信号
				M_AXI_WLAST_r <= M_AXI_WVALID_r & M_AXI_WREADY;
			else if(W_LAST_cnt == C_M_AXI_BURST_LEN - 1)
				M_AXI_WLAST_r <= 1'b1;
			else
				M_AXI_WLAST_r <= 1'b0;
		end
	end

	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 		M_AXI_WLAST_r <= 1'b0;
	// 	else if(W_LAST_cnt == C_M_AXI_BURST_LEN - 2'd2)
	// 		M_AXI_WLAST_r <= 1'b1;
	// 	else
	// 		M_AXI_WLAST_r <= 1'b0;
	// end

	//读地址通道:读数据地址有效标志,读数据地址
	//读地址有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_ARVALID_r <= 1'b0;
		else if(read_flag)
			M_AXI_ARVALID_r <= 1'b1;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_ARVALID_r <= 1'b0;
		else
			M_AXI_ARVALID_r <=M_AXI_ARVALID_r;
	end
	// //读首地址
	// /*
	// 		实现的功能是从11地址读出数据
	// */
	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 		M_AXI_ARADDR_r <= 'd0;
	// 	else if(read_flag)
	// 		M_AXI_ARADDR_r <= 'd11;
	// 	else
	// 		M_AXI_ARADDR_r <= M_AXI_ARADDR_r;
	// end

	//读数据通道
	//读数据准备好标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_RREADY_r <= 1'b0;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_RREADY_r <= 1'b1;
		else if(M_AXI_RLAST)
			M_AXI_RREADY_r <= 1'b0;
		else
			M_AXI_RREADY_r <=M_AXI_RREADY_r;
	end

endmodule

(B)读写控制模块
当读写控制模块用于产生AXI接口需要写的数据和地址,并接收AXI接口读出数据的模块。
a 状态机
使用一个三状态的有限状态机(空闲状态,写数据状态和读数据状态),默认空闲状态,当操作开始读写信号WR_START有效时开始进入写数据状态;当写数据完成(写到最后一个数据,即写数据LAST信号M_AXI_WLAST为高)进入读数据状态;当读数据完成(读到最后一个数据,即读数据LAST信号M_AXI_RLAST为高)进入空闲状态;在空闲状态等待下一个开始读写信号

b 写/读操作开始标志(write_flag/read_flag)
开始读写信号WR_START作为写操作开始标志信号write_flag触发标志;
写数据LAST信号M_AXI_WLAST作为读操作开始标志信号read_flag触发标志。

c 写数据首地址及数据产生
写操作开始标志信号write_flag有效时给写数据首地址M_AXI_AWADDR_r
因为写数据有效信号M_AXI_WVALID写数据准备好信号M_AXI_WREADY同时有效时,从机采集数据,所以要保证此时数据已经准备好,所以在写完地址时就给第一个数据。其后保证前一个数据写成功,即写数据有效信号M_AXI_WVALID写数据准备好信号M_AXI_WREADY同时有效时,递增产生后续数据。

d 读数据首地址产生
读操作开始标志信号read_flag有效时给读数据首地址M_AXI_ARADDR_r

e 读写控制模块完整代码

//读写数据控制模块:写数据产生模块,读数据接收模块
module write_read_data
    #(
        parameter integer   C_M_AXI_BURST_LEN	        = 16            ,           //突发长度
        parameter integer   C_M_AXI_ADDR_WIDTH	        = 32            ,           //数据地址位宽
		parameter integer   C_M_AXI_DATA_WIDTH	        = 32                        //数据位宽
    )
    (
        input                                           M_AXI_ACLK      ,
        input                                           M_AXI_ARESETN   ,
        //读写总开始标志信号
        input   wire                                    WR_START        ,  
        //写数据地址端口
        output  reg                                     write_flag      ,           //写数据开始标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_AWADDR_r  ,           //写的数据首地址
        input                                           M_AXI_AWVALID   ,           //主机写数据地址有效标志
        input                                           M_AXI_AWREADY   ,           //从机写数据地址准备好信号
        //写数据端口
        input                                           M_AXI_WVALID    ,           //主机写数据有效信号       
        input                                           M_AXI_WREADY    ,           //从机写数据准备好信号
        input                                           M_AXI_WLAST     ,           //主机写数据最后一个标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_WDATA_r   ,
        //读数据地址端口
        output  reg                                     read_flag       ,            //读数据开始标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_ARADDR_r  ,            //读的数据首地址     
        //读数据端口
        input   wire                                    M_AXI_RLAST
    );
    //有限状态机状态
    parameter   STATE_IDLE  =   3'b001;
    parameter   STATE_WRITE =   3'b010;
    parameter   STATE_READ  =   3'b100;
    reg     [2 : 0]   current_state ;
    reg     [2 : 0]   next_state    ;

    //第一段:时序always过程块,格式化地将次态赋值当前状态
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            current_state <= STATE_IDLE;
        else
            current_state <= next_state;
    end
    //第二段:组合always过程块,状态转移条件判断
    always@(*)begin
        case(current_state)
            STATE_IDLE  :begin 
                if(WR_START)
                    next_state = STATE_WRITE;
                else
                    next_state = STATE_IDLE;
            end
            STATE_WRITE :begin
                if(M_AXI_WLAST)
                    next_state = STATE_READ;
                else
                    next_state = STATE_WRITE;
            end
            STATE_READ  :begin
                if(M_AXI_RLAST)
                    next_state = STATE_IDLE;
                else
                    next_state = STATE_READ;
            end
            default:
                next_state = STATE_IDLE;
        endcase
    end
    //第三段:赋值,产生写数据和读数据使能信号
    //写/读操作开始标志
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            write_flag <= 1'b0;
        else if(WR_START)
            write_flag <= 1'b1;
        else
            write_flag <= 1'b0;
    end
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            read_flag <= 1'b0;
        else if(M_AXI_WLAST)
            read_flag <= 1'b1;
        else
            read_flag <= 1'b0;
    end

    /******************读写操作数据及首地址产生******************/
    //写数据地址:产生首地址
	/*
			实现的功能是向11地址写入数据11~20,起始地址为11
	*/
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_AWADDR_r <= 'd0;
		else if(write_flag)
			M_AXI_AWADDR_r <= 'd11;
		else
			M_AXI_AWADDR_r <= M_AXI_AWADDR_r;
	end
    //写数据产生:
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WDATA_r <= 'd0;
		else if(M_AXI_AWVALID && M_AXI_AWREADY)	//给第一个数据
			M_AXI_WDATA_r <= 'd11;
		else if((M_AXI_WVALID && M_AXI_WREADY) && (!M_AXI_WLAST))
			M_AXI_WDATA_r <= M_AXI_WDATA_r+1'b1;
		else 
			M_AXI_WDATA_r <= M_AXI_WDATA_r;
	end
    //读数据地址:产生首地址
    always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_ARADDR_r <= 'd0;
		else if(read_flag)
			M_AXI_ARADDR_r <= 'd11;
		else
			M_AXI_ARADDR_r <= M_AXI_ARADDR_r;
	end

endmodule

(C)从机(这里给出了xilinx例程中给的从机代码:后续会出这个代码的讲解)

`timescale 1 ns / 1 ps

	module AXI_full_slave #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// Width of ID for for write address, write data, read address and read data
		parameter integer C_S_AXI_ID_WIDTH	= 1,
		// Width of S_AXI data bus
		parameter integer C_S_AXI_DATA_WIDTH	= 32,
		// Width of S_AXI address bus
		parameter integer C_S_AXI_ADDR_WIDTH	= 6,
		// Width of optional user defined signal in write address channel
		parameter integer C_S_AXI_AWUSER_WIDTH	= 0,
		// Width of optional user defined signal in read address channel
		parameter integer C_S_AXI_ARUSER_WIDTH	= 0,
		// Width of optional user defined signal in write data channel
		parameter integer C_S_AXI_WUSER_WIDTH	= 0,
		// Width of optional user defined signal in read data channel
		parameter integer C_S_AXI_RUSER_WIDTH	= 0,
		// Width of optional user defined signal in write response channel
		parameter integer C_S_AXI_BUSER_WIDTH	= 0
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line

		// Global Clock Signal
		input wire  S_AXI_ACLK,
		// Global Reset Signal. This Signal is Active LOW
		input wire  S_AXI_ARESETN,
		// Write Address ID
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
		// Write address
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_AWLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_AWSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_AWBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_AWLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_AWCACHE,
		// Protection type. This signal indicates the privilege
    // and security level of the transaction, and whether
    // the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_AWPROT,
		// Quality of Service, QoS identifier sent for each
    // write transaction.
		input wire [3 : 0] S_AXI_AWQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_AWREGION,
		// Optional User-defined signal in the write address channel.
		input wire [C_S_AXI_AWUSER_WIDTH-1 : 0] S_AXI_AWUSER,
		// Write address valid. This signal indicates that
    // the channel is signaling valid write address and
    // control information.
		input wire  S_AXI_AWVALID,
		// Write address ready. This signal indicates that
    // the slave is ready to accept an address and associated
    // control signals.
		output wire  S_AXI_AWREADY,
		// Write Data
		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
		// Write strobes. This signal indicates which byte
    // lanes hold valid data. There is one write strobe
    // bit for each eight bits of the write data bus.
		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
		// Write last. This signal indicates the last transfer
    // in a write burst.
		input wire  S_AXI_WLAST,
		// Optional User-defined signal in the write data channel.
		input wire [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
		// Write valid. This signal indicates that valid write
    // data and strobes are available.
		input wire  S_AXI_WVALID,
		// Write ready. This signal indicates that the slave
    // can accept the write data.
		output wire  S_AXI_WREADY,
		// Response ID tag. This signal is the ID tag of the
    // write response.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
		// Write response. This signal indicates the status
    // of the write transaction.
		output wire [1 : 0] S_AXI_BRESP,
		// Optional User-defined signal in the write response channel.
		output wire [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
		// Write response valid. This signal indicates that the
    // channel is signaling a valid write response.
		output wire  S_AXI_BVALID,
		// Response ready. This signal indicates that the master
    // can accept a write response.
		input wire  S_AXI_BREADY,
		// Read address ID. This signal is the identification
    // tag for the read address group of signals.
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
		// Read address. This signal indicates the initial
    // address of a read burst transaction.
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_ARLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_ARSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_ARBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_ARLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_ARCACHE,
		// Protection type. This signal indicates the privilege
    // and security level of the transaction, and whether
    // the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_ARPROT,
		// Quality of Service, QoS identifier sent for each
    // read transaction.
		input wire [3 : 0] S_AXI_ARQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_ARREGION,
		// Optional User-defined signal in the read address channel.
		input wire [C_S_AXI_ARUSER_WIDTH-1 : 0] S_AXI_ARUSER,
		// Write address valid. This signal indicates that
    // the channel is signaling valid read address and
    // control information.
		input wire  S_AXI_ARVALID,
		// Read address ready. This signal indicates that
    // the slave is ready to accept an address and associated
    // control signals.
		output wire  S_AXI_ARREADY,
		// Read ID tag. This signal is the identification tag
    // for the read data group of signals generated by the slave.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
		// Read Data
		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
		// Read response. This signal indicates the status of
    // the read transfer.
		output wire [1 : 0] S_AXI_RRESP,
		// Read last. This signal indicates the last transfer
    // in a read burst.
		output wire  S_AXI_RLAST,
		// Optional User-defined signal in the read address channel.
		output wire [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
		// Read valid. This signal indicates that the channel
    // is signaling the required read data.
		output wire  S_AXI_RVALID,
		// Read ready. This signal indicates that the master can
    // accept the read data and response information.
		input wire  S_AXI_RREADY
	);

	// AXI4FULL signals
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
	reg  	axi_awready;
	reg  	axi_wready;
	reg [1 : 0] 	axi_bresp;
	reg [C_S_AXI_BUSER_WIDTH-1 : 0] 	axi_buser;
	reg  	axi_bvalid;
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;
	reg  	axi_arready;
	reg [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
	reg [1 : 0] 	axi_rresp;
	reg  	axi_rlast;
	reg [C_S_AXI_RUSER_WIDTH-1 : 0] 	axi_ruser;
	reg  	axi_rvalid;
	// aw_wrap_en determines wrap boundary and enables wrapping
	wire aw_wrap_en;
	// ar_wrap_en determines wrap boundary and enables wrapping
	wire ar_wrap_en;
	// aw_wrap_size is the size of the write transfer, the
	// write address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  aw_wrap_size ; 
	// ar_wrap_size is the size of the read transfer, the
	// read address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  ar_wrap_size ; 
	// The axi_awv_awr_flag flag marks the presence of write address valid
	reg axi_awv_awr_flag;
	//The axi_arv_arr_flag flag marks the presence of read address valid
	reg axi_arv_arr_flag; 
	// The axi_awlen_cntr internal write address counter to keep track of beats in a burst transaction
	reg [7:0] axi_awlen_cntr;
	//The axi_arlen_cntr internal read address counter to keep track of beats in a burst transaction
	reg [7:0] axi_arlen_cntr;
	reg [1:0] axi_arburst;
	reg [1:0] axi_awburst;
	reg [7:0] axi_arlen;
	reg [7:0] axi_awlen;
	//local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	//ADDR_LSB is used for addressing 32/64 bit registers/memories
	//ADDR_LSB = 2 for 32 bits (n downto 2) 
	//ADDR_LSB = 3 for 42 bits (n downto 3)

	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32)+ 1;
	localparam integer OPT_MEM_ADDR_BITS = 3;
	localparam integer USER_NUM_MEM = 1;
	//----------------------------------------------
	//-- Signals for user logic memory space example
	//------------------------------------------------
	wire [OPT_MEM_ADDR_BITS:0] mem_address;
	wire [USER_NUM_MEM-1:0] mem_select;
	reg [C_S_AXI_DATA_WIDTH-1:0] mem_data_out[0 : USER_NUM_MEM-1];

	genvar i;
	genvar j;
	genvar mem_byte_index;

	// I/O Connections assignments

	assign S_AXI_AWREADY	= axi_awready;
	assign S_AXI_WREADY	= axi_wready;
	assign S_AXI_BRESP	= axi_bresp;
	assign S_AXI_BUSER	= axi_buser;
	assign S_AXI_BVALID	= axi_bvalid;
	assign S_AXI_ARREADY	= axi_arready;
	assign S_AXI_RDATA	= axi_rdata;
	assign S_AXI_RRESP	= axi_rresp;
	assign S_AXI_RLAST	= axi_rlast;
	assign S_AXI_RUSER	= axi_ruser;
	assign S_AXI_RVALID	= axi_rvalid;
	assign S_AXI_BID = S_AXI_AWID;
	assign S_AXI_RID = S_AXI_ARID;
	assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen)); 
	assign  ar_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_arlen)); 
	assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;
	assign  ar_wrap_en = ((axi_araddr & ar_wrap_size) == ar_wrap_size)? 1'b1: 1'b0;

	// Implement axi_awready generation

	// 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       
	// Implement axi_awaddr latching

	// This process is used to latch the address when both 
	// S_AXI_AWVALID and S_AXI_WVALID are valid. 

	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awaddr <= 0;
	      axi_awlen_cntr <= 0;
	      axi_awburst <= 0;
	      axi_awlen <= 0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
	        begin
	          // address latching 
	          axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];  
	           axi_awburst <= S_AXI_AWBURST; 
	           axi_awlen <= S_AXI_AWLEN;     
	          // start address of transfer
	          axi_awlen_cntr <= 0;
	        end   
	      else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)        
	        begin

	          axi_awlen_cntr <= axi_awlen_cntr + 1;

	          case (axi_awburst)
	            2'b00: // fixed burst
	            // The write address for all the beats in the transaction are fixed
	              begin
	                axi_awaddr <= axi_awaddr;          
	                //for awsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst
	            // The write address for all the beats in the transaction are increments by awsize
	              begin
	                axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //awaddr aligned to 4 byte boundary
	                axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst
	            // The write address wraps when the address reaches wrap boundary 
	              if (aw_wrap_en)
	                begin
	                  axi_awaddr <= (axi_awaddr - aw_wrap_size); 
	                end
	              else 
	                begin
	                  axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                  axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}}; 
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //for awsize = 4 bytes (010)
	              end
	          endcase              
	        end
	    end 
	end       
	// Implement axi_wready generation

	// 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       
	// Implement write response logic generation

	// The write response and response valid signals are asserted by the slave 
	// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
	// This marks the acceptance of address and indicates the status of 
	// write transaction.

	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   
	// Implement axi_arready generation

	// axi_arready is asserted for one S_AXI_ACLK clock cycle when
	// 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       
	// Implement axi_araddr latching

	//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[C_S_AXI_ADDR_WIDTH - 1:0]; 
	          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[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {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[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_araddr <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB]+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       
	// Implement axi_arvalid generation

	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	// data are available on the axi_rdata bus at this instance. The 
	// assertion of axi_rvalid marks the validity of read data on the 
	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
	// cleared to zero on reset (active low).  

	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    
	// ------------------------------------------
	// -- Example code to access user logic memory region
	// ------------------------------------------

	generate
	  if (USER_NUM_MEM >= 1)
	    begin
	      assign mem_select  = 1;
	      assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
	    end
	endgenerate
	     
	// 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 [8-1:0] data_in ;
	        wire [8-1:0] data_out;
	        reg  [8-1:0] byte_ram [0 : 15];
	        integer  j;
	     
	        //assigning 8 bit data
	        assign data_in  = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
	        assign data_out = byte_ram[mem_address];
	     
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_wren && S_AXI_WSTRB[mem_byte_index])
	            begin
	              byte_ram[mem_address] <= data_in;
	            end   
	        end    
	      
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_rden)
	            begin
	              mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
	            end   
	        end    
	               
	    end
	  end       
	endgenerate
	//Output register or memory read data

	always @( mem_data_out, axi_rvalid)
	begin
	  if (axi_rvalid) 
	    begin
	      // Read address mux
	      axi_rdata <= mem_data_out[0];
	    end   
	  else
	    begin
	      axi_rdata <= 32'h00000000;
	    end       
	end    

	// Add user logic here

	// User logic ends

	endmodule

(D)顶层模块
作用:例化读写控制模块,主机和从机代码。

module AXI_full_top(
    input   M_AXI_ACLK      ,      
    input   M_AXI_ARESETN   ,
    input   WR_START
    );
    //主机参数
    //parameter           C_M_TARGET_SLAVE_BASE_ADDR	= 32'h4000_0000 ;
    parameter integer   C_M_AXI_BURST_LEN	        = 15            ;           //突发长度要大于2,且为2的幂次方4,8,16,32,64,256,512
    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	        = 32            ;
    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    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_AWID      ;	
    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    ;	
    wire    [3 : 0]                         M_AXI_AWCACHE   ;	
    wire    [2 : 0]                         M_AXI_AWPROT    ;	
    wire    [3 : 0]                         M_AXI_AWQOS     ;	
    wire    [C_M_AXI_AWUSER_WIDTH-1 : 0]    M_AXI_AWUSER    ;	
    wire                                    M_AXI_AWVALID   ;	
    wire                                    M_AXI_AWREADY   ;	
    //写数据通道
    wire    [C_M_AXI_DATA_WIDTH-1 : 0]      M_AXI_WDATA     ;	
    wire    [C_M_AXI_DATA_WIDTH/8-1 : 0]    M_AXI_WSTRB     ;	
    wire                                    M_AXI_WLAST     ;	
    wire    [C_M_AXI_WUSER_WIDTH-1 : 0]     M_AXI_WUSER     ;	
    wire                                    M_AXI_WVALID    ;	
    wire                                    M_AXI_WREADY    ;	
    //写相应通道
    wire    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_BID       ;
    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      ;	
    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    ;	
    wire    [3 : 0]                         M_AXI_ARCACHE   ;	
    wire    [2 : 0]                         M_AXI_ARPROT    ;	
    wire    [3 : 0]                         M_AXI_ARQOS     ;	
    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       ;
    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	;	
    //读写数据控制端口
    wire 									write_flag		;	
    wire 									read_flag		;	
    wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_AWADDR_r	;	
    wire	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r	;	
    wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_ARADDR_r  ;	


    /*********************例化读写控制模块*********************/
    write_read_data
    #(
        .C_M_AXI_BURST_LEN	        (C_M_AXI_BURST_LEN  ),           //突发长度
        .C_M_AXI_ADDR_WIDTH	        (C_M_AXI_ADDR_WIDTH ),           //数据地址位宽
		.C_M_AXI_DATA_WIDTH	        (C_M_AXI_DATA_WIDTH )            //数据位宽
    )
    u_write_read_data
    (
        .M_AXI_ACLK             (M_AXI_ACLK         ),
        .M_AXI_ARESETN          (M_AXI_ARESETN      ),
        //读写总开始标志信号
        .WR_START               (WR_START           ),  
        //写数据地址端口
        .write_flag             (write_flag         ),           //写数据开始标志信号
        .M_AXI_AWADDR_r         (M_AXI_AWADDR_r     ),           //写的数据首地址
        .M_AXI_AWVALID          (M_AXI_AWVALID      ),           //主机写数据地址有效标志
        .M_AXI_AWREADY          (M_AXI_AWREADY      ),           //从机写数据地址准备好信号
        //写数据端口
        .M_AXI_WVALID           (M_AXI_WVALID       ),           //主机写数据有效信号       
        .M_AXI_WREADY           (M_AXI_WREADY       ),           //从机写数据准备好信号
        .M_AXI_WLAST            (M_AXI_WLAST        ),           //主机写数据最后一个标志信号
        .M_AXI_WDATA_r          (M_AXI_WDATA_r      ),
        //读数据地址端口
        .read_flag              (read_flag          ),            //读数据开始标志信号
        .M_AXI_ARADDR_r         (M_AXI_ARADDR_r     ),            //读的数据首地址     
        
        .M_AXI_RLAST            (M_AXI_RLAST        )
    );
    /********************例化Full_axi_主机********************/
    AXI_full_M
    #(
		//.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_M
    (
		.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   ),	//突发模式选择,00为固定地址,01为自增地址突发
		.M_AXI_AWLOCK    (M_AXI_AWLOCK    ),	//锁信号一般不用,保持为0
		.M_AXI_AWCACHE   (M_AXI_AWCACHE   ),	//缓存模式,有多种,这里使用无缓存模式
		.M_AXI_AWPROT    (M_AXI_AWPROT    ),	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		.M_AXI_AWQOS     (M_AXI_AWQOS     ),	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		.M_AXI_AWREGION  (M_AXI_AWREGION  ),
        .M_AXI_AWUSER    (M_AXI_AWUSER    ),	//区域标识符,这里没用,默认0值
		.M_AXI_AWVALID   (M_AXI_AWVALID   ),	//写地址有效信号
		.M_AXI_AWREADY   (M_AXI_AWREADY   ),	//应答信号是从机输入的不需要控制
		//写数据通道
		.M_AXI_WDATA     (M_AXI_WDATA     ),	//写的数据
		.M_AXI_WSTRB     (M_AXI_WSTRB     ),	//掩码信号,每8位数据就对应一位掩码信号,掩码信号为高时,数据才能正常传输
		.M_AXI_WLAST     (M_AXI_WLAST     ),	//写数据最后一个数据标志信号
		.M_AXI_WUSER     (M_AXI_WUSER     ),	//用户自定义信号
		.M_AXI_WVALID    (M_AXI_WVALID    ),	//写数据有效信号
		.M_AXI_WREADY    (M_AXI_WREADY    ),	//从机准备好信号是从从机输入的
		//写相应通道
		.M_AXI_BID       (M_AXI_BID       ),
		.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   ),	//突发模式选择,00为固定地址,01为自增地址突发
		.M_AXI_ARLOCK    (M_AXI_ARLOCK    ),	//锁信号一般不用,保持为0
		.M_AXI_ARCACHE   (M_AXI_ARCACHE   ),	//缓存模式,有多种,这里使用无缓存模式
		.M_AXI_ARPROT    (M_AXI_ARPROT    ),	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		.M_AXI_ARQOS     (M_AXI_ARQOS     ),	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		.M_AXI_ARREGION  (M_AXI_ARREGION  ),
        .M_AXI_ARUSER    (M_AXI_ARUSER    ),	//区域标识符,这里没用,默认0值
		.M_AXI_ARVALID   (M_AXI_ARVALID   ),	//读地址有效信号
		.M_AXI_ARREADY   (M_AXI_ARREADY   ),	//应答信号是从机输入的不需要控制
		//读数据通道
		.M_AXI_RID       (M_AXI_RID       ),
		.M_AXI_RDATA     (M_AXI_RDATA     ),	//读入数据
		.M_AXI_RRESP     (M_AXI_RRESP     ),
		.M_AXI_RLAST     (M_AXI_RLAST     ),	//从机数据的读数据LAST信号
		.M_AXI_RUSER     (M_AXI_RUSER     ),
		.M_AXI_RVALID    (M_AXI_RVALID    ),	//从机输入的读数据准备好信号
		.M_AXI_RREADY	 (M_AXI_RREADY	 ),	//读数据通道主机准备好信号
		//读写数据控制端口
		.write_flag		(write_flag		),	//写操作标志信号	
		.read_flag		(read_flag		),	//读操作标志信号
		.M_AXI_AWADDR_r	(M_AXI_AWADDR_r	),	//写数据地址寄存
		.M_AXI_WDATA_r	(M_AXI_WDATA_r	),	//写数据赋值寄存器
		.M_AXI_ARADDR_r	(M_AXI_ARADDR_r	)	//读数据地址寄存
	);

    //例化AXI从机
    AXI_full_slave 
    #(
        .C_S_AXI_ID_WIDTH	    (C_M_AXI_ID_WIDTH       ),
		.C_S_AXI_DATA_WIDTH	    (C_M_AXI_DATA_WIDTH     ),
		.C_S_AXI_ADDR_WIDTH	    (C_M_AXI_ADDR_WIDTH     ),
		.C_S_AXI_AWUSER_WIDTH	(C_M_AXI_AWUSER_WIDTH   ),
		.C_S_AXI_ARUSER_WIDTH	(C_M_AXI_ARUSER_WIDTH   ),
		.C_S_AXI_WUSER_WIDTH	(C_M_AXI_WUSER_WIDTH    ),
		.C_S_AXI_RUSER_WIDTH	(C_M_AXI_RUSER_WIDTH    ),
		.C_S_AXI_BUSER_WIDTH	(C_M_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                 (M_AXI_AWREGION     ),        
        .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                 (M_AXI_ARREGION  ),
        .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

(E)testbench
作用:产生时钟,复位和总的读写开始信号WR_START,并例化顶层模块。

`timescale 1ns / 1ps
module AXI_full_tb;
    reg         M_AXI_ACLK      ;
    reg         M_AXI_ARESETN   ;
    reg         WR_START        ;

    parameter   T = 20;
    initial begin
        M_AXI_ACLK      =   1'b0;    
        M_AXI_ARESETN   =   1'b0;
        WR_START        =   1'b0;
        #(2*T);
        M_AXI_ARESETN   =   1'b1;
        #(10*T);
        WR_START        =   1'b1;
        #(T);
        WR_START        =   1'b0;
    end

    always#(T/2) M_AXI_ACLK = !M_AXI_ACLK;
    AXI_full_top u_AXI_full_top(
        .M_AXI_ACLK             (M_AXI_ACLK      ),      
        .M_AXI_ARESETN          (M_AXI_ARESETN   ),
        .WR_START               (WR_START        )
    );
endmodule

(4)仿真结果

写数据时序:
在这里插入图片描述
读数据时序:
在这里插入图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AMBA协议是指Advanced Microcontroller Bus Architecture(高级微控制器总线结构)协议,其中包括多个不同的总线协议,用于在现代SoC(系统级芯片)设计中实现高效的内部通信。其中,AMBA的第四代是AXI(Advanced eXtensible Interface)协议。 AXI协议是AMBA协议中的一种,被广泛应用于现代SoC设计中。它提供了一种高性能,灵活且可扩展的总线接口,用于在处理器、外设设备和内存之间进行高效的数据传输。AXI协议具有多个特性,包括支持高带宽、流水线设计、分层模型和端到端数据保护等。 AXI协议的主要特点包括: 1. 高带宽:AXI协议支持高频率的数据传输,能够满足现代SoC设计对于大量数据的处理需求。 2. 流水线设计:AXI协议使用流水线技术,可以同时进行多个传输操作,提高了总线的效率和吞吐量。 3. 分层模型:AXI协议采用分层的结构,可以灵活地连接多个从属设备,并支持多个处理器之间的共享内存访问。 4. 端到端数据保护:AXI协议引入了一些机制,如校验和和错误检测,以确保数据在传输过程中的完整性和可靠性。 总的来说,AMBA协议中的AXI协议是一种用于现代SoC设计的高性能、灵活和可扩展的总线接口协议,通过提供高带宽、流水线设计和端到端数据保护等特性,满足了现代SoC设计对于高效数据传输的需求。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [AMBA协议- AXI协议指南(1)](https://blog.csdn.net/ygyglg/article/details/129937804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值