专栏首页hankXilinx MPSoC PS/PL之间的数据交互和外设设计

Xilinx MPSoC PS/PL之间的数据交互和外设设计

Xilinx MPSoC PS/PL之间的数据交互和外设设计

1. 作者

付汉杰 2020-09-10

2. 概述

MPSoC是Xilinx基于16nm工艺推出的异构计算平台,由于灵活、稳定,在业界得到了广泛的使用。异构计算是一个比较新的领域,需要协调硬件设计、逻辑设计、软件设计,对工程师的要求很高。实际设计过程中,很多工程师对实现PS/PL之间的数据交互感到头疼。 本文将介绍主要的PS/PL之间的数据交互办法。

3. MPSoC PS/PL之间的数据通路

在开始之前,首先简要介绍PS/PL之间的数据通路,请参考 《UG1085 Zynq UltraScale+ MPSoC Technical Reference Manual》的Figure 1-1: AXI Interconnect。

PS/PL之间的数据通路主要是通用的AXI Memory接口,其中PS作为主设备的接口有128-bit位宽的HPM0/HPM1, 64-bit位宽的LPD_PL; PL作为主设备的接口有ACP/ACE/HPC0/HPC1/HP0/HP1/HP2/HP3。所有AXI Memory接口的位宽最高都可以支持到128-bit。

PS/PL之间主要通过PS-DDR交互大块数据。从Figure 1-1可以看到,PS-DDR控制器有六个AXI Slave接口,与PL直接相关的是S3、S4、S5。HPC0/HPC1都连接到了CCI Interconnect。DP和HP0连接到了S3。HP1和HP2连接到了S4。HP3和FP DMA连接到了S5。如果需要提高带宽,要充分利用PS-DDR控制器的AXI Slave接口。如果可能,HP1和HP2最好不要同时用,因为HP1和HP2都连接到了S4,最后会彼此竞争带宽。

UG1085的Figure 1-1提供了最详细的信息,也有点复杂。为了简单,也可以参考下面来自于《Zynq UltraScale+ MPSoC Technical Overview》的简化示意图。

在Vivado的IP 里,使能相关接口后,接口如下。

4. MPSoC PS/PL之间的简单数据通路和简单外设设计

很多时候,PS/PL之间只需要简单的数据通路。PS只需要下发有限的参数给PL,PL只需要向PS反馈有限的状态数据。串口、SPI设备、IIC等低速接口,就属于这种设备。这种情况下,PL内部只需要实现AXI Slave接口和一些寄存器就可以,PS通过AXI接口去访问寄存器,既向PL提供参数,也可以读回PL的状态。 客户可以自己设计AXI接口和寄存器,也可以使用Vivado里的工具Create and Package IP。

4.1. 使用Vivado里的工具Create and Package IP创建IP

如果使用Vivado里的工具Create and Package IP创建IP,可以参照下列步骤。

  1. 调用Vivado的Create and Package IP 模板
  1. Create and Package IP 模板介绍
  1. 新建IP

这一步选择"Create a new AXI4 peripheral"。

  1. IP命名和目录

根据自己需要,指定IP的名称和目录。

  1. IP接口选择

可以看到,只为新的IP选择了AXI Lite接口,并实现了16个寄存器。工程师可以根据需要选择寄存器个数,最小4个,最多512个。对于AXI Lite接口,数据位宽是32-bit。

  1. 完成IP创建

选择“Add IP to the repository”, 点击"Finish", 完成IP创建。

  1. BD框图

在Block Design中,选择对应的IP。示例中是MyIP。添加后,在Block Design中,得到如下IP。可以看到,MyIP有一个AXI Slave接口,及其对应的时钟和复位信号。

  1. BD设计

AXI Lite的外设很简单,只有一个AXI Slave接口,及其对应的时钟和复位信号。把AXI Slave接口通过AXI Interconnect连接到某个PS的AXI Master接口,示例是M_AXI_HPM0_FPD,再提供对应的时钟和复位信号就可以。AXI连接两侧的Mater和Slave必须使用同一个时钟和复位信号。

  1. 代码分析

创建IP后,在指定的目录下,得到如下的文件夹和和文件。

myip_1.0
   │  component.xml
   │
   ├─bd
   │      bd.tcl
   │
   ├─example_designs
   │  ├─bfm_design
   │  │      design.tcl
   │  │      myip_v1_0_tb.sv
   │  │
   │  └─debug_hw_design
   │          design.tcl
   │          myip_v1_0_hw_test.tcl
   │
   ├─hdl
   │      myip_v1_0.v
   │      myip_v1_0_S00_AXI.v
   │
   └─xgui
           myip_v1_0.tcl

myip_v1_0_S00_AXI.v里实现了寄存器及其读写逻辑。

实现寄存器的Verilog HDL代码:

	//----------------------------------------------
	//-- Signals for user logic register space example
	//------------------------------------------------
	//-- Number of Slave Registers 16
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg0;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg1;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg2;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg3;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg4;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg5;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg6;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg7;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg8;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg9;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg10;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg11;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg12;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg13;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg14;
	reg [C_S_AXI_DATA_WIDTH-1:0]	slv_reg15;

寄存器写操作的Verilog HDL代码的部分片段:

    if (slv_reg_wren)
      begin
        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
          4'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  
 					  ... ...
          default : begin
                      slv_reg0 <= slv_reg0;
 					  ... ...
                      slv_reg15 <= slv_reg15;
                    end
        endcase
    end

寄存器读操作的Verilog HDL代码的部分片段:

	// Implement memory mapped register select and read logic generation
	// Slave register read enable is asserted when valid address is available
	// and the slave is ready to accept the read address.
	assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
	always @(*)
	begin
	      // Address decoding for reading registers
	      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	        4'h0   : reg_data_out <= slv_reg0;
	        4'h1   : reg_data_out <= slv_reg1;
	        4'h2   : reg_data_out <= slv_reg2;
	        4'h3   : reg_data_out <= slv_reg3;
	        4'h4   : reg_data_out <= slv_reg4;
	        4'h5   : reg_data_out <= slv_reg5;
	        4'h6   : reg_data_out <= slv_reg6;
	        4'h7   : reg_data_out <= slv_reg7;
	        4'h8   : reg_data_out <= slv_reg8;
	        4'h9   : reg_data_out <= slv_reg9;
	        4'hA   : reg_data_out <= slv_reg10;
	        4'hB   : reg_data_out <= slv_reg11;
	        4'hC   : reg_data_out <= slv_reg12;
	        4'hD   : reg_data_out <= slv_reg13;
	        4'hE   : reg_data_out <= slv_reg14;
	        4'hF   : reg_data_out <= slv_reg15;
	        default : reg_data_out <= 0;
	      endcase
	end

根据需要,可以将寄存器的某个bit,作为控制信号,连接到应用的逻辑代码。也可以将应用逻辑代码的某些信号,作为状态信号,连接到寄存器的某个bit,做状态信号,供CPU读取。

4.2. 软件

简单外设只有寄存器,软件靠读写寄存器,就能实现对硬件的控制。

5. DMA外设设计

如果外设的数据量大,速率要求高,建议使用DMA搬移数据,使PS和PL通过DDR共享数据。 Vivado的工具Create and Package IP同样可以创建支持DMA功能的IP。大部分步骤,和前述“简单数据通路”一样。在“AXI Interfaces”窗口,除了“AXI Lite”接口以外,还要增加“AXI Full Master”接口。

  1. 新建AXI接口

在“AXI Interfaces”窗口,点击“+”按钮,能创建一个新的接口。

  1. 添加AXI Master接口

在弹出的接口中,为“Interface Type”选择"Full",为“Interface Mode”选择"Master"。 后续操作,和简单外设的操作一样。

  1. BD框图

在Block Design中,选择对应的IP。示例中是myip_dma。添加后,在Block Design中,得到如下IP。可以看到,myip_dma多了一个AXI Master接口“M00_AXI”和对应的时钟和复位信号。值得注意的是,myip_dma还多了输入信号m00_axi_init_axi_txn,输出信号m00_axi_txn_done和m00_axi_error。m00_axi_init_axi_txn用于发起写/读传输;m00_axi_txn_done和m00_axi_error由于指示传输是否完成。

  1. 代码分析

带有DMA的IP的文件如下。

 myip_dma_1.0
   │  component.xml
   │  
   ├─bd
   │      bd.tcl
   │      
   ├─example_designs
   │  ├─bfm_design
   │  │      design.tcl
   │  │      myip_dma_v1_0_tb.sv
   │  │      
   │  └─debug_hw_design
   │          design.tcl
   │          myip_dma_v1_0_hw_test.tcl
   │          
   ├─hdl
   │      myip_dma_v1_0.v
   │      myip_dma_v1_0_M00_AXI.v
   │      myip_dma_v1_0_S00_AXI.v
   │      
   └─xgui
           myip_dma_v1_0.tcl

AXI Master的HDL代码在文件myip_dma_v1_0_M00_AXI.v中,它实现了通过AXI Master端口写数据、读数据的功能。读写的地址由参数C_M_TARGET_SLAVE_BASE_ADDR指定。

工程师需要根据自己的需要,修改相关逻辑。上述AXI Master示例中,只能向固定地址发起成对的写、读操作。在实际工程中,地址通常由软件配置,写、读操作也经常分开。

5.1. 软件

DMA外设通常需要由软件配置DMA操作的目标内存。如果是standalone(baremetal,裸核)代码,缺省情况下物理地址和软件地址一样,直接向DMA的内存地址寄存器写入软件得到的地址就可以。如果是Linux下,需要先把软件地址转换成硬件地址,再写入DMA的内存地址寄存器。

6. AXI Stream外设设计

在自己IP里集成DMA,可以根据项目需求定制DMA的功能,实现最优的性能,但是也会带来设计和维护的工作量。

为了降低工作量,可以使用现成的DMA,并在IP里增加AXI Stream接口,对接AXI DMA,实现DMA功能。

大部分步骤,仍然和前述“简单数据通路”一样。在“AXI Interfaces”窗口,除了“AXI Lite”接口以外,选择要增加“AXI Stream Slave”接口, 和“AXI Stream MasterMaster”接口。

  1. 新建AXI接口

在“AXI Interfaces”窗口,点击“+”按钮,能创建一个新的接口。

  1. 添加AXI Streamm口

在弹出的接口中,为“Interface Type”选择"Stream",为“Interface Mode”选择"Master"或者"Slave"。示例中,既添加了AXI Streamm的Master,也添加了AXI Streamm的Master。实际工程中,工程师可以根据需要只添加其中一个,或者添加多个同样的接口。AXI Streamm的Slave,也被称为Sink;AXI Streamm的Master,也被称为Source。

后续操作,和简单外设的操作一样。

  1. BD框图

在Block Design中,选择对应的IP。示例中是myip_stream。添加后,在Block Design中,得到如下IP。可以看到,myip_stream多了一个AXI Stream Master接口,也多了一个AXI Streamm Slave,及其对应的时钟和复位信号。

  1. AXI-DMA接口

AXI Streamm需要和IP “AXI DMA”搭配使用。使用AXI DMA的简单配置就可以,比如如下配置。

AXI DMA有一个AXI Lite接口,用于PS配置;有3个 AXI Master接口,M_AXI_SG, M_AXI_MM2S, M_AXI_S2MM,用于访问DDR等存储器;另外还有两个Stream接口,M_AXIS_MM2S, M_AXIS_S2MM,用于通过AXI Streamm接口交换数据。

  1. AXI-DMA连接

如下图所示,AXI DMA的AXI Lite接口,通过AXI Interconnect 连接到PS AXI Master接口,比如HPM0_FPD,供PS访问。

AXI DMA的3个AXI Master接口,M_AXI_SG, M_AXI_MM2S, M_AXI_S2MM,通过AXI Interconnect 连接到PS的AXI Slave接口,比如S_AXI_HP0_FPD。AXI DMA的两个Stream接口,M_AXIS_MM2S连接到用户IP的S00_AXIS, M_AXIS_S2MM连接到用户IP的M00_AXIS。

通过AXI DMA的驱动,软件可以发起MM2S传输,AXI DMA先通过M_AXI_SG从PS-DDR里读取DMA的描述符,得到数据的源地址,再通过M_AXIS_MM2S从PS-DDR里读取数据。软件也可以发起S2MM传输,AXI DMA先通过M_AXI_SG从PS-DDR里读取DMA的描述符,得到数据的目标地址,再通过M_AXIS_S2MM向PS-DDR里写数据。MM2S传输和S2MM传输既可以分开使用,也可以联合使用。如果联合使用,相当于从PS-DDR到PS-DDR的内存搬移工作。

6.1. 软件

AXI-DMA的相关软件设计,请参考 MPSoC逻辑加速模块数据通道快速设计

7. PL外设其它接口

7.1. 中断接口

用户外设还经常用到中断,用于向PS产生中断,通知某些事件。Vivado的工具Create and Package IP也可以创建支持中断功能的IP。大部分步骤,和前述“简单数据通路”一样。在“AXI Interfaces”窗口,勾选“Enable Interrupt Support”, 会得到一个S_AXI_INTR接口和一个中断输出信号irq。

通过AXI Interconnect,把S00_AXI和S_AXI_INTR接口连接连接到PS AXI Master接口,比如HPM0_FPD,供PS访问。把中断输出信号irq,通过IP Concat连接到PS的输入pl_ps_irq。

7.2. EMIO接口

PS还提供了简单的GPIO接口:EMIO。

在PS的配置界面下的GPIO里,使能EMIO,根据自己的需要选择数量。然后在BD界面下,就能看见EMIO的信号,包括输出、输入、和三态信号。工程师可以把自己的信号连接到EMIO信号上,就能使用。

软件通过访问GGPIO的Bank 3/4/5,可以控制GPIO,包括操作输出状态,和读取输入电平。

软件经常需要检查PL是否正常工作。很多时候,软件靠检查PL加载的done信号来确定。但done只能保证PL已经被加载,不能保证PL已经正常工作。比如,如果PL使用外部时钟,在外部时钟故障时,PL即使已经被加载,也没有工作。这时候,PS去访问PL的寄存器,会导致PS死机。更好的办法是,PL通过EMIO向PS反馈PL是否已经正常工作。比如PL实现计数器,把计数器的输出连接到EMIO的输入。软件读取EMIO的输入值,如果在变化,说明PL的计数器已经正常工作,那么就代表PL已经正常工作。

8. AXI Firewall

在开发过程中,可能有各种异常状况。如果AXI传输出现异常,可能导致PS死机,影响调试。为了提高系统可靠性,可以使用Xilinx提供的IP -- AXI Firewall,把它插在正常的AXI Master和 AXI Slave接口之间。下图是AXI Firewall的连接示例。

使用软件使能 AXI Firewall后,如果AXI传输出现异常,AXI Firewall会正常结束AXI传输,保证软件继续运行,工程师可以检查AXI传输的错误。AXI Firewall输出的错误信号和中断信号,都可以连接到PS GPIO,或者ILA。工程师可以读出具体的错误信息。

9. 参考文档

Zynq UltraScale+ MPSoC Embedded Design Methodology Guide 2017-03-31 Zynq UltraScale+ MPSoC Software Developers Guide 2019-07-01 Zynq UltraScale+ MPSoC Embedded Design Tutorial 2018-07-31 Zynq UltraScale+ MPSoC Technical Reference Manual 2019-08-21 UltraFast Embedded Design Methodology Guide 2018-04-20 Introducing the UltraFAST Embedded Design Methodology Checklist 2014-06-10

MPSoC逻辑加速模块数据通道快速设计

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • MicroBlaze访问Zynq-7000的OCM

    在ZC702单板上,MicroBlaze通过IC/DC端口连接到PS S_AXI_GP0,MicroBlaze读取OCM,得到值DECODE1C。 DECODE...

    hankfu
  • 在Linux用户态使用MPSoC AES 加密加速器

    文档Using Cryptography in Zynq UltraScale MPSoC提供了在Linux用户态使用MPSoC AES 加速器的例子。 如果要...

    hankfu
  • MPSoC逻辑加速模块数据通道快速设计

    最近十几年,整个芯片产业都感觉到了摩尔定律的放缓,甚至失效。根据A Domain-Specific Architecture for Deep Neural N...

    hankfu
  • 进阶的Redis之集群实战与哈希分片原理

    前面介绍了《进阶的Redis之数据持久化RDB与AOF》和《进阶的Redis之Sentinel原理及实战》,这次来了解下Redis的集群分片功能,以及其中哈希分...

    Zack说码
  • Redis中的哈希问题

    在说redis中的哈希(准确来说是一致性哈希)问题之前,先来看一个问题:为什么在分布式集群中一致性哈希会得到大量应用?

    大数据学习与分享
  • Prometheus + Grafana 构建 Redis 实时监控平台

    现在有各种各样的工具都可以对 Redis 进行监控,例如:redis-stat、RedisLive等,在使用过各种各样的监控工具后,个人感觉redis_expo...

    java进阶架构师
  • Flutter 学习笔记 13 - 动画 Tween

    AnimationController 对象的默认范围从 0.0 到 1.0。如果需要不同的范围或不同的数据类型,则可以使用 Tween 来配置动画以生成不同的...

    七适散人
  • 【经验分享】遵循10步法,应用系统发布效率大不同!

    回顾近年来企业的发展趋势,企业数字化转型的出现使得越来越多的业务演变成数字业务,数字化业务对信息技术提出了更高更严苛的要求,比如:快速响应市场需求,尽快交付让客...

    嘉为科技
  • 【Flutter 专题】92 图解 Dart 单线程实现异步处理之 Isolate (一)

    和尚刚尝试了 Future 和 async-await 实现的简单异步操作,但对于耗时较长的异步该如何处理呢?对于 Android 来说可以新开一个线程单独处理...

    阿策小和尚
  • Kubernetes 1.8.6 集群部署–监控redis(十三)

    老七Linux

扫码关注云+社区

领取腾讯云代金券