赞
踩
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实现,有需要补充预备知识的提前看看。
最终设计支持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口,大概如下图。
然后对TOP编写tb仿真,tb里主要产生clk,rst即可,过于简单,这里就不放了。直接看波形。
先看与写相关的通道:可以看到在设置Burst_len为16时,满足握手要求,当AWVALID和AWREADY握手,成功写入1~16,并在最后一个数据处产生WLAST信号,成功后产生BVALID,且BRESP为Okay。
再看与读相关的通道:当ARVALID和ARREADY握手,且RVALID和RREADY握手时,成功读出1~16,并在最后一个数据处产生RLAST信号。但这里发现1)RVALID和RREADY握手时总是会产生间断,这是由于Xilinx 的IP自身问题产生的,因为RVALID对于咱们的接口来说是输入。2)最后读出的数据多了一个,这应该也是由于Xilinx 的IP自身问题产生的。总之咱们的Master接口实现是没有问题的。
最后验证对于其他的Burst_len都是成功的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。