05 AXI4总线axi-full-master
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA
登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述
关于AXI4总线协议的部分介绍请阅读"01AXI4总线axi-lite-slave"。
2:掌握通过VIVADO工具产生AXI-full-master代码
3:理解AXI-full-master中自定义寄存器的地址分配
4:掌握通过VIVADO封装AXI-full-slave图形化IP
5:通过仿真验证AXI-full-master IP的工作是否正常。
2创建axi4-full-master总线接口IP
新建完成工程后,单击菜单栏Tools->Create and Package New IP,开始创建一个AXI4-Full接口总线IP
选择使用vivado自带的AXI总线模板创建一个AXI4-FULL接口IP
模板支持3种协议,分别是AXI4-Full ,AXI4-Lite ,AXI4-Stream,这选择Full;总线包括Master和Slave两种模式,这里选择Master模式
这里选择Verify Peripheral IP using AXI4 VIP可以对AXI4-Lite快速验证
3程序分析
1:产生初始化信号
//Generate a pulse to initiate AXI transaction. always @(posedge M_AXI_ACLK) begin // Initiates AXI transaction delay if (M_AXI_ARESETN == 0 ) begin init_txn_ff <= 1'b0; init_txn_ff2 <= 1'b0; end else begin init_txn_ff <= INIT_AXI_TXN; init_txn_ff2 <= init_txn_ff; end end |
2:axi-full-master的axi_awvalid
当(~axi_awvalid && start_single_burst_write)==1条件满足,开始一次写传输,设置axi_awvalid有效。
always @(posedge M_AXI_ACLK) begin
if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_awvalid <= 1'b0; end // If previously not valid , start next transaction else if (~axi_awvalid && start_single_burst_write) begin axi_awvalid <= 1'b1; end /* Once asserted, VALIDs cannot be deasserted, so axi_awvalid must wait until transaction is accepted */ else if (M_AXI_AWREADY && axi_awvalid) begin axi_awvalid <= 1'b0; end else axi_awvalid <= axi_awvalid; end |
3:axi-full-slave的axi_awaddr
写通道地址每当M_AXI_AWREADY && axi_awvalid地址加1
// Next address after AWREADY indicates previous address acceptance always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_awaddr <= 'b0; end else if (M_AXI_AWREADY && axi_awvalid) begin axi_awaddr <= axi_awaddr + burst_size_bytes; end else axi_awaddr <= axi_awaddr; end |
4:axi-full-master的axi_wvalid
设置axi_wvalid <= 1'b1开始写数据。wnext信号有效代码axi_full_master写数据有效。
assign wnext = M_AXI_WREADY & axi_wvalid;
// WVALID logic, similar to the axi_awvalid always block above always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_wvalid <= 1'b0; end // If previously not valid, start next transaction else if (~axi_wvalid && start_single_burst_write) begin axi_wvalid <= 1'b1; end /* If WREADY and too many writes, throttle WVALID Once asserted, VALIDs cannot be deasserted, so WVALID must wait until burst is complete with WLAST */ else if (wnext && axi_wlast) axi_wvalid <= 1'b0; else axi_wvalid <= axi_wvalid; end |
5:axi-full-master的axi_master_last
//WLAST generation on the MSB of a counter underflow // WVALID logic, similar to the axi_awvalid always block above always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_wlast <= 1'b0; end // axi_wlast is asserted when the write index // count reaches the penultimate count to synchronize // with the last write data when write_index is b1111 // else if (&(write_index[C_TRANSACTIONS_NUM-1:1])&& ~write_index[0] && wnext) else if (((write_index == C_M_AXI_BURST_LEN-2 && C_M_AXI_BURST_LEN >= 2) && wnext) || (C_M_AXI_BURST_LEN == 1 )) begin axi_wlast <= 1'b1; end // Deassrt axi_wlast when the last write data has been // accepted by the slave with a valid response else if (wnext) axi_wlast <= 1'b0; else if (axi_wlast && C_M_AXI_BURST_LEN == 1) axi_wlast <= 1'b0; else axi_wlast <= axi_wlast; end |
wire wlast=(write_index==C_M_AXI_BURST_LEN-1)&&wnext; reg wlast_r1 = 1'b0; always @(posedge M_AXI_ACLK) wlast_r <= wlast; assign axi_wlast = (wlast_r==1'b0)&&(wlast==1'b1); |
另外需要修改reg axi_wlast;为wire axi_wlast;
6:写次数记录write_index计数器
/* Burst length counter. Uses extra counter register bit to indicate terminal count to reduce decode logic */ always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 || start_single_burst_write == 1'b1) begin write_index <= 0; end else if (wnext && (write_index != C_M_AXI_BURST_LEN-1)) begin write_index <= write_index + 1; end else write_index <= write_index; end |
7:axi-full-master的axi_wdata
/* Write Data Generator Data pattern is only a simple incrementing count from 0 for each burst */ always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) axi_wdata <= 'b1; //else if (wnext && axi_wlast) // axi_wdata <= 'b0; else if (wnext) axi_wdata <= axi_wdata + 1; else axi_wdata <= axi_wdata; end |
8:axi-full-master的axi_bready
always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_bready <= 1'b0; end // accept/acknowledge bresp with axi_bready by the master // when M_AXI_BVALID is asserted by slave else if (M_AXI_BVALID && ~axi_bready) begin axi_bready <= 1'b1; end // deassert after one clock cycle else if (axi_bready) begin axi_bready <= 1'b0; end // retain the previous value else axi_bready <= axi_bready; end |
9:axi-full-slave的axi_arvalid
Axi_full_master读通道的分析非常类似,代码是对称的。
当(~axi_arvalid && start_single_burst_read)==1条件满足,开始一次写传输,设置axi_arvalid有效。
always @(posedge M_AXI_ACLK) begin
if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_arvalid <= 1'b0; end // If previously not valid , start next transaction else if (~axi_arvalid && start_single_burst_read) begin axi_arvalid <= 1'b1; end else if (M_AXI_ARREADY && axi_arvalid) begin axi_arvalid <= 1'b0; end else axi_arvalid <= axi_arvalid; end |
10:axi-full-slave的axi_araddr
// Next address after ARREADY indicates previous address acceptance always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_araddr <= 'b0; end else if (M_AXI_ARREADY && axi_arvalid) begin axi_araddr <= axi_araddr + burst_size_bytes; end else axi_araddr <= axi_araddr; end |
11:axi-full-master的axi_rready
/* The Read Data channel returns the results of the read request In this example the data checker is always able to accept more data, so no need to throttle the RREADY signal */ always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_rready <= 1'b0; end // accept/acknowledge rdata/rresp with axi_rready by the master // when M_AXI_RVALID is asserted by slave else if (M_AXI_RVALID) begin if (M_AXI_RLAST && axi_rready) begin axi_rready <= 1'b0; end else begin axi_rready <= 1'b1; end end // retain the previous value end |
12:读次数记录read_index计数器
assign rnext = M_AXI_RVALID && axi_rready; // Burst length counter. Uses extra counter register bit to indicate // terminal count to reduce decode logic always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 || start_single_burst_read) begin read_index <= 0; end else if (rnext && (read_index != C_M_AXI_BURST_LEN-1)) begin read_index <= read_index + 1; end else read_index <= read_index; end |
13:产生对比数据expected_rdata
数据expected_rdata用于和读出的M_AXI_RDATA进行对比以此验证数据的正确性。
//Generate expected read data to check against actual read data always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)// || M_AXI_RLAST) expected_rdata <= 'b1; else if (M_AXI_RVALID && axi_rready) expected_rdata <= expected_rdata + 1; else expected_rdata <= expected_rdata; end |
14:比对数据正确性
//Check received read data against data generator always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin read_mismatch <= 1'b0; end //Only check data when RVALID is active else if (rnext && (M_AXI_RDATA != expected_rdata)) begin read_mismatch <= 1'b1; end else read_mismatch <= 1'b0; end |
15:读写状态机
//implement master command interface state machine always @ ( posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 1'b0 ) begin // reset condition // All the signals are assigned default values under reset condition mst_exec_state <= IDLE; start_single_burst_write <= 1'b0; start_single_burst_read <= 1'b0; compare_done <= 1'b0; ERROR <= 1'b0; end else begin // state transition case (mst_exec_state) IDLE: // This state is responsible to wait for user defined C_M_START_COUNT // number of clock cycles. if ( init_txn_pulse == 1'b1) begin mst_exec_state <= INIT_WRITE; ERROR <= 1'b0; compare_done <= 1'b0; end else begin mst_exec_state <= IDLE; end INIT_WRITE: // This state is responsible to issue start_single_write pulse to // initiate a write transaction. Write transactions will be // issued until burst_write_active signal is asserted. // write controller if (writes_done) begin mst_exec_state <= INIT_READ;// end else begin mst_exec_state <= INIT_WRITE; if (~axi_awvalid && ~start_single_burst_write && ~burst_write_active) begin start_single_burst_write <= 1'b1; end else begin start_single_burst_write <= 1'b0; //Negate to generate a pulse end end INIT_READ: // This state is responsible to issue start_single_read pulse to // initiate a read transaction. Read transactions will be // issued until burst_read_active signal is asserted. // read controller if (reads_done) begin mst_exec_state <= INIT_COMPARE; end else begin mst_exec_state <= INIT_READ; if (~axi_arvalid && ~burst_read_active && ~start_single_burst_read) begin start_single_burst_read <= 1'b1; end else begin start_single_burst_read <= 1'b0; //Negate to generate a pulse end end INIT_COMPARE: // This state is responsible to issue the state of comparison // of written data with the read data. If no error flags are set, // compare_done signal will be asseted to indicate success. //if (~error_reg) begin ERROR <= error_reg; mst_exec_state <= IDLE; compare_done <= 1'b1; end default : begin mst_exec_state <= IDLE; end endcase end end //MASTER_EXECUTION_PROC |
16:正在写burst_write_active
always @(posedge M_AXI_ACLK) begin if(M_AXI_ARESETN==0||init_txn_pulse==1'b1) burst_write_active<=1'b0; //The burst_write_active is asserted when a write burst transaction is initiated else if (start_single_burst_write) burst_write_active <= 1'b1; else if (M_AXI_BVALID && axi_bready) burst_write_active <= 0; end |
17:写完成writes_done
always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) writes_done <= 1'b0; //The writes_done should be associated with a bready response //else if (M_AXI_BVALID && axi_bready && (write_burst_counter == {(C_NO_BURSTS_REQ-1){1}}) && axi_wlast) else if (M_AXI_BVALID && (write_burst_counter[C_NO_BURSTS_REQ]) && axi_bready) writes_done <= 1'b1; else writes_done <= writes_done; end |
18:正在读burst_read_active
// burst_read_active signal is asserted when there is a burst write transaction // is initiated by the assertion of start_single_burst_write. start_single_burst_read // signal remains asserted until the burst read is accepted by the master always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) burst_read_active <= 1'b0; //The burst_write_active is asserted when a write burst transaction is initiated else if (start_single_burst_read) burst_read_active <= 1'b1; else if (M_AXI_RVALID && axi_rready && M_AXI_RLAST) burst_read_active <= 0; end |
19:读完成reads_done
always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) reads_done <= 1'b0; //The reads_done should be associated with a rready response //else if (M_AXI_BVALID && axi_bready && (write_burst_counter == {(C_NO_BURSTS_REQ-1){1}}) && axi_wlast) else if (M_AXI_RVALID && axi_rready && (read_index == C_M_AXI_BURST_LEN-1) && (read_burst_counter[C_NO_BURSTS_REQ])) reads_done <= 1'b1; else reads_done <= reads_done; end |
20:IP的更新
4实验结果
一次axi4写操作burst lenth=16如下图所示,由于WREADY信号不是连续的,所以可以传输效率不是最高的
本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/17936369.html