AXI4的PL与PS联合设计

Posted on 2020-07-08 23:10  绿叶落秋风  阅读(646)  评论(0编辑  收藏  举报

AXI4的PL与PS联合设计

1、实验原理

在前面的学习中,解决了如何利用一个缓冲寄存器控制另外一个寄存器的输入输出配置。接下来就是如何将PL设计直接导入到PS中实现资源互换。PS是可以通过AXI4总线访问从机的缓存寄存器,从机是可以直接调用PL设计的。只需要从机的IP的编辑界面正常的调用对应的module即可。这次的学习花费了很多时间,出现了许多软件操作错误,这里一一总结,以免日后再犯。

2、实验操作

(1)打开IP设计界面

这里的操作还是打开Ip封装界面,创建一个自定义的AXI4的总线IP。除了第二个界面选择一下create a new AXI4 peripheral之外,其他一路next即可。最后一个选择第二个edit IP,可以自动打开编辑IP界面。没有选择的话在IP category里找到自定义IP的名字后右击也是有edit IP in package的选项的。由于没有过多的选项,就不放图片了。

(2)IP中verilog文件的添加

这里有个十分特别的问题,如果直接从IP编辑界面新建一个文件,没有默认目录。自定义目录如果不在前面设计的工程中源文件目录的话,在完成编辑打包后该文件会自动丢失,无法再试打包。换言之,如果从其他目录引入文件到IP,只能使用一次就会失效。而且失效的文件还会占用在IP工程文件中,导致无法重新添加。这里的设置也没有细查,简单的解决方法就是先在创建的总工程中新建文件,然后在IP编辑界面添加源文件,这样就可以实现多次调用。好像在设置中看到IP打包时可以不删除添加的文件的设置,也没有验证,这里就不展开了。注意在总工程中创建后要移出工程(不要删除存储),以免对后面的步骤造成干扰。

下面是添加的部分:

module stream_led(
    input clk_user,
    input rst_n_user,
    input state_user,
    output reg [2:0] led_user
    );
    reg [25:0] cnt;
    always@(posedge clk_user or negedge rst_n_user)begin
        if(!rst_n_user)begin
            cnt<=1'b0;
        end
        else if(cnt==26'd50_000_000-1'b1)begin
            cnt<=1'b0;
        end
        else if(state_user)begin
            cnt<=cnt+1'b1;
        end
    end
    always@(posedge clk_user or negedge rst_n_user)begin
        if(!rst_n_user)begin
            led_user<=3'b0;
        end
        else if(cnt==26'd50_000_000-1'b1)begin
            case(led_user)
                3'b000:led_user<=3'b001;
                3'b001:led_user<=3'b010;
                3'b010:led_user<=3'b100;
                3'b100:led_user<=3'b001;
                default:led_user<=3'b000;
            endcase
        end
    end
endmodule

(3)连接模块

这个是verilog的基本操作了,这里我是在前面的设计的基础上连接的,所以使用的是slv_reg3来实现PS的输出作用到PL的。clk_user和rst_n_user都是PL的端口,可以直接连出。led_user也是PL的端口,直接连接到模块顶层即可。

    stream_led U1_user(
        .clk_user(CLK_USER),
        .rst_n_user(RST_N_USER),
        .state_user(slv_reg3),
        .led_user(LED_USER)
    );

(4)打包IP

这个操作在IP编辑界面的create and package IP中可以执行。第二个界面选择package your current project即可,其他一路next。

(5)IP的再编辑

一般来说,PL端的代码需要仿真后确认无误才能用于IP中,所以一般不会出问题。主要是端口的连接,这里出了问题也查不到。(由于偷懒,IP的文件添加后不会综合,直接打包,这也导致了一些问题,比较大的IP功能设计是应该综合并查看报告)IP核的再次编辑也是在IP category中找到自定义IP,右击后就会有edit IP in package的选项。有时候第一次打包IP的端口列表由于某些问题没有刷新到添加IP的BD界面上,也可以使用这个操作。

(6)已经完成顶层文件生成的IP的刷新

刷新IP在IP category中,只需要打开IP states(一般重新打包IP后会有提示),选择有感叹号的IP,update即可实现IPcategory中的刷新工作。对于已经添加IP到BD中,完成了顶层调用,或者已经综合映射完成的设计来说,刷新BD文件中IP需要BD文件generate output products(这个操作也是BD右击列表的功能,和自动例化IP的位置一样)。

有时候为了防止忘记,一般新建自定义IP到BD设计时也会刷新一次,在例化BD文件时才能保持一致。如果忘记这个操作:一般情况下可以生成bit流文件,但是无法导出xsa文件。

ERROR: [Common 17-69] Command failed: The current design is not implemented.
ERROR: [Common 17-69] Command failed: ERROR: [Common 17-69] Command failed: The current design is not implemented.

报错信息如上所示。感觉就是IP在BD中和category中不一致导致的。这会导致需要重新做一次流程,时间消耗还是巨大的。

(7)配置端口

输入输出口的配置还是在Elaborated design中实现,根据开发板原理图就可以配置。注意这里所有的配置都是针对PL配置。PS端的端口是由ARM核的寄存器来配置的。所以这里如果使用了PS端的端口的话会报错。

(8)生成XSA文件

在生成bit流后即可输出硬件,然后就可以供vitis使用了。输出硬件就是file的export中的第一个。

(9)软件测试

前面的操作就不多介绍了,就是导入硬件到ARM开发平台即可。直接看代码吧。

#include "xil_io.h"
#include "sleep.h"
#include "stdio.h"
#include "xparameters.h"
#define IP_BASE XPAR_MYIP_V1_0_0_BASEADDR
#define REG0_OFFSET 0
#define REG1_OFFSET 4
#define REG2_OFFSET 8
#define REG3_OFFSET 12
int main(){
    int BTN;
    Xil_Out32(IP_BASE+REG2_OFFSET,0xffff);
    while(1){
        BTN=Xil_In32(IP_BASE+REG1_OFFSET);

        Xil_Out32(IP_BASE+REG0_OFFSET,BTN);
        Xil_Out32(IP_BASE+REG3_OFFSET,1);

    }
}

注意,Xil_Out32(IP_BASE+REG3_OFFSET,1)这个语句就可以实现PS驱动PL的流水灯工作。前面的代码是来自前一次的学习。

3、实验结果

最后的板级验证是符合预期的。这里有一个额外的收获:调试时,打开调试按钮,PS部分的设计正常工作;关闭按钮,PS部分停止工作,但是PL部分还是会继续工作。这里体现了调试只是调试PS部分,PL部分是不受调试的影响的。PL的调试需要使用前面学习的ILA和VIO。