[X]关闭

米联客-XILINX-H3_CZ08_7100] FPGA_AXI总线入门连载-02AXI4 总线 axi-lite-master

文档创建者:FPGA课程
浏览次数:151
最后更新:2024-10-12
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 3-FPGA AXI 总线入门
本帖最后由 FPGA课程 于 2024-10-12 16:21 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
使用XILINX 的软件工具VIVADO以及XILINX的7代以上的FPGA或者SOC掌握AXI-4总线结束,并且可以灵活使用AXI-4总线技术完成数据的交换,可以让我们在构建强大的FPGA内部总线数据互联通信方面取得高效、高速、标准化的优势。
关于AXI4总线协议的部分介绍请阅读“01AXI4总线axi-lite-slave”。
本文实验目的:
1:掌握基于VIVADO工具产生AXI协议模板
2:掌握通过VIVADO工具产生AXI-lite-master代码
3:理解AXI-lite-master中自定义寄存器的地址分配
4:掌握通过VIVADO封装AXI-lite-master图形化IP
5:通过仿真验证AXI-lite-master IP的工作是否正常。
2创建axi4-lite-master总线接口IP
新建fpga工程,过程省略
新建完成工程后,单击菜单栏Tools->Create and Package New IP,开始创建一个AXI4-Lite接口总线IP
1506cf3f6e7844b585c858d37db51f06.jpg
选择使用vivado自带的AXI总线模板创建一个AXI4-Lite接口IP
ec1e78727af844838ee813d71a9c385f.jpg
设置IP的名字为maxi_lite
c9dba114a4104343b0de3d8b66825d87.jpg
模板支持3种协议,分别是AXI4-Full ,AXI4-Lite ,AXI4-Stream
4bbfa74ab8524b9eb0943b72a5d78e8f.jpg

总线包括Master和Slave两种模式,这里选择Master模式
7acce9323eb8453b81eb01643e672cda.jpg
这里选择Verify Peripheral IP using AXI4 VIP 可以对AXI4-Lite快速验证
560e00baa5f94c3dbbf1cce093d968d3.jpg
单击Finish 后展开VIVADO自动产生的demo,单击Block Design的工程,可以看到如下2个IP。其中maxi_lite_0就是我们自定义的IP,另外一个slave_0是用来验证maxi_lite_0正确性。
82f3fd3af67d4a52a61b4fa4da4f385e.jpg
采用默认地址分配即可
28ac58fe82654075a9c0960e78a2c3a0.jpg

继续再看代码看看里面有什么东西
451e0d5f79ec4c0ba586b2f3a3c3e7dc.jpg
路径uisrc/03_ip/ maxi_lite_1.0/hdl路径下的maxi_lite_v1_0_M00_AXI.v就是我们的源码。另外一个maxi_lite_v1_0.v是软件产生了一个接口文件,如果我们自己定义IP可有可无。
3程序分析
axi总线信号的关键无非是地址和数据,而写地址的有效取决于AXI_AWVALID和AXI_AWREADY,写数据的有效取决于S_AXI_WVALID和S_AXI_WREADY。同理,读地址的有效取决于AXI_ARVALID和AXI_ARREADY,读数据的有效取决于S_AXI_RVALID和S_AXI_RREADY。所以以下代码的阅读分析注意也是围绕以上4个信号的有效时序。
以下程序我们把关键信号的代码拆分阅读
1:产生初始化信号   
  1.     always @(posedge M_AXI_ACLK)                                             
  2.       begin                                                                        
  3.         // Initiates AXI transaction delay   
  4.         if (M_AXI_ARESETN == 0 )                                                   
  5.           begin                                                                    
  6.             init_txn_ff <= 1'b0;                                                   
  7.             init_txn_ff2 <= 1'b0;                                                   
  8.           end                                                                              
  9.         else                                                                       
  10.           begin  
  11.             init_txn_ff <= INIT_AXI_TXN;
  12.             init_txn_ff2 <= init_txn_ff;                                                                 
  13.           end                                                                     
  14.       end  
复制代码

2:axi-lite-masteraxi_awvalid
当start_single_write有效,开始一次写传输,设置axi_awvalid有效。
  1.       always @(posedge M_AXI_ACLK)                                            
  2.       begin                                                                        
  3.         //Only VALID signals must be deasserted during reset per AXI spec         
  4.         //Consider inverting then registering active-low reset for higher fmax     
  5.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                   
  6.           begin                                                                    
  7.             axi_awvalid <= 1'b0;                                                   
  8.           end                                                                     
  9.           //用户逻辑发出新地址/数据命令的信号         
  10.         else                                                                       
  11.           begin                                                                    
  12.             if (start_single_write)                                                
  13.               begin                                                               
  14.                 axi_awvalid <= 1'b1;                                               
  15.               end                                                                  
  16.          //Address accepted by interconnect/slave (issue of M_AXI_AWREADY by slave)
  17.             else if (M_AXI_AWREADY && axi_awvalid)                                 
  18.               begin                                                               
  19.                 axi_awvalid <= 1'b0;                                               
  20.               end                                                                  
  21.           end                                                                     
  22.       end
复制代码

3:axi-lite-masteraxi_awaddr     
  1.       always @(posedge M_AXI_ACLK)                                 
  2.           begin                                                     
  3.             if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
  4.               begin                                                
  5.                 axi_awaddr <= 0;                                    
  6.               end                                                   
  7.               // Signals a new write address/ write data is         
  8.               // available by user logic                           
  9.             else if (M_AXI_AWREADY && axi_awvalid)                  
  10.               begin                                                
  11.                 axi_awaddr <= axi_awaddr + 32'h00000004;            
  12.                                                                     
  13.               end                                                   
  14.           end   
复制代码

4:axi-lite-masteraxi_wvalid
当M_AXI_WREADY && axi_wvalid同时有效的时候,数据才是有效的,对于axi-lite_master接口,M_AXI_WREADY && axi_wvalid同时有效的时间窗口是一个时钟周期。
  1. always @(posedge M_AXI_ACLK)                                       
  2.        begin                                                                        
  3.          if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                   
  4.            begin                                                                     
  5.              axi_wvalid <= 1'b0;                                                     
  6.            end                                                                       
  7.          //Signal a new address/data command is available by user logic              
  8.          else if (start_single_write)                                                
  9.            begin                                                                     
  10.              axi_wvalid <= 1'b1;                                                     
  11.            end                                                                       
  12.          //Data accepted by interconnect/slave (issue of M_AXI_WREADY by slave)      
  13.          else if (M_AXI_WREADY && axi_wvalid)                                       
  14.            begin                                                                     
  15.             axi_wvalid <= 1'b0;                                                      
  16.            end                                                                       
  17.        end   
复制代码

5:axi-lite-masteraxi_wdata
产生写测试用的测试数据
  1. always @(posedge M_AXI_ACLK)                                 
  2.           begin                                                     
  3.             if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                
  4.               begin                                                
  5.                 axi_wdata <= C_M_START_DATA_VALUE;                  
  6.               end                                                   
  7.             // Signals a new write address/ write data is           
  8.             // available by user logic                              
  9.             else if (M_AXI_WREADY && axi_wvalid)                    
  10.               begin                                                
  11.                 axi_wdata <= C_M_START_DATA_VALUE + write_index;   
  12.               end                                                   
  13.             end  
复制代码

6:写次数记录write_index计数器
这个demo中以start_single_wirte信号作为统计的,如果我们完全自定axi-lite_master代码可以自行优化,可以写出更好的代码。我们这里是用vivado模板产生的代码主要是教会大家如何使用现有的手段和软件工具学习axi4总线。
  1.       always @(posedge M_AXI_ACLK)                                                
  2.       begin                                                                        
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                   
  4.           begin                                                                    
  5.             write_index <= 0;                                                      
  6.           end                                                                     
  7.           // Signals a new write address/ write data is                           
  8.           // available by user logic                                               
  9.         else if (start_single_write)                                               
  10.           begin                                                                    
  11.             write_index <= write_index + 1;                                       
  12.           end                                                                     
  13.       end   
复制代码

7:axi-lite-masteraxi_bready
当收到写通道的axi-lite-slave发回的M_AXI_BVALDI应答信号,设置axi_bready为1,BRESP返回AXI写操作是否有错误。
  1. always @(posedge M_AXI_ACLK)                                    
  2.       begin                                                               
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                          
  4.           begin                                                            
  5.             axi_bready <= 1'b0;                                            
  6.           end                                                              
  7.         // accept/acknowledge bresp with axi_bready by the master         
  8.         // when M_AXI_BVALID is asserted by slave                          
  9.         else if (M_AXI_BVALID && ~axi_bready)                              
  10.           begin                                                            
  11.             axi_bready <= 1'b1;                                            
  12.           end                                                              
  13.         // deassert after one clock cycle                                 
  14.         else if (axi_bready)                                               
  15.           begin                                                            
  16.             axi_bready <= 1'b0;                                            
  17.           end                                                              
  18.         // retain the previous value                                       
  19.         else                                                               
  20.           axi_bready <= axi_bready;                                       
  21.       end                                                                  
  22.                                                                            
  23.     //Flag write errors                                                   
  24.     assign write_resp_error = (axi_bready & M_AXI_BVALID & M_AXI_BRESP[1]);
复制代码

8:axi-lite-masteraxi_arvalid   
  1.       always @(posedge M_AXI_ACLK)                                                     
  2.       begin                                                                           
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                      
  4.           begin                                                                        
  5.             axi_arvalid <= 1'b0;                                                      
  6.           end                                                                          
  7.         //Signal a new read address command is available by user logic                 
  8.         else if (start_single_read)                                                   
  9.           begin                                                                        
  10.             axi_arvalid <= 1'b1;                                                      
  11.           end                                                                          
  12.         //RAddress accepted by interconnect/slave (issue of M_AXI_ARREADY by slave)   
  13.         else if (M_AXI_ARREADY && axi_arvalid)                                         
  14.           begin                                                                        
  15.             axi_arvalid <= 1'b0;                                                      
  16.           end                                                                          
  17.         // retain the previous value                                                   
  18.       end   
复制代码

9:axi-lite-masteraxi_araddr
  1. always @(posedge M_AXI_ACLK)                                 
  2.           begin                                                     
  3.             if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
  4.               begin                                                
  5.                 axi_awaddr <= 0;                                    
  6.               end                                                   
  7.               // Signals a new write address/ write data is         
  8.               // available by user logic                           
  9.             else if (M_AXI_AWREADY && axi_awvalid)                  
  10.               begin                                                
  11.                 axi_awaddr <= axi_awaddr + 32'h00000004;            
  12.                                                                     
  13.               end                                                   
  14.           end   
复制代码

10:axi-lite-masteraxi_rready
当M_AXI_RVALID && axi_rready同时有效的时候,数据才是有效的,对于axi-lite_master接口,M_AXI_RVALID && ~axi_rready==1的时候设置axi_rready=1,当axi_rready==1,再设置axi_rready=0
  1. always @(posedge M_AXI_ACLK)                                    
  2.       begin                                                                 
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                            
  4.           begin                                                            
  5.             axi_rready <= 1'b0;                                             
  6.           end                                                               
  7.         // accept/acknowledge rdata/rresp with axi_rready by the master     
  8.         // when M_AXI_RVALID is asserted by slave                           
  9.         else if (M_AXI_RVALID && ~axi_rready)                              
  10.           begin                                                            
  11.             axi_rready <= 1'b1;                                             
  12.           end                                                               
  13.         // deassert after one clock cycle                                   
  14.         else if (axi_rready)                                                
  15.           begin                                                            
  16.             axi_rready <= 1'b0;                                             
  17.           end                                                               
  18.         // retain the previous value                                       
  19.       end                                                                  
  20.                                                                            
  21.     //Flag write errors                                                     
  22.     assign read_resp_error = (axi_rready & M_AXI_RVALID & M_AXI_RRESP[1]);  
复制代码

11:axi-lite-masterM_AXI_RDATA
当M_AXI_RVALID && axi_rready都有效的时候,对读取的M_AXI_RDATA数据和expected_rdata数据进行比较。
  1.       always @(posedge M_AXI_ACLK)                                                      
  2.       begin                                                                             
  3.         if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                         
  4.         read_mismatch <= 1'b0;                                                                                                                           
  5.         //The read data when available (on axi_rready) is compared with the expected data
  6.         else if ((M_AXI_RVALID && axi_rready) && (M_AXI_RDATA != expected_rdata))         
  7.           read_mismatch <= 1'b1;                                                        
  8.         else                                                                           
  9.           read_mismatch <= read_mismatch;                                               
  10.       end  
复制代码

12:产生对比数据expected_rdata
数据expected_rdata用于和读出的M_AXI_RDATA进行对比以此验证数据的正确性。
  1.       always @(posedge M_AXI_ACLK)                                 
  2.           begin                                                     
  3.             if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                
  4.               begin                                                
  5.                 axi_wdata <= C_M_START_DATA_VALUE;                  
  6.               end                                                   
  7.             // Signals a new write address/ write data is           
  8.             // available by user logic                              
  9.             else if (M_AXI_WREADY && axi_wvalid)                    
  10.               begin                                                
  11.                 axi_wdata <= C_M_START_DATA_VALUE + write_index;   
  12.               end                                                   
  13.             end        
复制代码
13:读次数记录read_index计数器
这个demo中以start_single_read信号作为统计的,如果我们完全自定axi-lite_master代码可以自行优化,可以写出更好的代码。我们这里是用vivado模板产生的代码主要线教会大家如何使用现有的手段和软件工具学习axi4总线。
  1. always @(posedge M_AXI_ACLK)                                                     
  2.       begin                                                                           
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                      
  4.           begin                                                                        
  5.             read_index <= 0;                                                           
  6.           end                                                                          
  7.         // Signals a new read address is                                               
  8.         // available by user logic                                                     
  9.         else if (start_single_read)                                                   
  10.           begin                                                                        
  11.             read_index <= read_index + 1;                                             
  12.           end                                                                          
  13.       end   
复制代码

14:axi-lite-master的状态机
  1. always @(posedge M_AXI_ACLK)                                 
  2.           begin                                                     
  3.             if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
  4.               begin                                                
  5.                 expected_rdata <= C_M_START_DATA_VALUE;            
  6.               end                                                   
  7.               // Signals a new write address/ write data is         
  8.               // available by user logic                           
  9.             else if (M_AXI_RVALID && axi_rready)                    
  10.               begin                                                
  11.                 expected_rdata <= C_M_START_DATA_VALUE + read_index;
  12.               end                                                   
  13.           end                                                      
  14.       //implement master command interface state machine                        
  15.       always @ ( posedge M_AXI_ACLK)                                                   
  16.       begin                                                                             
  17.         if (M_AXI_ARESETN == 1'b0)                                                     
  18.           begin                                                                        
  19.           // reset condition                                                            
  20.           // All the signals are assigned default values under reset condition         
  21.             mst_exec_state  <= IDLE;                                            
  22.             start_single_write <= 1'b0;                                                
  23.             write_issued  <= 1'b0;                                                      
  24.             start_single_read  <= 1'b0;                                                
  25.             read_issued   <= 1'b0;                                                      
  26.             compare_done  <= 1'b0;                                                      
  27.             ERROR <= 1'b0;
  28.           end                                                                           
  29.         else                                                                           
  30.           begin                                                                        
  31.            // state transition                                                         
  32.             case (mst_exec_state)                                                      
  33.                                                                                        
  34.               IDLE:                                                            
  35.               // This state is responsible to initiate
  36.               // AXI transaction when init_txn_pulse is asserted
  37.                 if ( init_txn_pulse == 1'b1 )                                    
  38.                   begin                                                                 
  39.                     mst_exec_state  <= INIT_WRITE;                                      
  40.                     ERROR <= 1'b0;
  41.                     compare_done <= 1'b0;
  42.                   end                                                                  
  43.                 else                                                                    
  44.                   begin                                                                 
  45.                     mst_exec_state  <= IDLE;                                    
  46.                   end                                                                  
  47.                                                                                        
  48.               INIT_WRITE:                                                               
  49.                 // This state is responsible to issue start_single_write pulse to      
  50.                 // initiate a write transaction. Write transactions will be            
  51.                 // issued until last_write signal is asserted.                          
  52.                 // write controller                                                     
  53.                 if (writes_done)                                                        
  54.                   begin                                                                 
  55.                     mst_exec_state <= INIT_READ;//                                      
  56.                   end                                                                  
  57.                 else                                                                    
  58.                   begin                                                                 
  59.                     mst_exec_state  <= INIT_WRITE;                                      
  60.                                                                                        
  61.                       if (~axi_awvalid && ~axi_wvalid && ~M_AXI_BVALID && ~last_write && ~start_single_write && ~write_issued)
  62.                         begin                                                           
  63.                           start_single_write <= 1'b1;                                   
  64.                           write_issued  <= 1'b1;                                       
  65.                         end                                                            
  66.                       else if (axi_bready)                                             
  67.                         begin                                                           
  68.                           write_issued  <= 1'b0;                                       
  69.                         end                                                            
  70.                       else                                                              
  71.                         begin                                                           
  72.                           start_single_write <= 1'b0; //Negate to generate a pulse      
  73.                         end                                                            
  74.                   end                                                                  
  75.                                                                                        
  76.               INIT_READ:                                                               
  77.                 // This state is responsible to issue start_single_read pulse to        
  78.                 // initiate a read transaction. Read transactions will be               
  79.                 // issued until last_read signal is asserted.                           
  80.                  // read controller                                                     
  81.                  if (reads_done)                                                        
  82.                    begin                                                               
  83.                      mst_exec_state <= INIT_COMPARE;                                    
  84.                    end                                                                  
  85.                  else                                                                  
  86.                    begin                                                               
  87.                      mst_exec_state  <= INIT_READ;                                      
  88.                                                                                        
  89.                      if (~axi_arvalid && ~M_AXI_RVALID && ~last_read && ~start_single_read && ~read_issued)
  90.                        begin                                                            
  91.                          start_single_read <= 1'b1;                                    
  92.                          read_issued  <= 1'b1;                                          
  93.                        end                                                              
  94.                      else if (axi_rready)                                               
  95.                        begin                                                            
  96.                          read_issued  <= 1'b0;                                          
  97.                        end                                                              
  98.                      else                                                               
  99.                        begin                                                            
  100.                          start_single_read <= 1'b0; //Negate to generate a pulse        
  101.                        end                                                              
  102.                    end                                                                  
  103.                                                                                        
  104.                INIT_COMPARE:                                                            
  105.                  begin
  106.                      // This state is responsible to issue the state of comparison         
  107.                      // of written data with the read data. If no error flags are set,      
  108.                      // compare_done signal will be asseted to indicate success.            
  109.                      ERROR <= error_reg;
  110.                      mst_exec_state <= IDLE;                                    
  111.                      compare_done <= 1'b1;                                             
  112.                  end                                                                  
  113.                default :                                                               
  114.                  begin                                                                  
  115.                    mst_exec_state  <= IDLE;                                    
  116.                  end                                                                    
  117.             endcase                                                                     
  118.         end                                                                             
  119.       end //MASTER_EXECUTION_PROC               
复制代码

整理成流程图,更加容易理解:
60be5ef5c8ea4904a8ee931990fa36bd.jpg
15:最后一个写数据
  1. always @(posedge M_AXI_ACLK)                                                      
  2.       begin                                                                             
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
  4.           last_write <= 1'b0;                                                                                                                                            
  5.         //The last write should be associated with a write address ready response      
  6.         else if ((write_index == C_M_TRANSACTIONS_NUM) && M_AXI_AWREADY)               
  7.           last_write <= 1'b1;                                                           
  8.         else                                                                           
  9.           last_write <= last_write;                                                     
  10.       end                                                                                                                                                   
  11.       //Check for last write completion.                                                                                                                           
  12.       //This logic is to qualify the last write count with the final write              
  13.       //response. This demonstrates how to confirm that a write has been               
  14.       //committed.                                                                                                                                                   
  15.       always @(posedge M_AXI_ACLK)                                                      
  16.       begin                                                                             
  17.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
  18.           writes_done <= 1'b0;                                                         
  19.                                                                                 
  20.           //The writes_done should be associated with a bready response                 
  21.         else if (last_write && M_AXI_BVALID && axi_bready)                              
  22.           writes_done <= 1'b1;                                                         
  23.         else                                                                           
  24.           writes_done <= writes_done;                                                   
  25.       end      <span style="background-color: rgb(255, 255, 255);">    </span><img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码
16:最后一个读数据
  1. always @(posedge M_AXI_ACLK)                                                      
  2.       begin                                                                             
  3.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
  4.           last_read <= 1'b0;                                                            
  5.                                                                                        
  6.         //The last read should be associated with a read address ready response         
  7.         else if ((read_index == C_M_TRANSACTIONS_NUM) && (M_AXI_ARREADY) )              
  8.           last_read <= 1'b1;                                                            
  9.         else                                                                           
  10.           last_read <= last_read;                                                      
  11.       end                                                                              
  12.                                                                                        
  13.     /*   Check for last read completion.                                                                                                                                 
  14.      This logic is to qualify the last read count with the final read response/data.    */                 
  15.                                                                                 
  16.       always @(posedge M_AXI_ACLK)                                                      
  17.       begin                                                                             
  18.         if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
  19.           reads_done <= 1'b0;                                                                                                                                
  20.         //The reads_done should be associated with a read ready response               
  21.         else if (last_read && M_AXI_RVALID && axi_rready)                              
  22.           reads_done <= 1'b1;                                                           
  23.         else                                                                           
  24.           reads_done <= reads_done;                                                     
  25.         end   
复制代码
02e317fe57034ffc957c825ce8cc45e8.jpg

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则