爱游戏-在HLS中插入HDL代码

在HLS中插入HDL代码 时候:2024-11-29 13:50:14 手机看文章

扫描二维码随时随地手机看文章

良多人都比力反感用C/C++开辟(HLS)FPGA,大师第一谢绝的来由就是花费资本太多。可是HLS也有本身的长处,除快速构建算法外,还一个就是接口的生成,特别对AXI类接口,依照尺度语法便可以很便利地生成相干接口。

那末有无能操纵HLS的长处,又包括HDL的长处的方式呢?今天就来介绍一种在HLS中插入HDL代码的体例,连系二者的优势为FPGA开辟打造一把“白”。

申明

接下来,将介绍若何建立 Vitis-HLS 项目并将其与自界说 Verilog 模块集成一路。

将插入两个黑盒函数 - 第一个在流水线区域(线路接口,ap_none),第二个在数据流区域(FIFO 接口,ap_ctrl_chain)。

步调 1. 建立C/C++源文件(基在C的HLS模子+Testbench)

建立模块的 C/C++ 模子,此中包罗函数源代码(模块预期行动)和测试平台(io 刺激和成果查抄)。

按照ug1399-vitis-hls rtl黑盒,rtl黑盒遭到几个身分的限制:

应当是Verilog(.v)代码。 必需具有独一的时钟旌旗灯号和独一的高电平有用复位旌旗灯号。 必需有一个 CE 旌旗灯号,用在启用或住手 RTL IP。 可使用 ap_ctrl_chain 或 ap_ctrl_none 块级节制和谈。 仅撑持 C++。 没法毗连到顶层接口 I/O 旌旗灯号。 不克不及直接作为被测设计(DUT)。 不撑持布局或类类型接口。 main.cpp ——C/C++ 测试台。
#include "add.hpp" int main (void) {    static uint32_t a[1024];    static uint32_t b[1024];    static uint32_t c[1024];    static uint32_t c_stream[1024]; for (uint32_t i = 0; i for (uint32_t i = 0; i if (c[i] != a[i] + b[i]) { printf("Data does not match. %d vs %d\n", c[i], a[i] + b[i]); return -1;        } if (c[i] != c_stream[i]) { printf("Data does not match. %d vs %d\n", c[i], c_stream[i]); printf("Add modules have different results.\n"); return -2;        }    } printf("Test succesfull.\n"); return 0;}
add.hpp——函数声明。
#ifndef ADD_HPP #define ADD_HPP #include #include  void add(uint32_t a, uint32_t b, uint32_t  void add_stream(    hls::stream&a,    hls::stream&b,    hls::stream void scalar_to_stream(uint32_t a, hls::stream&a_stream);void stream_to_scalar(hls::stream&a_stream, uint32_t  void wrap(uint32_t a, uint32_t b, uint32_t  void top_module(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *c_stream); #endif 
add.cpp——函数源代码。
#include "add.hpp" void add(uint32_t a, uint32_t b, uint32_t &c) {    c = a + b;};void add_stream(    hls::stream&a,    hls::stream&b,    hls::stream&c) {    c.write(a.read() + b.read());};void scalar_to_stream(uint32_t a, hls::stream&a_stream) {    a_stream.write(a);};void stream_to_scalar(hls::stream&a_stream, uint32_t &a) {    a = a_stream.read();};void wrap(uint32_t a, uint32_t b, uint32_t &c) { #pragma HLS DATAFLOW hls::streamc_s;    hls::streama_s;    hls::streamb_s;    scalar_to_stream(a, a_s);    scalar_to_stream(b, b_s);    add_stream(a_s, b_s, c_s);    stream_to_scalar(c_s, c);};void top_module(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *c_stream) { #pragma HLS INTERFACE mode=m_axi port=a depth=1024 bundle=first #pragma HLS INTERFACE mode=m_axi port=b depth=1024 bundle=second #pragma HLS INTERFACE mode=m_axi port=c depth=1024 bundle=first #pragma HLS INTERFACE mode=m_axi port=c_stream depth=1024 bundle=second #pragma HLS INTERFACE mode=s_axilite port=return main_loop_pipeline: for (uint32_t i = 0; i for (uint32_t i = 0; i  2. 为 Vitis HLS建立设置装备摆设文件 

Vitis HLS需要设置装备摆设文件来构建项目。根基设置装备摆设文件应包括

Part——FPGA 部件编号。 syn.top——顶级函数名称。 tb.file——测试台文件。 syn.file — HLS 中利用的文件。

在此示例中,cfg 文件的最小版本以下所示:

part=xc7z007sclg225-1[hls]syn.top=top_moduletb.file=main.cppsyn.file=add.cppsyn.file=add.hpppackage.output.format=ip_catalogflow_target=vivado
3. 建立并构建最小项目

启动 Vitis,选择工作区并点击“建立 HLS 组件”。

更改组件位置和名称,单击下一步。

选择从现有设置装备摆设文件建立,点击下一步。

项目布局以下所示:

无需添加额外的标记,只需细心查抄顶部函数是不是是“top_module”,然后单击下一步。

选择芯片(默许部门应当是cfg文件中写的),单击下一步

确认flow_target和package.output.format,点击next。

查抄摘要并单击完成。

最后运行所有步调以确保所有设置装备摆设均已设置装备摆设并正常运行。

4.建立blackbox函数json

在此步调中,我们将用 blackbox verilog 代码替代我们的添加函数。在pipeline区域:

右键单击 hls_component 并单击“建立 RTL blackbox”,将生成 JSON 文件,描写 verilog 模块与其 C 函数之间的毗连。

选择包括 C 模块描写的文件。

选择端口标的目的并填写RTL组设置装备摆设(verilog模块中的端口名称)。

选择verilog文件,若有需要再填写其他框,单击下一步。

删除 ap_ctrl_chain_protocol 字符串,保存空白。单击完成。

对 add_stream 函数反复所有这些步调。

输入进步前辈先出:

输出进步前辈先出:

归纳综合:

不要点窜 ap_ctrl_chain 旌旗灯号,由于该模块将利用 ap_ctrl_chain 和谈。

尔后,hls_component 文件夹中应当会生成两个 json 文件。

add.json
{ "c_files": [    { "c_file": "add.cpp", "cflag": "" }  ], "c_function_name": "add", "rtl_files": [ "add.v" ], "c_parameters": [    { "c_name": "a", "c_port_direction": "in", "rtl_ports": { "data_read_in": "a" }    },    { "c_name": "b", "c_port_direction": "in", "rtl_ports": { "data_read_in": "b" }    },    { "c_name": "c", "c_port_direction": "out", "rtl_ports": { "data_write_out": "c", "data_write_valid": "c_vld" }    }  ], "rtl_top_module_name": "add", "rtl_performance": { "II": "0", "latency": "0" }, "rtl_resource_usage": { "BRAM": "0", "DSP": "0", "FF": "0", "LUT": "0", "URAM": "0" }, "rtl_common_signal": { "module_clock": "ap_clk", "module_reset": "ap_rst", "module_clock_enable": "ap_ce", "ap_ctrl_chain_protocol_idle": "", "ap_ctrl_chain_protocol_start": "", "ap_ctrl_chain_protocol_ready": "", "ap_ctrl_chain_protocol_done": "", "ap_ctrl_chain_protocol_continue": "" }}
add_stream.json
{ "c_files": [    { "c_file": "add.cpp", "cflag": "" }  ], "c_function_name": "add_stream", "rtl_files": [ "add_stream.v" ], "c_parameters": [    { "c_name": "a", "c_port_direction": "in", "rtl_ports": { "FIFO_empty_flag": "a_empty_flag", "FIFO_read_enable": "a_read_enable", "FIFO_data_read_in": "a" }    },    { "c_name": "b", "c_port_direction": "in", "rtl_ports": { "FIFO_empty_flag": "b_empty_flag", "FIFO_read_enable": "b_read_enable", "FIFO_data_read_in": "b" }    },    { "c_name": "c", "c_port_direction": "out", "rtl_ports": { "FIFO_full_flag": "c_full_flag", "FIFO_write_enable": "c_write_enable", "FIFO_data_write_out": "c" }    }  ], "rtl_top_module_name": "add_stream", "rtl_performance": { "II": "0", "latency": "0" }, "rtl_resource_usage": { "BRAM": "0", "DSP": "0", "FF": "0", "LUT": "0", "URAM": "0" }, "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" }}

主文件夹应与此近似:

hls_config.cfg 文件应当添加两新行( syn.blackbox.file)

part=xc7z007sclg225-1[hls]flow_target=vivadocsim.code_analyzer=0syn.top=top_modulesyn.blackbox.file=add.jsonsyn.blackbox.file=add_stream.jsontb.file=main.cppsyn.file=add.cppsyn.file=add.hpp
5.建立Verilog黑盒函数

函数“add”必需具有ap_none接口,而且 ap_none 作为模块接口。(有关模块接口的更多信息,请查看https://docs.amd.com/r/en-US/ug1399-vitis-hls/JSON-File-for-RTL-Blackbox 。)

按照UG1399,端口a和b是32位宽度的输入端口,输出c端口也是32位宽度,但带有额外的有用旌旗灯号,我们称之为c_vld。模块还需要ap_clk,ap_ce,ap_rst端口。

Verilog 以下所示:

add.v
`timescale 1ns/1psmodule add (    input [31:0] a,    input [31:0] b,    output [31:0] c,    output c_vld,    input ap_ce,    input ap_rst,    input ap_clk);    reg [31:0] c_d;    reg c_vld_d;    assign c = c_d;    assign c_vld = c_vld_d;    always @(posedge ap_clk) begin if (ap_rst == 1'b1) begin        c_d b0;        c_vld_d 'b0;    end else begin        c_d 

运行 C 综合和 C/RTL 协同仿真。可以或许在 HLS 模块中看到打包的 add.v 文件。

单击 hls_config.cfg 文件,在 Vitis GUI 的帮忙下将 cosim.trace_level 更改成全数并运行结合仿真。

单击波形查看器。Vivado 会弹出 XSIM。

将 grp_add_fu_134 旌旗灯号添加到 wcfg

函数行动很希奇,接下来在 json 中更改黑盒函数 II,看看它若何影响仿真。打开 add.json 并将 II 更改成 10。再次运行 C 综归并从头运行 C/RTL 协同仿真。

add.v 模块是不是杰出且可以正常工作?其行动是不是准确?模块是不是正常工作由哪些身分决议?“fixing”模块对资本利用有何影响?

那末 add_stream 呢?函数位在数据流区域,而且必需包括 fifo 端口和 ap_ctrl_chain 和谈。

add_stream.v
`timescale 1ns/1psmodule add_stream (    input [31:0] a,    input a_empty_flag,    output a_read_enable,    input [31:0] b,    input b_empty_flag,    output b_read_enable,    output [31:0] c,    input c_full_flag,    output c_write_enable,    output ap_idle,    input ap_start,    output ap_ready,    output ap_done,    input ap_continue,    input ap_ce,    input ap_rst,    input ap_clk);    reg a_read_enable_d;    reg b_read_enable_d;    reg c_write_enable_d;    reg [31:0] c_d;    assign a_read_enable = a_read_enable_d;    assign b_read_enable = b_read_enable_d;    assign c_write_enable = c_write_enable_d;    assign c = c_d;    assign ap_idle = !ap_start;    assign ap_ready = ap_start;    assign ap_done = ap_start;    //Flags are negated...    assign flags_good = a_empty_flag && b_empty_flag && c_full_flag;    assign hs_good = ap_start && ap_continue;    always @(posedge ap_clk) begin if (ap_rst == 1'b1) begin            a_read_enable_d b1) begin            a_read_enable_d 

欲知详情,请下载word文档 下载文档

上一篇:爱游戏-芯鲜事 下一篇:爱游戏-米尔电子