AXI4总线学习

IP核选择:AXI BRAM Controller
IP文档:pg078

AXI总线介绍

ARM AMBA(Advance Microcontroller Bus Architecture),是ARM在1996年提出的一个微控制器的片上总线协议,AHB和APB等总线协议都是AMBA的一部分
在这里插入图片描述

AXI总线类型:AXI4、AXI4-Lite、AXI-Stream

  1. AXI4用于高性能内存映射(Menory-Mapped)型的通信,主要用于大块数据的读写,如DDR、BRAM的数据搬移
  2. AXI4-Lite用于简单低吞吐量的内存映射型通信上(比如简单的寄存器读写),主要用于外设模块的配置,状态寄存器的读写等
  3. AXI4-Stream用于高速的数据流传输,无需地址管理,主要用于高速AD数据、视频数据等的传输

关键特点:
1.分离的地址 / 控制、数据相位
2.使用字节线来支持非对齐的数据传输
3.使用基于burst的传输,只需要传输首地址
4.分离的读、写数据通道,提供低功耗DMA
5.支持多种寻址方式
6.支持乱序传输
7.允许容易的添加寄存器级来进行时序收敛

  • AXI总线是点对点的传输协议。总线两端发起读写事务的一端称为主设备,响应事务的一端是从设备。点对点传输意味着本条总线只能用于两个设备间通信,和SPI(图一)等接口不一样,不存在片选从设备这样的机制。中央互联(Interconnect)提供了设备间一对多,多对多的访问能力,可以理解为路由器的作用,AXI可以用在三种接口之间,master/slave,mater/interconnect,master/interconnect
    在这里插入图片描述
    在这里插入图片描述

  • AXI协议是一个读写通道分离的总线协议,数据总线分离,地址和控制总线分分离,这样可以在总线上全双工的读写数据,提高总线带宽。(写事务并不一定非要等地址和控制信号发送以后再发送写数据,AXI允许先发送写数据再发送写地址和写控制;AXI也允许先发送多个写地址和写控制,再慢慢发送写数据,而不是一次地址一次数据这样的传统总线模式。)
    在这里插入图片描述

  • AXI采用握手机制,各个通道都有一对握手信号,valid和ready,只有两个信号都有效时,通道的数据才开始传输,这样AXI总线上的主从设备都能根据自己的情况4控制开启和中断通道的数据传输,双向流控机制

时钟和复位

信号名来源描述
ACLKsystem clk系统时钟
ARESETNsystem rst复位信号低有效,释放的时候要和aclk上升沿同步

AXI的五组独立通道

Write Address Channel 写地址通道

突发传输指的是传输一次起始地址后,进行多次地址上连续的读写操作。

突发方式BURST:
FIXED(固定突发模式):每次突发传输的地址都相同
INCR(增量突发模式):突发传输地址递增,地增量与突发尺寸相关
WRAP(回卷突发模式):突发传输的地址可溢出性递增,突发长度仅支持2、4、8、16.地址空间被划分为长度[ SIZE * LEN ]的块,传输地址不会超出起始地址所在的块,一旦递增超出,则回到该块的起始地址

信号名来源描述
AWIDm写地址ID(用于区分该地址属于哪个写地址组)
AWADDRm写地址
AWLENm突发长度(一次突发传输中数据传输的个数)
AWSIZEm突发尺寸(每次突发传输中数据的位宽)
AWBURSTm突发方式(2’b00 FIXED,2’b01 INCR,2’b10 WRAP)
AWCACHEm存储类型(标记系统需要的传输类型)
AWPROTm保护模式
AWQOSmQoS标识符
AWREGIONmregion标识符(当slave有多种逻辑接口时标识使用的逻辑接口)
AWUSERm用户自定义信号
AWVALIDm写地址有效信号(有效时表示AWADDR上地址有效)
AWREADYs写从机就绪信号(有效时表示从机准备好接收地址)

Write Data Channel 写数据通道

写通道比读通道多了WSTRB信号,用于标识写数据中有效传输的字节,告知从机不需要接收。一次突发传输开启后就不能提前终止,主机可以通过控制WSTRB信号使能部分有效字节,来减少写传输的数量

信号名来源描述
WDATAm写数据
WSTRBm数据段有效(标记写数据有效字节)
WLASTmlast信号(有效时表示当前为突发传输最后一个数据)
WUSERm用户自定义信号
WVALIDm写有效信号(有效时表示WDATA上数据有效)
WREADYs写ready信号(有效时表示从机准备好接收数据)

Write Response Channel 写响应信号

从机将写完成情况回复给主机,针对一次突发传输,而不每一次的写数据操作,一次突发传输可以包括多次写操作

为啥写有响应通道,读没有?
主机在读取数据的时候,数据在读数据通道由从机流向主机,读响应信号也是由从机流向主机,可以合并在一起。主机在写数据的时候,数据在写数据通道由主机流向从机,写回复信号是报告从机写操作的完成情况,由从机流向主机,没办法合并,就单独来一个写响应通道

响应信号RESP:
OKAY(2’b00):正常访问成功
EXOKAY(2’b01):独占访问成功
SLVERR(2’b10):从机错误。表明访问已经成功到了从机,但从机希望返回一个错误的情况给主机。
DECERR(2’b11):译码错误。一般由互联组件给出,表明没有对应的从机地址

信号名来源描述
BIDs响应ID
BRESPs写响应
BUSERs用户自定义信号
BVALIDs写响应信号有效
BREADYm写响应ready(主机准备好接受写响应信号)

Read Address Channel 读地址信号

信号名来源描述
ARIDm读地址ID
ARADDRm读地址
ARLENm突发长度
ARSIZEm突发尺寸(每次突发传输的byte数)
ARBURSTm突发类型(FIXED,INCR,WRAP)
ARCACHEm存储类型
ARPROTm保护类型
ARQOSmQoS标识符
ARREGIONm区域标识符
ARUSERm用户自定义
ARVALIDm读地址有效(有效时表示ARADDR上地址有效)
ARREADYs写有效信号(有效时表示从机准备好接收读地址)

Read Data Channel 读数据信号

信号名来源描述
RIDs读ID标签
RDATAs读数据
RRESPs读响应
RLASTs有效时表示为突发传输的最后一个
RUSERs用户自定义
RVALIDs读数据有效信号
RREADYm主机就绪信号(有效时表示)

读写传输

握手机制

AXI使用基于valid/ready的握手机制数据传输协议。传输源端使用valid表明地址/控制信号、数据是有效的,目的端使用ready表明自己能够接收信息
valid和ready的先后关系有三种:

  1. valid线有效,等待ready有效后完成传输(valid一旦有效后在传输完成前不可取消)
  2. ready先有效,等待valid有效后完成传输(ready可以在valid有效前撤销)
  3. valid和ready同时有效,立刻完成传输
    在这里插入图片描述

写地址通道:当主机驱动有效的地址和控制信号时,主机拉高AWVALID,保持拉高状态,直到时钟上升沿采样到从机的AWREDY。AWREADY信号默认可高可低(如果为低,一次传输至少需要两个周期,一个用来断言AWVALID,一个用来断言AWREADY);其他通道类似的

通道顺序

为了防止死锁,传输通道规定了先后顺序

  1. 写响应通道传输必须在写操作完成以后进行
  2. 读数据通道传输必须在读地址通道传输后进行
  3. 必须遵循一系列的状态依赖关系

valid信号不能等待ready信号
AXI接口可以检测到valid信号后再拉高ready,也可以检测到valid之前就拉高ready
在这里插入图片描述

数据通道的传输

使用STRB字节选择信号,标志数据中的对应字节是否有效,位宽为[DATA_WITTH / 8 : 0]

支持窄带传输(narrow transfers)。当传输的数据位宽小于xDATA总线带宽时,为窄带传输,每次使用的数据位数不同:

  1. 固定地址的突发下,使用同一段数据信号线
  2. 递增地址的突发下,使用不同段信号线

举例:

  1. 5次突发传,起始地址为0,每次传输为8bit,数据总线为32bit,突发类型为INCR
    在这里插入图片描述
  2. 3次突发,起始地址为4,每次传输32bit,数据总线为64bit,突发类型为INCR
    在这里插入图片描述

支持不对齐传输(Unaligned transfers)。

举例

指定控制为内部Intermal
在这里插入图片描述

`timescale 1ns / 1ps

/*
	data width: 32
	memory depth:262166
	memory width:20
	
*/
module tb_axi4 ( );

	parameter	DATA_WIDTH	=	32;
	parameter	ADDR_WIDTH	=	20;

// global
	reg		aclk	;
	reg		aresetn	;	// 异步复位,低有效

// write address channel
	wire						m_axi_awid		;
	wire	[ADDR_WIDTH	- 1: 0]	m_axi_awaddr	;
	wire				[ 7: 0]	m_axi_awlen		;	// Burst Length:突发传输长度 1~256 len[7:0]+1
	wire				[ 2: 0]	m_axi_awsize	;	// Brust Size:突发尺寸,单次突发传输byte数
	wire				[ 1: 0]	m_axi_awburst	;	// Brust Type:突发类型,FIXED(2'b00),INCR(2'b01),WRAP(2'b10)
	wire						m_axi_awlock	;	// 写地址锁信号,提供原子操作传输和屏障事务的信息
	wire				[ 3: 0]	m_axi_awcache	;
	wire				[ 2: 0]	m_axi_awprot	;
	wire 				[ 3: 0] m_axi_awqos		;
	wire 						m_axi_awuser	;
	wire						m_axi_awvalid	;
	wire						m_axi_awready	;

// write data channel
	wire	[DATA_WIDTH - 1: 0]	m_axi_wdata		;
	wire				[ 3: 0]	m_axi_wstrb		;	// 写字节选择
	wire						m_axi_wlast		;	// 标志突发传输最后一个数据
	wire 						m_axi_wuser		;
	wire						m_axi_wvalid	;
	wire						m_axi_wready	;

// wire response channel
	wire 						m_axi_bid		;
	wire				[ 1: 0]	m_axi_bresp		;
	wire 						m_axi_buser		;
	wire						m_axi_bvalid	;
	wire						m_axi_bready	;

// read address channel
	wire						m_axi_arid		;	
	wire	[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 						m_axi_aruser	;
	wire						m_axi_arvalid	;
	wire						m_axi_arready	;

// read data channel
	wire 						m_axi_rid		;
	wire	[DATA_WIDTH - 1: 0]	s_axi_rdata		;
	wire				[ 1: 0]	m_axi_rresp		;
	wire						m_axi_rlast		;
	wire						m_axi_ruser		;
	wire						m_axi_rvalid	;
	wire						m_axi_rready	;

// user insterface
	reg							master_rst	;
	reg							wr_start	;
	reg		[ADDR_WIDTH - 1: 0]	wr_addrs	;
	reg					[ 7: 0]	wr_len		;
	reg		[DATA_WIDTH - 1: 0]	wr_data		;
	wire						wr_handshake;
	wire						wr_busy		;
	wire						wr_done		;
	
	reg							rd_start	;
	reg		[ADDR_WIDTH - 1: 0]	rd_addrs	;
	reg					[ 7: 0]	rd_len		;
	wire	[DATA_WIDTH - 1: 0]	rd_data		;
	wire						rd_handshake;
	wire						rd_busy		;
	wire						rd_done		;
	
	initial	begin
		aclk	=	0;
		aresetn	=	0;
		
		#100
		aresetn	=	1;		
	end
	
	always # (5)	aclk = ~aclk;
	
	initial	begin
		master_rst	=	0;
		wr_start	=	0;	// 
		wr_addrs	=	0;
		wr_len		=	0;
		wr_data		=	0;
		
		#100
		@(posedge aclk)
		// aresetn	<=	1;
		
		@(posedge aclk)
		wr_addrs	=	0;
		wr_len		=	15; 
		@(posedge aclk)
		if (wr_busy == 1'b0)		// 当前没有写事务
			wr_start	=	1;			// 开启一次写事务
		@(posedge aclk)
		wr_start	=	0;
			
		repeat ( 30)	@(posedge aclk);
		wr_addrs	=	1024;
		wr_len		=	255;
		@(posedge aclk)
		if (wr_busy == 1'b0)
			wr_start	<=	1; 
//		@(posedge aclk)       // 不太理解这里wr_start拉高一拍,不能正常开启写传输.....明明跟第一次写一样,但是这里在时钟上升沿采样不到
//                              其他三次突发开启,start都是拉高一拍,就只有这里偶尔可以偶尔不行
		#11
		wr_start	=	0;
	end
	
	initial	begin
		rd_start	=	0;
		rd_addrs	=	0;
		rd_len		=	0;
		
		repeat (500)	@(posedge aclk)
		@(posedge aclk)
		rd_addrs	=	1024;
		rd_len		=	255;
		@(posedge aclk)
		if (rd_busy == 1'b0)
			rd_start	=	1;
		@(posedge aclk)
		rd_start	=	0;
		
		repeat (300)	@(posedge aclk)
		@(posedge aclk)
		rd_addrs	=	0;
		rd_len		=	15;
		@(posedge aclk)
		if (rd_busy == 1'b0)
			rd_start	=	1;
		@(posedge aclk)
		rd_start	=	0;
	end
	
	always @ (posedge aclk)
		if (wr_handshake)
			wr_data	=	wr_data + 1;


/* AXI WRITE */
	parameter	W_IDLE	=	3'd0,
				WA_WAIT	=	3'd1,	// write address
				WA_START=	3'd2,
				WD_WAIT	=	3'd3,	// wrte data
				WD_PROC	=	3'd4,
				WR_WAIT	=	3'd5,	// write response
				WR_DONE	=	3'd6;
	
	reg					[ 2: 0]	wr_state	;
	reg		[ADDR_WIDTH - 1: 0]	reg_wr_addrs;	// 写地址
	reg					[ 7: 0]	reg_wr_len	;	// 突发长度
	reg							reg_awvalid	;	// 写地址有效
	reg							reg_wvalid	;	// 写数据有效
	reg							reg_w_last	;
	
	// write state
	always @ (posedge aclk)
		if (aresetn == 1'b0)
			begin
				wr_state	<=	W_IDLE;
				reg_wr_addrs<=	0;
				reg_wr_len	<=	0;
				reg_awvalid	<=	0;
				reg_wvalid	<=	0;
				reg_w_last	<=	0;
			end
		else
			begin
				if (master_rst)		// 主机复位
					wr_state	<=	W_IDLE;
				else
					begin
						case (wr_state)
							W_IDLE:		begin
								if (wr_start)		// 开启一次写事务
									begin
										wr_state	<=	WA_WAIT;
										reg_wr_addrs<=	wr_addrs;
										reg_wr_len	<=	wr_len;
									end
								reg_awvalid	<=	0;
								reg_wvalid	<=	0;
								reg_w_last	<=	0;
							end
							WA_WAIT:	begin
								wr_state	<=	WA_START;
							end
							WA_START:	begin		// 拉高写地址有效信号
								wr_state	<=	WD_WAIT;
								reg_awvalid	<=	1;
							end
							WD_WAIT:	begin		// 从机响应写地址,拉低写地址有效信号,拉高数据有效信号
								if (m_axi_awvalid && m_axi_awready)
									begin
										wr_state	<=	WD_PROC;
										reg_awvalid	<=	0;
										reg_wvalid	<=	1;
									end
							end
							WD_PROC:	begin		// 突发传输len次
								if (m_axi_wvalid && m_axi_wready)
									begin
										if (reg_wr_len == 0)
											begin
												wr_state	<=	WR_WAIT;
												reg_wvalid	<=	0;
											end
										else
											reg_wr_len	<=	reg_wr_len - 1;
										if (reg_wr_len == 1)
											reg_w_last	<=	1;
										else
											reg_w_last	<=	0;
									end
							end
							WR_WAIT:	begin		// 等待写相应通道信号握手
								if (m_axi_bvalid && m_axi_bready)
									wr_state	<=	WR_DONE;
							end
							WR_DONE:	begin
								wr_state	<=	W_IDLE;
							end
							default:	begin
								wr_state	<=	W_IDLE;
							end
						endcase
					end
			end	

	// assign m-AXI interface
	// aw写地址
	assign	m_axi_awid		=	1'b0;		// default value
	assign	m_axi_awaddr	=	reg_wr_addrs;
	assign	m_axi_awlen		=	reg_wr_len;
	assign	m_axi_awsize	=	$clog2(DATA_WIDTH / 8);	// 4byte
	assign	m_axi_awburst	=	2'b01;		// default value	增量突发
	assign	m_axi_awlock	=	1'b0;		// default value
	assign	m_axi_awcache	=	4'b0011;	// default value
	assign	m_axi_awprot	=	3'b000;		// default value
	assign	m_axi_awqos		=	4'b0000;	// default value	QOS标识符
	assign	m_axi_awuser	=	1'b0;		// default value	用户自定义
	assign	m_axi_awvalid		=	reg_awvalid;
	// w写数据
	assign	m_axi_wdata		=	wr_data;
	assign	m_axi_wstrb		=	{$clog2(DATA_WIDTH / 8){1'b1}};
	assign	m_axi_wlast		=	reg_w_last;
	assign	m_axi_wuser		=	1'b0;		// default value
	assign	m_axi_wvalid	=	reg_wvalid;
	// b写响应
	assign	m_axi_bready	=	m_axi_bvalid;
	// user interface
	assign	wr_handshake	=	m_axi_wvalid & m_axi_wready;
	assign	wr_busy			=	(wr_state != W_IDLE);
	assign	wr_done			=	(wr_state == WR_DONE);

/* ASI READ */
	parameter	R_IDLE	=	3'd0,
				RA_WAIT	=	3'd1,
				RA_START=	3'd2,
				RD_WAIT	=	3'd3,
				RD_PROC	=	3'd4,
				RD_DONE	=	3'd5;
				
	reg					[ 2: 0]	rd_state	;
	reg		[ADDR_WIDTH - 1: 0]	reg_rd_addrs;
	reg					[ 7: 0]	reg_rd_len	;
	reg							reg_arvalid	;
	reg							reg_r_last	;

	// read state
	always @ (posedge aclk or negedge aresetn)
		if (aresetn == 1'b0)
			begin
				rd_state	<=	R_IDLE;
				reg_rd_addrs<=	0;
				reg_rd_len	<=	0;
				reg_arvalid	<=	0;
			end
		else
			begin
				case (rd_state)
					R_IDLE:		begin
						if (rd_start)
							begin
								rd_state	<=	RA_WAIT;
								reg_rd_addrs<=	rd_addrs;
								reg_rd_len	<=	rd_len;
							end
						reg_arvalid	<=	0;
					end
					RA_WAIT:	begin
						rd_state	<=	RA_START;
					end
					RA_START:	begin
						rd_state	<=	RD_WAIT;
						reg_arvalid	<=1;
					end
					RD_WAIT:	begin
						if (m_axi_arvalid && m_axi_arready)
							begin
								rd_state	<=	RD_PROC;
								reg_arvalid	<=	0;
							end
					end
					RD_PROC:	begin
						if (m_axi_rvalid && m_axi_rready)
							begin
								if (m_axi_rlast && reg_r_last)
									rd_state	<=	RD_DONE;
								else
									reg_rd_len	<=	reg_rd_len - 1;
								if (reg_rd_len == 1)
									reg_r_last	=	1;
								else
									reg_r_last	=	0;
							end
					end
					RD_DONE:	begin
						rd_state	<=	R_IDLE;
					end
					default:	begin
						rd_state	<=	R_IDLE;
					end
					
					
				endcase
			end
			
	// assign m-AXI interface
	// ar读地址
	assign	m_axi_arid	=	1'b0;			// default value
	assign	m_axi_araddr	=	reg_rd_addrs;
	assign	m_axi_arlen		=	reg_rd_len;
	assign	m_axi_arsize	=	$clog2(DATA_WIDTH / 8);
	assign	m_axi_arburst	=	2'b01;		// default value
	assign	m_axi_arlock	=	1'b0;		// default value
	assign	m_axi_arcache	=	4'b0011;	// default value
	assign	m_axi_arprot	=	3'b000;		// default value
	assign	m_axi_arqos		=	4'b0000;	// default value
	assign	m_axi_aruser	=	1'b0;		// default value
	assign	m_axi_arvalid	=	reg_arvalid;
	// r读数据
	assign	m_axi_rready	=	m_axi_rvalid;
	// user interface
	assign	rd_handshake	=	m_axi_rvalid && m_axi_rready;
	assign	rd_busy			=	(rd_state != R_IDLE);
	assign	rd_done			=	(rd_state == RD_DONE);

// inst
	// io相对于从机来说 //
	axi_bram_ctrl_0m axi4_inst (
		// global
		.s_axi_aclk		(aclk		),	// input wire s_axi_aclk
		.s_axi_aresetn	(aresetn	),	// input wire s_axi_aresetn
		
		// write address channel
		.s_axi_awaddr	(m_axi_awaddr	),	// i
		.s_axi_awlen	(m_axi_awlen	),	// i
		.s_axi_awsize	(m_axi_awsize	),	// i
		.s_axi_awburst	(m_axi_awburst	),	// i
		.s_axi_awlock	(m_axi_awlock	),	// i
		.s_axi_awcache	(m_axi_awcache	),	// i
		.s_axi_awprot	(m_axi_awprot	),	// i
		.s_axi_awvalid	(m_axi_awvalid	),	// i
		.s_axi_awready	(m_axi_awready	),	// o
		
		// write data channel
		.s_axi_wdata	(m_axi_wdata	),	// i
		.s_axi_wstrb	(m_axi_wstrb	),	// i
		.s_axi_wlast	(m_axi_wlast	),	// i
		.s_axi_wvalid	(m_axi_wvalid	),	// i
		.s_axi_wready	(m_axi_wready	),	// o
		
		// write response channel
		.s_axi_bresp	(m_axi_bresp	),	// o
		.s_axi_bvalid	(m_axi_bvalid	),	// o
		.s_axi_bready	(m_axi_bready	),	// i
		
		// read address channel
		.s_axi_araddr	(m_axi_araddr	),	// i
		.s_axi_arlen	(m_axi_arlen	),	// i
		.s_axi_arsize	(m_axi_arsize	),	// i
		.s_axi_arburst	(m_axi_arburst	),	// i
		.s_axi_arlock	(m_axi_arlock	),	// i
		.s_axi_arcache	(m_axi_arcache	),	// i
		.s_axi_arprot	(m_axi_arprot	),	// i
		.s_axi_arvalid	(m_axi_arvalid	),	// i
		.s_axi_arready	(m_axi_arready	),	// o
		
		// read data channel
		.s_axi_rdata	(s_axi_rdata	),	// o
		.s_axi_rresp	(m_axi_rresp	),	// o
		.s_axi_rlast	(m_axi_rlast	),	// o
		.s_axi_rvalid	(m_axi_rvalid	),	// o
		.s_axi_rready	(m_axi_rready	)	// i
);

endmodule

写事务
在这里插入图片描述

在这里插入图片描述

对比文档的写事务时序,是对应的
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值