当前位置:   article > 正文

手撕AXI-Full总线接口,实现AXI_Full Master接口_axi full master读写接口

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

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		;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

三、仿真验证

验证采用在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都是成功的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/217991
推荐阅读
  

闽ICP备14008679号