手撕AXI-Full总线接口,实现AXI_Full Master接口

一、AXI介绍

AXI全称Advanced eXtensible Interface,属于AMBA总线中的一种,由ARM公司制定。目前主流的包括AXI3和AXI4,其中AXI4又包括AXI4_Lite、AXI4_Full以及AXI4_Stream。本文是基于Xilinx AXI4 IP实现AXI4_FULL Master控制接口。

AXI协议是基于突发传输的,意味着只需要告诉首地址以及突发大小等信息即可实现数据传输。AXI_Full包括五个独立的通道
1)读地址通道;
2)读数据通道;
3)写地址通道;
4)写数据通道;
5)写响应通道。
具体的通道信号可以参考ARM官网文档,此处不列举,重点在Verilog实现,有需要补充预备知识的提前看看。

二、Verilog实现

最终设计支持Burst_len为1、2、4、8、16、32、64、128、256的传输,在地址0处写入1-16,产生Wlast,然后又在地址0处读出1-16,接收Rlast。重点在控制每个通道的Valid和Ready信号,产生写地址AWADDR、写数据WDATA、读地址ARADDR。
1)接口信号
参考Xilinx的IP,端口信号基本不变,全部复制即可,这里就不放了。
2)时序逻辑
这部分代码主要就是控制寄存器类型的Valid和Ready信号的产生,以及Waddr、Raddr和Wdata、Wlast的产生。这里需要重点关注WLAST的产生,为了支持Burst_len长度从1~256,这里对Burst_len进行判断,最终真正的WLAST信号由组合逻辑部分选择产生。

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || (M_AXI_AWVALID && M_AXI_AWREADY))
		r_m_axi_awvalid <= 'd0;
	else if(r_m_axi_wstart)
		r_m_axi_awvalid <= 'd1;
	else
		r_m_axi_awvalid <= r_m_axi_awvalid;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_awaddr <= 'd0;
	else if(r_m_axi_wstart)
		r_m_axi_awaddr <= 'd0;
	else
		r_m_axi_awaddr <= 'd0;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || M_AXI_WLAST)
		r_m_axi_wvalid <= 'd0;
	else if(M_AXI_AWVALID && M_AXI_AWREADY)
		r_m_axi_wvalid <= 'd1;
	else
		r_m_axi_wvalid <= r_m_axi_wvalid;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || M_AXI_WLAST)
		r_m_axi_wdata <= 'd1;
	else if(M_AXI_WVALID && M_AXI_WREADY)
		r_m_axi_wdata <= r_m_axi_wdata + 1;
	else
		r_m_axi_wdata <= r_m_axi_wdata;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_wlast <= 'd0;
	else if(C_M_AXI_BURST_LEN == 1)
		r_m_axi_wlast <= 'd0;
	else if(C_M_AXI_BURST_LEN == 2 && (M_AXI_WVALID && M_AXI_WREADY && !r_m_axi_wlast))
		r_m_axi_wlast <= M_AXI_WVALID && M_AXI_WREADY;
	else if(C_M_AXI_BURST_LEN > 2 && r_burst_cnt == C_M_AXI_BURST_LEN-2)
		r_m_axi_wlast <= 'd1;
	else
		r_m_axi_wlast <= 'd0;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || M_AXI_WLAST)
		r_burst_cnt <= 'd0;
	else if(M_AXI_WVALID && M_AXI_WREADY)
		r_burst_cnt <= r_burst_cnt + 1;
	else
		r_m_axi_wlast <= r_burst_cnt;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || (M_AXI_ARVALID && M_AXI_ARREADY))
		r_m_axi_arvalid <= 'd0;
	else if(r_m_axi_rstart)
		r_m_axi_arvalid <= 'd1;
	else
		r_m_axi_arvalid <= 'd0;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_araddr <= 'd0;
	else if(r_m_axi_rstart)
		r_m_axi_araddr <= 'd0;
	else
		r_m_axi_araddr <= 'd0;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN || M_AXI_RLAST)
		r_m_axi_rready <= 'd0;
	else if(M_AXI_ARVALID && M_AXI_ARREADY)
		r_m_axi_rready <= 'd1;
	else
		r_m_axi_rready <= r_m_axi_rready;

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_rdata <= 'd0;
	else if(M_AXI_RVALID && M_AXI_RREADY)
		r_m_axi_rdata <= M_AXI_RDATA;
	else
		r_m_axi_rdata <= r_m_axi_rdata;

3)组合逻辑
这部分就是第一部分接口信号的输出逻辑。这里的clog2b为自己写的求数据位宽的函数。注意真正写入的地址是要加上一个基地址的。

assign M_AXI_AWID    = 'd0                              ;
assign M_AXI_AWLEN   = C_M_AXI_BURST_LEN                ;
assign M_AXI_AWSIZE  = clog2b(C_M_AXI_DATA_WIDTH/8 - 1) ;
assign M_AXI_AWBURST = 2'b01                            ;
assign M_AXI_AWLOCK  = 'd0                              ;
assign M_AXI_AWCACHE = 4'b0010                          ;
assign M_AXI_AWPROT  = 'd0                              ;
assign M_AXI_AWQOS   = 'd0                              ;
assign M_AXI_AWUSER  = 'd0                              ;
assign M_AXI_AWADDR  = r_m_axi_awaddr + C_M_TARGET_SLAVE_BASE_ADDR ;
assign M_AXI_AWVALID = r_m_axi_awvalid                  ;

assign M_AXI_WSTRB  = {C_M_AXI_DATA_WIDTH/8{1'b1}}      ;
assign M_AXI_WUSER  = 'd0                               ;
assign M_AXI_WDATA  = r_m_axi_wdata                     ;
assign M_AXI_WLAST  = (C_M_AXI_BURST_LEN == 1) ? w_write_last : r_m_axi_wlast ;
assign M_AXI_WVALID = r_m_axi_wvalid                    ;

assign M_AXI_BREADY = 1'b1								;

assign M_AXI_ARID    = 'd0                              ;
assign M_AXI_ARADDR  = r_m_axi_araddr + C_M_TARGET_SLAVE_BASE_ADDR ;
assign M_AXI_ARLEN   = C_M_AXI_BURST_LEN                ;
assign M_AXI_ARSIZE  = clog2b(C_M_AXI_DATA_WIDTH/8 - 1) ;
assign M_AXI_ARBURST = 2'b01                            ;
assign M_AXI_ARLOCK  = 'd0                              ;
assign M_AXI_ARCACHE = 4'b0010                          ;
assign M_AXI_ARPROT  = 'd0                              ;
assign M_AXI_ARQOS   = 'd0                              ;
assign M_AXI_ARUSER  = 'd0                              ;
assign M_AXI_ARVALID = r_m_axi_arvalid                  ;

assign M_AXI_RREADY  = r_m_axi_rready                   ;

assign w_write_last = M_AXI_WVALID && M_AXI_WREADY		;

4)状态机
这里对写逻辑和读逻辑采用了两个FSM进行控制,产生写开始Wstart和读开始Rstart信号。写读共有7个状态。

/************************状态机*************************/
always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_write_current <= P_ST_IDLE;
	else
		r_m_write_current <= r_m_write_next;

always@(*)
	case(r_m_write_current)
		P_ST_IDLE       : r_m_write_next = P_ST_WRITE_START;
		P_ST_WRITE_START: r_m_write_next = r_m_axi_wstart ? P_ST_WRITE_TRANS : P_ST_WRITE_START;
		P_ST_WRITE_TRANS: r_m_write_next = M_AXI_WLAST ? P_ST_WRITE_END : P_ST_WRITE_TRANS;
		P_ST_WRITE_END  : r_m_write_next = (r_m_read_current == P_ST_READ_END) ? P_ST_IDLE : P_ST_WRITE_END;
		default         : r_m_write_next = P_ST_IDLE;
	endcase

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_wstart <= 'd0;
	else if(r_m_write_current == P_ST_WRITE_START)
		r_m_axi_wstart <= 'd1;
	else
		r_m_axi_wstart <= 'd0;

/************************状态机*************************/
always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_read_current <= P_ST_IDLE;
	else
		r_m_read_current <= r_m_read_next;

always@(*)
	case(r_m_read_current)
		P_ST_IDLE      : r_m_read_next = (r_m_write_current == P_ST_WRITE_END) ? P_ST_READ_START : P_ST_IDLE;
		P_ST_READ_START: r_m_read_next = r_m_axi_rstart ? P_ST_READ_TRANS : P_ST_READ_START;
		P_ST_READ_TRANS: r_m_read_next = M_AXI_RLAST ? P_ST_READ_END : P_ST_READ_TRANS;
		P_ST_READ_END  : r_m_read_next = P_ST_IDLE;
		default        : r_m_read_next = P_ST_IDLE;
	endcase

always@(posedge M_AXI_ACLK)
	if(!M_AXI_ARESETN)
		r_m_axi_rstart <= 'd0;
	else if(r_m_read_current == P_ST_READ_START)
		r_m_axi_rstart <= 'd1;
	else
		r_m_axi_rstart <= 'd0;

三、仿真验证

验证采用在TOP模块里例化一个Xilinx 的AXI4_Full IP以及咱们自己写的Master接口,将咱们的信号连接到AXI4_Full IP 里的Slave口,大概如下图。
Fig. 1 TOP框图

然后对TOP编写tb仿真,tb里主要产生clk,rst即可,过于简单,这里就不放了。直接看波形。

先看与写相关的通道:可以看到在设置Burst_len为16时,满足握手要求,当AWVALID和AWREADY握手,成功写入1~16,并在最后一个数据处产生WLAST信号,成功后产生BVALID,且BRESP为Okay。
Fig. 2 写通道仿真波形
再看与读相关的通道:当ARVALID和ARREADY握手,且RVALID和RREADY握手时,成功读出1~16,并在最后一个数据处产生RLAST信号。但这里发现1)RVALID和RREADY握手时总是会产生间断,这是由于Xilinx 的IP自身问题产生的,因为RVALID对于咱们的接口来说是输入。2)最后读出的数据多了一个,这应该也是由于Xilinx 的IP自身问题产生的。总之咱们的Master接口实现是没有问题的。
Fig. 3 读通道仿真波形
最后验证对于其他的Burst_len都是成功的。

AXI-Full是Xilinx提供的一种高性能、可扩展的总线协议,用于处理器和外设之间的通信。它是AXI(Advanced eXtensible Interface)协议的一种变体。AXI-Full支持高带宽、低延迟的数据传输,并且能够提供高度的并行性和灵活性。 AXI-Full协议包括多个通道,其中包括写地址通道(AW)、写数据通道(W)、写响应通道(B)、读地址通道(AR)、读数据通道(R)。通信通过这些通道进行,并且每个通道都有相应的握信号。 在AXI-Full协议中,写数据通道的握过程是根据主机给出的握信号来拉高axi_wready信号。当S_AXI_AWVALID和S_AXI_WVALID都被主机拉高时,axi_wready会在一个S_AXI_ACLK时钟周期内被拉高。当重置信号低电平时,axi_wready会被置为低电平。同时,axi_awv_awr_flag信号也被使用来表示从机进入了被写入数据的过程。 而读地址通道的握过程是根据主机给出的握信号来拉高axi_arready信号,并拉高axi_awv_awr_flag信号,表示从机进入了被读取数据的过程。当S_AXI_ARVALID被主机拉高时,axi_arready会在一个S_AXI_ACLK时钟周期内被拉高。当重置信号被拉低时,axi_arready会被置为低电平。同时,axi_arv_arr_flag信号也被使用来指示从机是否接收到了读取地址。 以上是关于AXI-Full协议中写数据通道和读地址通道的握过程的描述。如果您有更多关于AXI-Full协议的问题,或者需要更详细的说明,请告诉我。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [带你快速入门AXI4总线--AXI4-Full篇(2)----XILINX AXI4-Full接口IP源码仿真分析(Slave接口)](https://blog.csdn.net/wuzhikaidetb/article/details/121594798)[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_1"}}] [.reference_item style="max-width: 50%"] - *3* [Designing-a-Custom-AXI-Slave-Peripheral:使用Xilinx Vivado工具创建自定义AXI-lite从属外围设备的指南](https://download.csdn.net/download/weixin_42099906/18652670)[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_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值