使用SystemVerilog简化FPGA中的接口

  FPGA工程师们应该都会吐槽Verilog的语法,相当的不友好,尤其是对于有很多接口的模块,像AXI4/AXI-Lite这种常用的总线接口,动不动就好几十根线,写起来是相当费劲。

  当然现在Xilinx推荐使用纯bd文件的方式来设计FPGA,这样HDL代码就会少了很多。但我们大多数的工程还是无法避免使用HDL来连接两个module。所以本文就推荐使用SystemVerilog来简化FPGA中接口的连接方式。

  也许很多FPGA工程师对SystemVerilog并不是很了解,因为以前的FPGA开发工具是不支持SystemVerilog的,导致大家都是用VHDL或者Verilog来开发,但现在Vivado对SystemVerilog的支持已经比较好了,完全可以使用SystemVerilog写出可综合的FPGA程序,而且FPGA开发中只会使用的SystemVerilog语法的一小部分,入门也很快,因此建议FPGA工程师学一下SystemVerilog。

本文中用到的logic关键字的解释可以参考SystemVerilog教程之数据类型1

  此次例程也比较简单,有两个模块module1module2module1中输出ab,在module2中完成加法后再返还给module1,最终输出的led=c | a

使用SystemVerilog简化FPGA中的接口_第1张图片 image-20200720203534072

  首先用Verilog来实现,代码也比较简单,就简单解释一句:文件格式都是.sv,这是因为SystemVerilog的语法都是包含Verilog的。

//top.sv
module top(
 input        clk,
 input        rst,
 output [3:0] led
 );

logic    [3:0] a ;
logic    [3:0] b ;
logic    [3:0] c ;

module1 inst_module1(
    .clk  (clk  ),
    .rst  (rst  ),
    .a    (a),
    .b    (b),
    .c    (c),
    .led  (led)
    );   

module2 inst_module2(
    .clk  (clk  ),
    .rst  (rst  ),
    .a    (a),
    .b    (b),
    .c    (c)
    );  

endmodule

// module1.sv
module module1(
 input clk,
 input rst,
 output logic [3:0] a,
 output logic [3:0] b,
 input  logic [3:0] c,
 output logic [3:0] led
    );

 assign led = c | a;

 always @ ( posedge clk ) begin
    if(rst) begin
        a <= 4'd1;
        b <= 4'd2;
    end
    else begin
        a <= a + 1'b1;
        b <= b + 1'b1;
    end
 end 

endmodule

// module2.sv

module module2(
 input clk,
 input rst,
 input  logic [3:0] a,
 input  logic [3:0] b,
 output logic [3:0] c
    );

 always @ ( posedge clk ) begin
    if(rst) 
        c <= 4'd1;
    else 
        c <= a + b;
 end 

endmodule

综合之后的Schematic如下图所示:(为了更好的表示电路结构,我将flatten_hierarchy选为了none

使用SystemVerilog简化FPGA中的接口_第2张图片 image-20200720192328527

  下面我们把程序稍作改动,将a/b/c三个接口使用SystemVerilog中的interface来连接。

  在工程中添加my_itf.sv文件如下:

// my_itf.sv
interface my_itf;
   logic [3:0] a, b, c;

   modport mod1 (input c,    output a, b);
   modport mod2 (input a, b, output c  );

endinterface : my_itf

关键字interface就表示要创建一个接口模块,里面包含了3个接口:a/b/c。

modport定义了这三个接口的方向,对于module1来说,a和b是输出,c是输入;对于module2来说,a和b是输入,c是输出。

注:也可以不使用modport,Vivado会根据代码自动推断出接口的方向,但不建议这么做

修改module1.sv如下,其中a/b/c端口换成了my_itf.mod1 itf_abcmy_itf.mod1就表示my_itf接口的方向按照mod1中指定的,而且代码中的a、b、c要相应的换成itf_abc.aitf_abc.bitf_abc.c.

// module1.sv
module module1(
 input clk,
 input rst,
 my_itf.mod1 itf_abc,
 output logic [3:0] led
    );

 assign led = itf_abc.c | itf_abc.a;

 always @ ( posedge clk ) begin
    if(rst) begin
        itf_abc.a <= 4'd1;
        itf_abc.b <= 4'd2;
    end
    else begin
        itf_abc.a <= itf_abc.a + 1'b1;
        itf_abc.b <= itf_abc.b + 1'b1;
    end
 end 

endmodule

修改module2.sv代码如下,原则跟上面是一样的,不再赘述。

// module2.sv
module module2(
 input clk,
 input rst,
 my_itf.mod2 itf_abc
    );


 always @ ( posedge clk ) begin
    if(rst) 
        itf_abc.c <= 4'd1;
    else 
        itf_abc.c <= itf_abc.a + itf_abc.b;
 end 

endmodule

修改top.sv如下,例化my_itf接口,将itf_abc.mod1传给module1,将itf_abc.mod2传给module2.

// top.sv
module top(
 input        clk,
 input        rst,
 output [3:0] led
    );

    logic    [3:0] a ;
    logic    [3:0] b ;
    logic    [3:0] c ;

    my_itf itf_abc();

    module1 inst_module1(
        .clk       (clk  ),
        .rst       (rst  ),
        .itf_abc   (itf_abc.mod1),
        .led       (led)
    );   

    module2 inst_module2(
        .clk       (clk  ),
        .rst       (rst  ),
        .itf_abc   (itf_abc.mod2)
    );  

endmodule

大功告成!!!

综合后Schematic如下,跟上面的图只是名字不同,电路是一样的。

使用SystemVerilog简化FPGA中的接口_第3张图片 image-20200720201342972

FPGA时序约束教程

  1. FPGA时序约束理论篇之建立保持时间

  2. FPGA时序约束理论篇之时序路径与时序模型

   3. FPGA时序约束理论篇之IO约束

   4. FPGA时序约束理论篇之时钟周期约束

   5. FPGA时序约束理论篇之两种时序例外

   6. FPGA时序约束理论篇之xdc约束优先级

   7. FPGA时序约束实战篇之梳理时钟树

   8. FPGA时序约束实战篇之主时钟约束

   9. FPGA时序约束实战篇之衍生时钟约束

  10. FPGA时序约束实战篇之延迟约束

  11. FPGA时序约束实战篇之伪路径约束

  12. FPGA时序约束实战篇之多周期路径约束

  13. Vivado时序约束辅助工具

  14. FPGA时序约束之Tcl命令的对象及属性

微信公众号:Quant_Times

你可能感兴趣的:(使用SystemVerilog简化FPGA中的接口)