ZYNQ learning chapter 1-AXI learning notes

Posted by dannymc1983 on Thu, 13 Jan 2022 05:22:14 +0100

1, Introduction to AXI

1.AXI overview

ZYNQ closely combines high-performance ARM Cotex-A series processors with high-performance FPGA in a single chip. After integrating processors with different process characteristics and FPGA on one chip, the interconnection path between on-chip processor and FPGA has become the top priority of ZYNQ chip design. If the data interaction between Cotex-A9 and FPGA becomes a bottleneck, the performance advantage of the combination of processor and FPGA cannot be brought into play. The purpose of AXI is to solve the fast data interaction between Contex-A9 and FPGA.
AXI's full English name is Advanced eXtensible Interface, that is, Advanced eXtensible Interface. It is a part of AMBA (Advanced Microcontroller Bus Architecture) protocol proposed by ARM company. In the digital circuit, only binary numbers 0 and 1 can be transmitted, so a group of signals may be required to transmit information efficiently, which constitutes the interface. The AXI4 protocol supports the following three types of interfaces:

  • AXI4: high performance storage mapping interface.
  • AXI4 Lite: simplified version of AXI4 interface for storage mapping communication with less data volume.
  • Axi4 stream: used for high-speed data stream transmission, non storage mapping interface. Like FIFO, the interface does not need an address during data transmission, and directly and continuously reads and writes data between master and slave devices. It is mainly used in occasions requiring high-speed data transmission, such as video, high-speed AD, PCIe, DMA interfaces, etc

Memory map: if a protocol is memory mapped, then
Then the session (whether read or write) issued by the host will indicate an address. This address corresponds to an address in the system storage space, indicating that it is a read-write operation for the storage space.

2. Overview of Axi bus

Bus, interface and protocol are often associated, but they are different. Bus is a group of transmission channels, which is composed of various logic devices to transmit data. It is generally composed of data lines, address lines, control lines, etc. Interface is a connection standard, also known as physical interface. Protocol is the rule of transmitting data.
ZYNQ supports three AXI buses and three AXI interfaces. Of course, all of them use the AXI protocol. Three AXI buses are:

  • List itemAXI4: (For high-performance memory-mapped requirements.) It is mainly oriented to the requirements of high-performance address mapping communication
    The interface of address mapping allows up to 256 rounds of data burst transmission;
  • Axi4 Lite: (for simple, low-throughput memory mapped communication) is a lightweight address mapping single transmission interface, which occupies very few logical units. It is mainly used to access registers in some low-speed peripherals.
  • AXI4-Stream: (For high-speed streaming data.) For high-speed streaming data transmission; The address item is removed to allow unlimited data burst transmission scale.

AXI4 bus and AXI4 Lite bus have the same components:

  • Read address channel, including arvalid, araddr and arready signals;
  • Read data channel, including rvalid, rdata, rready and rresp signals;
  • Write address channel, including AWVALID, awaddr and awready signals;
  • Write data channel, including WVALID, WDATA, WSTRB, WREADY signals;
  • Write response channel, including bvalid, bresp and ready signals;
  • System channel, including ACLK and ARESETN signals.

The signals of AXI4 bus and AXI4 Lite bus also have its naming characteristics

  • All read address signals begin with AR (A: address; R: read)
  • Write address signals start with AW (A: address; W: write)
  • All read data signals begin with R (R: read)
  • All write data signals begin with w (W: write)
  • Answer models start with B (B: back (answer back))

3. Overview of Axi interface

The three AXI interfaces are:

  • AXI-GP interface (4): it is a general AXI interface, including two 32-bit master device interfaces and two 32-bit slave device interfaces. This interface is used
    You can access the on-chip and off-chip devices in the PS.
  • AXI-HP interface (4): it is a standard interface with high performance / bandwidth, and the PL module is connected as the main device (as can be seen from the arrow in the figure below). main
    To use PL to access memory on PS (DDR and on chip RAM)
  • AXI-ACP interface (1): it is an interface defined under ARM multi-core architecture. It is translated into accelerator consistency port in Chinese to manage DMA
    For AXI peripherals without cache, the PS side is the Slave interface.

We can double-click to view the internal configuration of the IP core of ZYNQ, and we can find the above three interfaces, which have been marked with red boxes in the figure.

4. Overview of Axi protocol

The two ends of AXI bus protocol can be divided into master and slave. They generally need to be connected through an AXI Interconnect to provide a switching mechanism to connect one or more AXI master devices to one or more AXI slave devices.
The main function of AXI Interconnect is to connect and manage multiple hosts and slave machines. Because AXI supports out of order transmission, out of order transmission requires the support of host ID signals, and different hosts may send the same ID. AXI Interconnect solves this problem. It will process the ID signals of different hosts to make the ID unique. AXI protocol separates read address channel, read data channel, write address channel, write data channel and write response channel. Each channel has its own handshake protocol. Each channel does not interfere with each other but depends on each other. This is one of the reasons why AXI is efficient.

4.1 AXI protocol - handshake protocol

AXI4 adopts a READY and VALID handshake communication mechanism. In short, there is a handshake process before the master and slave sides conduct data communication. The transmission source generates VLAID signals to indicate when data or control information is VALID. The destination source generates a READY signal to indicate that it is READY to receive data or control information. Transmission occurs when the VALID and READY signals are both high. There are three relationships between VALID and READY signals.


2, Axi4 Lite source code learning

1. Customize AXI IP core

Step 1: open Vivado software - > select Manage IP - > select New IP Location

Step 2: next - > select the corresponding chip of ZYNQ at ① - > select the IP storage location at ② - > finish

Step 3: Tools - > create and package new IP - > next - > create a new axi4 peripheral - > next - > name at ① in Figure 3 - > next - > configure IP core, as shown in Figure 4 - > next - > Edit IP - > finish





Step4: double click, as shown in Figure 1 below

2. Analysis of source code

1. First, some IP interfaces; See the table below for specific functions

		// Global Clock Signal
		input wire  S_AXI_ACLK,
		// Global Reset Signal. This Signal is Active LOW
		input wire  S_AXI_ARESETN,
		// Write address (issued by master, acceped by Slave)
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
		// Write channel Protection type. This signal indicates the
    		// privilege and security level of the transaction, and whether
    		// the transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_AWPROT,
		// Write address valid. This signal indicates that the master signaling
    		// valid write address and control information.
		input wire  S_AXI_AWVALID,
		// Write address ready. This signal indicates that the slave is ready
    		// to accept an address and associated control signals.
		output wire  S_AXI_AWREADY,
		// Write data (issued by master, acceped by Slave) 
		input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
		// Write strobes. This signal indicates which byte lanes hold
    		// valid data. There is one write strobe bit for each eight
    		// bits of the write data bus.    
		input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
		// Write valid. This signal indicates that valid write
    		// data and strobes are available.
		input wire  S_AXI_WVALID,
		// Write ready. This signal indicates that the slave
    		// can accept the write data.
		output wire  S_AXI_WREADY,
		// Write response. This signal indicates the status
    		// of the write transaction.
		output wire [1 : 0] S_AXI_BRESP,
		// Write response valid. This signal indicates that the channel
    		// is signaling a valid write response.
		output wire  S_AXI_BVALID,
		// Response ready. This signal indicates that the master
    		// can accept a write response.
		input wire  S_AXI_BREADY,
		// Read address (issued by master, acceped by Slave)
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
		// Protection type. This signal indicates the privilege
    		// and security level of the transaction, and whether the
    		// transaction is a data access or an instruction access.
		input wire [2 : 0] S_AXI_ARPROT,
		// Read address valid. This signal indicates that the channel
    		// is signaling valid read address and control information.
		input wire  S_AXI_ARVALID,
		// Read address ready. This signal indicates that the slave is
    		// ready to accept an address and associated control signals.
		output wire  S_AXI_ARREADY,
		// Read data (issued by slave)
		output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
		// Read response. This signal indicates the status of the
    		// read transfer.
		output wire [1 : 0] S_AXI_RRESP,
		// Read valid. This signal indicates that the channel is
    		// signaling the required read data.
		output wire  S_AXI_RVALID,
		// Read ready. This signal indicates that the master can
    		// accept the read data and response information.
		input wire  S_AXI_RREADY


2. Write data related source code

always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      slv_reg0 <= 0;
	      slv_reg1 <= 0;
	      slv_reg2 <= 0;
	      slv_reg3 <= 0;
	    end 
	  else begin
	    if (slv_reg_wren)
	      begin
	        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	          2'h0:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 0
	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h1:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 1
	                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h2:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 2
	                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          2'h3:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 3
	                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          default : begin
	                      slv_reg0 <= slv_reg0;
	                      slv_reg1 <= slv_reg1;
	                      slv_reg2 <= slv_reg2;
	                      slv_reg3 <= slv_reg3;
	                    end
	        endcase
	      end
	  end
	end  

When the PS writes data to the axi4 Lite bus, it stores the data transmitted from the bus in the register slv_reg. And slv_reg register has 0 ~ 3
4 in total. As for which is assigned by
axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] is determined by Axi according to the macro definition_ Awaddr [3:2] (write)
The address contains not only the address, but also the control bit. Here [3:2] is the control bit) to determine which SLV to assign_ reg.
When PS calls the write function, if the address offset is not done, Axi_ The default value of awaddr [3:2] is 0. For example, if the address of our custom IP is mapped to 0x43c00000, we__ Xil_Out32(0x43C00000,Value)__ It's SLV_ The value of reg0. If the address is offset by 4 bits, such as_ Xil_Out32(0x43C00000 + 4,Value) writes SLV_ The value of reg1, and so on;
In slv_reg0 as an example:

for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 0
	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  

The most critical sentence in the for loop:

slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

When byte_ When index = 0, this sentence is equivalent to:
slv_reg0[7:0] <= S_AXI_WDATA[7:0];
When byte_ When index = 1, this sentence is equivalent to:
slv_reg0[15:8] <= S_AXI_WDATA[15:8];
When byte_ When index = 2, this sentence is equivalent to:
slv_reg0[23:16] <= S_AXI_WDATA[23:16];
When byte_ When index = 3, this sentence is equivalent to:
slv_reg0[31:24] <= S_AXI_WDATA[31:24];
That is, only when the write strobe signal is 1, it corresponds to S_AXI_WDATA bytes will be read.

3. Read source code analysis

// Output register or memory read data
	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_rdata  <= 0;
	    end 
	  else
	    begin    
	      // When there is a valid read address (S_AXI_ARVALID) with 
	      // acceptance of read address by the slave (axi_arready), 
	      // output the read dada 
	      if (slv_reg_rden)
	        begin
	          axi_rdata <= reg_data_out;     // register read data
	        end   
	    end
	end    

The observation shows that when PS reads data, the program will send reg_data_out copy to axi_rdata (RADTA read data). We keep tracking reg_data_out:

always @(*)
begin
 // Address decoding for reading registers
 case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
 	2'h0 : reg_data_out <= slv_reg0;
 	2'h1 : reg_data_out <= slv_reg1;
 	2'h2 : reg_data_out <= slv_reg2;
 	2'h3 : reg_data_out <= slv_reg3;
 default : reg_data_out <= 0;
 endcase
end

This program is an example provided by Vivado. It just wants to verify that the value written out is equal to the value read in.

3. Summary

If we want to use the PS side to read the Axi_ When using lite4 bus data, you can write your own code:

reg [11:0]axi_urdata;
 always @( posedge S_AXI_ACLK )
 begin
 if ( S_AXI_ARESETN == 1'b0 )
 	begin
 		axi_urdata<= 12'd0; //Reset register
	end 
 else
 	begin
 		axi_urdata<= slv_reg0[11:0];//Copy the data of register 0 to the custom register
 	end
 end 
 assign axi_rdata= axi_urdata;// Read data output;

If we want to pair Axi with PS side_ When writing data on lite4 bus, you can write a code yourself:

wire[31:0]axi_wdata;
always @(*)
 begin
	 case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
 		2'h0 : reg_data_out <= axi_wdata;//slv_reg0; 
	 	2'h1 : reg_data_out <= slv_reg1;
 		2'h2 : reg_data_out <= slv_reg2;
 		2'h3 : reg_data_out <= slv_reg3;
 	default : reg_data_out <= 0;
 endcase
 end

3, Source code test

1. Encapsulate IP core


2. Create project

Step 1: create project - > next

Step2



Step3
Create an empty design

Join the IP core of ZYNQ

Double click ZYNQ IP to modify the corresponding configuration


Add custom IP core path

Add custom IP core

Connect automatically

Right click and click generate layout to optimize routing

Automatic deployment, connection DDR, etc

Ctrl + S what it looks like after saving

To verify whether there are errors, click the following figure;

Add observation signal


How the connection looks

Generate hardware

What it looks like when it's finished

Generate bitstream

Wait for completion

3. Import SDK




New project file - > New - > Application Project

New Hello World Project

Base address found

Write data

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

#include "xil_io.h"
#include "xil_types.h"
#include "xparameters.h"



int main()
{
	volatile u32 rdata_0;
	volatile u32 rdata_1;
	volatile u32 rdata_2;
	volatile u32 rdata_3;

	while(1)
	{
		//Write AXI data
		Xil_Out32(XPAR_MYIP_0_S00_AXI_BASEADDR,0x01);

		Xil_Out32(XPAR_MYIP_0_S00_AXI_BASEADDR+4,0x02);

		Xil_Out32(XPAR_MYIP_0_S00_AXI_BASEADDR+8,0x03);

		Xil_Out32(XPAR_MYIP_0_S00_AXI_BASEADDR+12,0x04);

		//Reading AXI data
		rdata_0 = Xil_In32(XPAR_MYIP_0_S00_AXI_BASEADDR);
			printf("read reg0 data:%ld\n\r",rdata_0);
		rdata_1 = Xil_In32(XPAR_MYIP_0_S00_AXI_BASEADDR+4);
			printf("read reg1 data:%ld\n\r",rdata_1);
		rdata_2 = Xil_In32(XPAR_MYIP_0_S00_AXI_BASEADDR+8);
			printf("read reg2 data:%ld\n\r",rdata_2);
		rdata_3 = Xil_In32(XPAR_MYIP_0_S00_AXI_BASEADDR+12);
			printf("read reg3 data:%ld\n\r",rdata_3);

	}
//    init_platform();

//    print("Hello World\n\r");

//    cleanup_platform();


//    return 0;
}

Add serial port

debugging
Project - > right click - > debug as - > debug configurations


Double click to set breakpoint

Generation simulation


Test chart
Serial port reading diagram

Simulation diagram

4, Summary

Through this, I learned the theoretical knowledge of AXI, the internal source code of AXI, the basic steps of Vivado to establish a project, and how to create a project in the SDK and write my own application; The basic timing of AXI is tested. The AXI is written into the data through the serial port and connected with the read-out data. How to control the write and read-out of AXI bus through PS terminal is verified;
Problems: 1. The logic of key statements in source Verilog; 2. Use Verilog to write and read AXI;

Topics: Verilog FPGA