hls简介
高级综合(high-level synthesis,简称 HLS)能自动把 C/C++ 之类的高级语言转化成 Verilog/VHDL 之类的底层硬件描述语言(RTL),生成定制硬件在 FPGA 上跑实现加速。这使得不懂硬件的软件工程师也可以拥有玩转硬件的能力。HLS 的存在已有多年,它的优点,极短的开发和验证时间
Xilinx 推出的 Vivado HLS 工具可以直接使用C、C++或 System C 来对 Xilinx 系列的 FPGA 进行编程,从而提高抽象的层级,大大减少了使用传统 RTL描述进行 FPGA 开发所需的时间。
在对 HLS 设计进行综合之前,我们要先对其进行“功能性验证”,也就是 C 仿真,其目的是验证 HLS 输入的 C 代码的功能是否正确。验证的方式就是在 TestBench 中调用 C 设计的函数,然后将其输出与“黄金参考”进行比对,如果与黄金参考有差异就需要先对 C 设计进行修改调试。
hls项目
接下来就是对设计进行高层综合,即 HLS 过程本身。该过程涉及到分析和处理基于 C 的代码,加上用户所给出的指令和约束,来创建 RTL 描述。高层综合结束后会产生一组输出文件,包括以 Veilog 或者VHDL 语言编写的 RTL 设计文件。
添加源文件:
示例代码
hls_hello.h:
#ifndef _HLS_HELLO_H_
#define _HLS_HELLO_H_
#include "ap_int.h"
#define CNT_MAX 100000000
//#define CNT_MAX 100
#define FLASH_FLAG CNT_MAX-2
//typedef int led_t;
//typedef int cnt_t;
// 修改指定位宽,如果使用 int 则会默认使用 32 位宽,我们并不需要,所以选择自定义位宽
typedef ap_int<1> led_t;
typedef ap_int<32> cnt_t;
void flash_led(led_t *led_o , led_t led_i);
#endif
hls_hello.cpp:
#include "hls_hello.h"
void flash_led(led_t *led_o , led_t led_i){
#pragma HLS INTERFACE ap_vld port=led_i
#pragma HLS INTERFACE ap_ovld port=led_o
cnt_t i;
for(i=0;i<CNT_MAX;i++){
//#pragma HLS PIPELINE
if(i==FLASH_FLAG){
*led_o = ~led_i;
}
}
}
添加测试文件:
选择开发板:
hls_hello_tb.cpp:
#include "hls_hello.h"
#include <stdio.h>
int main(){
led_t led_i=0x01;
led_t led_o;
const int SHIFT_TIME = 4;
int i;
for(i=0;i<SHIFT_TIME;i++){
flash_led(&led_o , led_i);
led_i = led_o;
printf("shift_out is %d \n",(int)(led_o&0x01));
}
}
project run c simulation
在设置里设置top function
solution,run c synthesis生成veriolg文件
这是生成的verilog文件:
// ==============================================================
// RTL generated by Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2022.2 (64-bit)
// Version: 2022.2
// Copyright (C) Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="flash_led_flash_led,hls_ip_2022_2,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z020-clg400-2,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=3.265750,HLS_SYN_LAT=100000002,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=33,HLS_SYN_LUT=112,HLS_VERSION=2022_2}" *)
module flash_led (
ap_clk,
ap_rst,
ap_start,
ap_done,
ap_idle,
ap_ready,
led_o,
led_o_ap_vld,
led_i,
led_i_ap_vld
);
parameter ap_ST_fsm_state1 = 3'd1;
parameter ap_ST_fsm_state2 = 3'd2;
parameter ap_ST_fsm_state3 = 3'd4;
input ap_clk;
input ap_rst;
input ap_start;
output ap_done;
output ap_idle;
output ap_ready;
output [0:0] led_o;
output led_o_ap_vld;
input [0:0] led_i;
input led_i_ap_vld;
reg ap_done;
reg ap_idle;
reg ap_ready;
reg led_o_ap_vld;
(* fsm_encoding = "none" *) reg [2:0] ap_CS_fsm;
wire ap_CS_fsm_state1;
reg [0:0] led_i_preg;
reg [0:0] led_i_in_sig;
reg led_i_ap_vld_preg;
reg led_i_ap_vld_in_sig;
reg led_i_blk_n;
wire [0:0] neg_i_fu_67_p2;
reg [0:0] neg_i_reg_111;
reg [26:0] i_V_fu_50;
wire [26:0] i_V_2_fu_87_p2;
wire ap_CS_fsm_state2;
wire [0:0] icmp_ln1027_fu_81_p2;
reg ap_block_state1;
wire [0:0] icmp_ln1019_fu_93_p2;
wire ap_CS_fsm_state3;
reg [2:0] ap_NS_fsm;
reg ap_ST_fsm_state1_blk;
wire ap_ST_fsm_state2_blk;
wire ap_ST_fsm_state3_blk;
wire ap_ce_reg;
// power-on initialization
initial begin
#0 ap_CS_fsm = 3'd1;
#0 led_i_preg = 1'd0;
#0 led_i_ap_vld_preg = 1'b0;
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
ap_CS_fsm <= ap_ST_fsm_state1;
end else begin
ap_CS_fsm <= ap_NS_fsm;
end
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
led_i_ap_vld_preg <= 1'b0;
end else begin
if ((1'b1 == ap_CS_fsm_state3)) begin
led_i_ap_vld_preg <= 1'b0;
end else if ((~((ap_start == 1'b0) & (1'b1 == ap_CS_fsm_state1)) & (led_i_ap_vld == 1'b1))) begin
led_i_ap_vld_preg <= led_i_ap_vld;
end
end
end
always @ (posedge ap_clk) begin
if (ap_rst == 1'b1) begin
led_i_preg <= 1'd0;
end else begin
if ((~((ap_start == 1'b0) & (1'b1 == ap_CS_fsm_state1)) & (led_i_ap_vld == 1'b1))) begin
led_i_preg <= led_i;
end
end
end
always @ (posedge ap_clk) begin
if ((~((ap_start == 1'b0) | (led_i_ap_vld_in_sig == 1'b0)) & (1'b1 == ap_CS_fsm_state1))) begin
i_V_fu_50 <= 27'd0;
end else if (((icmp_ln1027_fu_81_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
i_V_fu_50 <= i_V_2_fu_87_p2;
end
end
always @ (posedge ap_clk) begin
if ((1'b1 == ap_CS_fsm_state1)) begin
neg_i_reg_111 <= neg_i_fu_67_p2;
end
end
always @ (*) begin
if (((ap_start == 1'b0) | (led_i_ap_vld_in_sig == 1'b0))) begin
ap_ST_fsm_state1_blk = 1'b1;
end else begin
ap_ST_fsm_state1_blk = 1'b0;
end
end
assign ap_ST_fsm_state2_blk = 1'b0;
assign ap_ST_fsm_state3_blk = 1'b0;
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state3)) begin
ap_done = 1'b1;
end else begin
ap_done = 1'b0;
end
end
always @ (*) begin
if (((ap_start == 1'b0) & (1'b1 == ap_CS_fsm_state1))) begin
ap_idle = 1'b1;
end else begin
ap_idle = 1'b0;
end
end
always @ (*) begin
if ((1'b1 == ap_CS_fsm_state3)) begin
ap_ready = 1'b1;
end else begin
ap_ready = 1'b0;
end
end
always @ (*) begin
if ((led_i_ap_vld == 1'b1)) begin
led_i_ap_vld_in_sig = led_i_ap_vld;
end else begin
led_i_ap_vld_in_sig = led_i_ap_vld_preg;
end
end
always @ (*) begin
if (((ap_start == 1'b1) & (1'b1 == ap_CS_fsm_state1))) begin
led_i_blk_n = led_i_ap_vld;
end else begin
led_i_blk_n = 1'b1;
end
end
always @ (*) begin
if ((led_i_ap_vld == 1'b1)) begin
led_i_in_sig = led_i;
end else begin
led_i_in_sig = led_i_preg;
end
end
always @ (*) begin
if (((icmp_ln1019_fu_93_p2 == 1'd1) & (icmp_ln1027_fu_81_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
led_o_ap_vld = 1'b1;
end else begin
led_o_ap_vld = 1'b0;
end
end
always @ (*) begin
case (ap_CS_fsm)
ap_ST_fsm_state1 : begin
if ((~((ap_start == 1'b0) | (led_i_ap_vld_in_sig == 1'b0)) & (1'b1 == ap_CS_fsm_state1))) begin
ap_NS_fsm = ap_ST_fsm_state2;
end else begin
ap_NS_fsm = ap_ST_fsm_state1;
end
end
ap_ST_fsm_state2 : begin
if (((icmp_ln1027_fu_81_p2 == 1'd0) & (1'b1 == ap_CS_fsm_state2))) begin
ap_NS_fsm = ap_ST_fsm_state2;
end else begin
ap_NS_fsm = ap_ST_fsm_state3;
end
end
ap_ST_fsm_state3 : begin
ap_NS_fsm = ap_ST_fsm_state1;
end
default : begin
ap_NS_fsm = 'bx;
end
endcase
end
assign ap_CS_fsm_state1 = ap_CS_fsm[32'd0];
assign ap_CS_fsm_state2 = ap_CS_fsm[32'd1];
assign ap_CS_fsm_state3 = ap_CS_fsm[32'd2];
always @ (*) begin
ap_block_state1 = ((ap_start == 1'b0) | (led_i_ap_vld_in_sig == 1'b0));
end
assign i_V_2_fu_87_p2 = (i_V_fu_50 + 27'd1);
assign icmp_ln1019_fu_93_p2 = ((i_V_fu_50 == 27'd99999998) ? 1'b1 : 1'b0);
assign icmp_ln1027_fu_81_p2 = ((i_V_fu_50 == 27'd100000000) ? 1'b1 : 1'b0);
assign led_o = neg_i_reg_111;
assign neg_i_fu_67_p2 = (led_i_in_sig ^ 1'd1);
endmodule //flash_led
可以看到很简单的流水灯花了很大的篇幅,我感觉没有verilog自己动手写方便。
solution,run rtl cosimulation生成波形仿真文件