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
此次例程也比较简单,有两个模块module1
和module2
,module1
中输出a
和b
,在module2
中完成加法后再返还给module1
,最终输出的led=c | a
。
首先用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
)
下面我们把程序稍作改动,将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_abc
,my_itf.mod1
就表示my_itf接口的方向按照mod1
中指定的,而且代码中的a、b、c要相应的换成itf_abc.a
、itf_abc.b
、itf_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如下,跟上面的图只是名字不同,电路是一样的。
FPGA时序约束教程
FPGA时序约束理论篇之建立保持时间
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