首页 > 其他分享 >基于ZCU104的PS和PL数据交互例程(三):vivado中创建IP

基于ZCU104的PS和PL数据交互例程(三):vivado中创建IP

时间:2023-10-24 20:11:24浏览次数:34  
标签:PS 例程 IP slv reg0 reg1 AXI reg

基于ZCU104的PS和PL数据交互例程(三):vivado中创建IP

以创建带有AXI-LITE接口的IP为例子

按照下面步骤创建

image-20231019172307099

image-20231019172349838 image-20231019172332688 image-20231019172557208

这里注意,这里选择的Number of Registers,会在后面的代码里面对应slv_reg0, slv_reg1, ..., slv_reg3

image-20231019172804671 image-20231019172831799

打开IP目录,右键刚才的IP,选择Eidt in IP Packager

image-20231019172920235

image-20231019173003224

controller_v1_0

双击打开controller_v1_0.v文件

添加端口

image-20231019204728025

连接端口

image-20231019204812847

controller_v1_0_S00_AXI_LITE

双击打开controller_v1_0_S00_AXI_LITE.v文件

添加端口

image-20231019204947581

添加必要逻辑

  1. 声明parameter

    image-20231020102811139

  2. 在前面声明变量

image-20231020102843051

  1. 修改slv_reg逻辑,这里的slv_reg就是当时选择的Number of Registers,在代码里面找到原来的代码,添加下面的逻辑

    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 
    	  //Add User logic
    	  else if (slv_reg_vld_axi[0] | slv_reg_vld_axi[1]) begin
    	    case (slv_reg_vld_axi)
                SLV0:begin
                    slv_reg0 <= slv_reg0_data;
                    slv_reg1 <= slv_reg1;
                    slv_reg2 <= slv_reg2;
                    slv_reg3 <= slv_reg3;
                end 
                SLV1:begin
                    slv_reg0 <= slv_reg0;
                    slv_reg1 <= slv_reg1_data;
                    slv_reg2 <= slv_reg2;
                    slv_reg3 <= slv_reg3;
                end
                default: begin
                    slv_reg0 <= slv_reg0;
                    slv_reg1 <= slv_reg1;
                    slv_reg2 <= slv_reg2;
                    slv_reg3 <= slv_reg3;
                end
            endcase
    	  end
          //Add User logic 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    
    

例化模块

先通过添加文件,添加两个新模块:reset_asyn_syn.vuser_ctrl.v

再完成例化

image-20231020102641949

异步复位同步释放

module reset_asyn_syn(
    input  clk      ,
    input  rst_asyn,
    output rstb_syn 
    );
    // maybe key jitter but not matter
    reg [1:0] reset_reg;
    always @(posedge clk or posedge rst_asyn) begin
        if(rst_asyn) begin
            reset_reg <= 2'b0;
        end
        else begin
            reset_reg[0] <= 1'b1;
            reset_reg[1] <= reset_reg[0];
        end
    end

    assign rstb_syn = reset_reg[1];

endmodule

控制逻辑

  1. 时钟:axi有个时钟,PL端有个时钟,可以是同一个,也可以是不同的。这里添加有跨时钟域处理。选择slv_reg0的bit0作为启动信号的判断,如果检测到slv_reg0_bit0的上升沿,则表示PS端要求启动PL端,所以拉高start_DUT信号一个周期。
  2. 状态机逻辑
状态机:

image-20231019211826698

注意事项:

1.读写slv_reg

对于slv_reg1的写入控制,内部模块输出一个数据slv_reg1_data,和对应的有效信号slv_reg1_vld。

然后在slv_reg1接受AXI_lite里面赋值的地方多加一组if-else情况,使得当AXI_lite写入数据时,赋值给slv_reg1;或者slv_reg1_vld拉高时,把slv_reg1_data赋值给slv_reg1;或者保持不变。

slv_reg0同理

2.简单的跨时钟域处理

这里注意写slv_reg的时候,属于跨时钟域操作,对于数据信号可以设置为静态数据,对于vld信号,可以通过打两拍同步到axi时钟域。这里axi的时钟域一般是100M,默认是快时钟域

代码

一般认为ctrl模块跟PL属于同时钟域,跟AXI属于跨时钟域。

module user_ctrl#(
    // Width of S_AXI data bus
	parameter integer C_S_AXI_DATA_WIDTH	= 32,
    // Width of FSM
    parameter FSM_WIDTH = 4,
    parameter IDLE      = 4'b1,
    parameter ENABLE    = 4'b10,
    parameter MYWAIT    = 4'b100,
    parameter FINISH    = 4'b1000
)(
    input                               pl_clk                  ,
    input                               axi_clk                 ,
    input                               pl_rstb                 ,
    input                               axi_rstb                ,
    
    input                               DUT_finish              ,

    input                               slv_reg0_bit0           ,

    output     [C_S_AXI_DATA_WIDTH-1:0]	slv_reg0_data           ,
    output                              slv_reg0_vld_axi        , 
    output     [C_S_AXI_DATA_WIDTH-1:0]	slv_reg1_data           ,
    output                              slv_reg1_vld_axi        ,  
         
    output                              start_DUT                                    
    );

    reg [FSM_WIDTH-1:0] FSM_state ;
    wire slv_reg0_vld,slv_reg1_vld;
    reg [1:0] slv_reg0_vld_reg , slv_reg1_vld_reg;
    
    always @(posedge pl_clk or negedge pl_rstb) begin
        if(!pl_rstb)
            FSM_state <= IDLE;
        else begin
            case (FSM_state)
                IDLE: begin
                    if (slv_reg0_bit0) begin
                        FSM_state <= ENABLE;
                    end
                end
                ENABLE:begin
                    FSM_state <= MYWAIT;
                end
                MYWAIT:begin
                    if (DUT_finish) begin
                        FSM_state <= FINISH;
                    end
                end
                FINISH:begin
                    FSM_state <= IDLE;
                end
                default: FSM_state <= IDLE;
            endcase
        end
    end
    //slv_reg0 output signals
    assign slv_reg0_data = {C_S_AXI_DATA_WIDTH{1'b0}};
    assign slv_reg0_vld  = (FSM_state == ENABLE) ? 1'b1 : 1'b0;

    //slv_reg1 output signals
    assign slv_reg1_data = {31'd0,1'b1};
    assign slv_reg1_vld  = (FSM_state == FINISH) ? 1'b1 : 1'b0;

    //translate to axi clk 
    assign slv_reg0_vld_axi = slv_reg0_vld_reg[1];
    assign slv_reg1_vld_axi = slv_reg1_vld_reg[1];

    always @(posedge axi_clk or negedge axi_rstb) begin
        if(!axi_rstb) begin
            slv_reg0_vld_reg <= 2'b0;
            slv_reg1_vld_reg <= 2'b0;
        end
        else begin
            slv_reg0_vld_reg <= {slv_reg0_vld_reg[0],slv_reg0_vld};
            slv_reg1_vld_reg <= {slv_reg1_vld_reg[0],slv_reg1_vld};
        end
    end
    //enable output 
    assign enable = (FSM_state == ENABLE) ? 1'b1 : 1'b0;
endmodule

封装IP

image-20231020103403476

具体的封装步骤,跟基于ZCU104的PS和PL数据交互例程(二):vivado中封装现有工程成IP类似,也可以参考正点原子2_启明星ZYNQ之嵌入式SDK开发指南_V2.0.pdf------>第六章 自定义IP核-呼吸灯实验

image-20231020103445199

标签:PS,例程,IP,slv,reg0,reg1,AXI,reg
From: https://www.cnblogs.com/shuiliu/p/17783512.html

相关文章

  • 【Java 进阶篇】JavaScript 自动跳转首页案例
    在这篇博客中,我们将创建一个JavaScript案例,演示如何自动跳转到网站的首页。这种自动跳转通常用于欢迎页面或广告页面等场景。我们将从头开始创建这个案例,逐步介绍相关的JavaScript知识,让初学者也能理解并实现这个功能。1.什么是自动跳转?自动跳转是指当用户访问一个网页时,页面会自......
  • 【Java 进阶篇】创建 JavaScript 轮播图:让网页焕发生机
    欢迎大家来到本篇博客,今天我们将一起探讨如何使用JavaScript创建一个精美的轮播图。轮播图是现代网站设计的关键元素之一,它能够使网页更加吸引人,提高用户体验。无需担心,本文将面向基础小白,从头开始解释每一步。我们将详细介绍如何构建一个轮播图,涵盖以下内容:什么是轮播图?创建HTML......
  • 【Java 进阶篇】JavaScript BOM(浏览器对象模型)详解
    BOM,即浏览器对象模型(BrowserObjectModel),是JavaScript与浏览器之间的接口,它允许JavaScript与浏览器进行交互,实现访问和控制浏览器窗口、文档和其他浏览器功能的功能。本文将详细介绍BOM的各个方面,包括窗口对象、定时器、历史记录、位置信息等,并提供示例代码来帮助您更好地理解和运......
  • 【Java 进阶篇】JavaScript电灯开关案例:从原理到实现
    JavaScript是一门强大的编程语言,它可以用来创建各种交互式网页应用。在这篇博客中,我们将通过一个简单的电灯开关案例来深入了解JavaScript的基础概念,包括HTML、CSS和JavaScript的结合使用。我们将从头开始构建这个案例,逐步引入相关概念,以帮助初学者更好地理解JavaScript的工作原理......
  • 【Java 进阶篇】JavaScript 事件详解
    在本篇博客中,我们将深入探讨JavaScript事件,这是网页交互的核心。我们将从什么是事件开始,然后逐步介绍事件的类型、如何注册事件、事件处理程序、事件对象以及事件冒泡等相关内容。最终,我们将提供大量的示例代码来帮助您更好地理解JavaScript事件。什么是事件?在Web开发中,事件是用户......
  • 21.4 Python 使用GeoIP2地图定位
    GeoIP2是一种IP地址定位库,它允许开发人员根据IP地址查找有关位置和地理位置的信息。它使用MaxMind公司的IP地址数据库,并提供一个方便的PythonAPI。GeoIP2可以用于许多不同的应用程序,例如网站分析、广告定位和身份验证。GeoIP2提供了许多不同的信息,例如国家、城市、邮政编码、经纬......
  • Apipost自动化测试使用教程
    Apipost提供可视化的API自动化测试功能,使用Apipost研发人员可以设计、调试接口,测试人员可以基于同一数据源进行测试,Apipost接口自动化功能在上次更新中进行了逻辑调整,带来更好的交互操作、更多的控制器选择,同时新增同步接口模式选择、测试数据选择功能。添加接口使用Apipost,研发......
  • Apipost自动化测试使用教程
    Apipost提供可视化的API自动化测试功能,使用Apipost研发人员可以设计、调试接口,测试人员可以基于同一数据源进行测试,Apipost接口自动化功能在上次更新中进行了逻辑调整,带来更好的交互操作、更多的控制器选择,同时新增同步接口模式选择、测试数据选择功能。添加接口使用Apipost,......
  • 21.4 Python 使用GeoIP2地图定位
    GeoIP2是一种IP地址定位库,它允许开发人员根据IP地址查找有关位置和地理位置的信息。它使用MaxMind公司的IP地址数据库,并提供一个方便的PythonAPI。GeoIP2可以用于许多不同的应用程序,例如网站分析、广告定位和身份验证。GeoIP2提供了许多不同的信息,例如国家、城市、邮政编码、经纬......
  • DevOps Tools
    DevOpsTools有一天我发现了这个有创造力的社区(bytebytego)和这些有创造力的工程师设计的流程图,很惊喜很喜欢,就把他们留存了下来。......