目录
1. 简介
2. 用法详解
2.1 需要的文件
2.1.1 RTL 函数签名
2.1.2 黑盒 JSON 描述文件
2.1.3 RTL IP 文件
2.2 操作步骤
3. 总结
1. 简介
Vitis HLS 工具可以将现有的 Verilog RTL IP(即硬件描述语言编写的模块)集成到 C/C++ HLS 项目中。通过这种方式,Vitis HLS 能够将 RTL 代码与 C/C++ 代码一起综合,形成最终的硬件设计。
RTL 黑盒允许设计者在 HLS 设计中的特定区域(如顺序区域、流水线区域或数据流区域)内使用 Verilog 或 VHDL 编写的 RTL IP。这样做的好处是可以重用现有的硬件模块,同时利用 HLS 的优势来加速整个设计和开发过程。
简单的说,如果你有一个用 Verilog 编写的性能优化好的 IP,可以将其作为黑盒插入到 HLS 项目中,而不需要将其重新用 C/C++ 实现。这样可以节省时间,并确保硬件设计的高效性和可靠性。
2. 用法详解
2.1 需要的文件
2.1.1 RTL 函数签名
RTL 代码的 C 语言函数签名,是指用于代表RTL模块的C函数的声明。这个签名定义了函数的名称、输入参数和返回类型,这样C代码就可以调用它,就像调用任何其他C函数一样。这个签名通常放在一个头文件(.h)中,以便在整个项目中使用。
#include "ap_int.h"
//--------------------------------------------------------
//RTL 代码的 C 语言函数签名
//--------------------------------------------------------
void rtl_model(ap_int<10> a1, ap_int<10> a2, ap_int<10> a3, ap_int<10> a4,
ap_int<10> b1, ap_int<10> b2, ap_int<10> b3, ap_int<10> b4,
ap_int<10>& z1, ap_int<10>& z2, ap_int<10>& z3, ap_int<10>& z4);
//--------------------------------------------------------
void example(ap_int<10> a1, ap_int<10> a2, ap_int<10> a3, ap_int<10> a4,
ap_int<10> b1, ap_int<10> b2, ap_int<10> b3, ap_int<10> b4,
ap_int<10>& sigma) {
ap_int<10> tmp1, tmp2, tmp3, tmp4;
rtl_model(a1, a2, a3, a4, b1, b2, b3, b4, tmp1, tmp2, tmp3, tmp4);
sigma = tmp1 + tmp2 + tmp3 + tmp4;
}
2.1.2 黑盒 JSON 描述文件
{
"c_function_name" : "rtl_model",
"rtl_top_module_name" : "rtl_model",
"c_files" : [{
"c_file" : "rtl_model.cpp",
"cflag" : ""
}],
"rtl_files" : [
"rtl_model.v"
],
"c_parameters" : [{
"c_name" : "a1",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "a1"
}
},
{
"c_name" : "a2",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "a2"
}
},
{
"c_name" : "a3",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "a3"
}
},
{
"c_name" : "a4",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "a4"
}
},{
"c_name" : "b1",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "b1"
}
},
{
"c_name" : "b2",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "b2"
}
},
{
"c_name" : "b3",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "b3"
}
},
{
"c_name" : "b4",
"c_port_direction" : "in",
"rtl_ports" : {
"data_read_in" : "b4"
}
},
{
"c_name" : "z1",
"c_port_direction" : "out",
"rtl_ports" : {
"data_write_out" : "z1",
"data_write_valid" : "z1_ap_vld"
}
},
{
"c_name" : "z2",
"c_port_direction" : "out",
"rtl_ports" : {
"data_write_out" : "z2",
"data_write_valid" : "z2_ap_vld"
}
},
{
"c_name" : "z3",
"c_port_direction" : "out",
"rtl_ports" : {
"data_write_out" : "z3",
"data_write_valid" : "z3_ap_vld"
}
},
{
"c_name" : "z4",
"c_port_direction" : "out",
"rtl_ports" : {
"data_write_out" : "z4",
"data_write_valid" : "z4_ap_vld"
}
}],
"rtl_common_signal" : {
"module_clock" : "ap_clk",
"module_reset" : "ap_rst",
"module_clock_enable" : "ap_ce",
"ap_ctrl_chain_protocol_idle" : "ap_idle",
"ap_ctrl_chain_protocol_start" : "ap_start",
"ap_ctrl_chain_protocol_ready" : "ap_ready",
"ap_ctrl_chain_protocol_done" : "ap_done",
"ap_ctrl_chain_protocol_continue" : "ap_continue"
},
"rtl_performance" : {
"latency" : "2",
"II" : "1"
},
"rtl_resource_usage" : {
"FF" : "0",
"LUT" : "0",
"BRAM" : "0",
"URAM" : "0",
"DSP" : "1"
}
}
2.1.3 RTL IP 文件
`timescale 100ps/100ps
(* use_dsp = "simd" *)
(* dont_touch = "1" *)
module rtl_model (input ap_clk, ap_rst, ap_ce, ap_start, ap_continue,
input [9:0] a1, a2, a3, a4, b1, b2, b3, b4,
output ap_idle, ap_done, ap_ready,
output z1_ap_vld, z2_ap_vld, z3_ap_vld, z4_ap_vld,
output reg [9:0] z1, z2, z3, z4);
wire ce = ap_ce;
reg [9:0] areg1, areg2, areg3, areg4;
reg [9:0] breg1, breg2, breg3, breg4;
reg dly1, dly2;
always @ (posedge ap_clk)
if (ap_rst)
begin
z1 <= 0;
z2 <= 0;
z3 <= 0;
z4 <= 0;
areg1 <= 0;
areg2 <= 0;
areg3 <= 0;
areg4 <= 0;
breg1 <= 0;
breg2 <= 0;
breg3 <= 0;
breg4 <= 0;
dly1 <= 0;
dly2 <= 0;
end
else if (ce)
begin
z1 <= areg1 + breg1;
z2 <= areg2 + breg2;
z3 <= areg3 + breg3;
z4 <= areg4 + breg4;
areg1 <= a1;
areg2 <= a2;
areg3 <= a3;
areg4 <= a4;
breg1 <= b1;
breg2 <= b2;
breg3 <= b3;
breg4 <= b4;
dly1 <= ap_start;
dly2 <= dly1;
end
assign z1_ap_vld = dly2;
assign z2_ap_vld = dly2;
assign z3_ap_vld = dly2;
assign z4_ap_vld = dly2;
assign ap_ready = dly2;
assign ap_done = dly2;
assign ap_idle = ~ap_start;
endmodule // rtl_model
2.2 使用 RTL 黑盒向导
整体步骤和常规的 Vitis HLS 步骤一致,特殊点在于多了一个 JSON 文件需要配置:
- 从顶层函数内或者从 Vitis HLS 工程的子函数内调用 C 语言函数签名。
- 在 Vitis HLS IDE 中使用“Add Files”(添加文件),将黑盒 JSON 描述文件添加到 HLS 工程中。
- 运行 Vitis HLS 设计文件照常进行仿真、综合和协同仿真。
使用 RTL 黑盒向导操作步骤:
在导航到工程中,打开 RTL 黑盒向导:
3. 总结
Vitis HLS 的引入为硬件设计师提供了一种灵活高效的设计途径,通过允许 RTL 黑盒的使用,设计师可以在不牺牲性能的前提下,重用现有的硬件模块,同时利用 HLS 的高层次抽象和快速迭代能力来加速设计和开发过程。这种方法既节省了将硬件模块重新用 C/C++ 实现的时间,也保持了设计的高效性和可靠性。通过简化操作步骤和提供直观的工具,如 RTL Blackbox Wizard,Vitis HLS 降低了硬件设计的复杂性,使得开发者能够更加专注于创新和优化。