HLS+各种接口实现案例(mm_master、mm_slave、pointer、mm_stream interface)

本文详细介绍了HLS组件中各种接口的使用,包括指针参数、Avalon Streaming Interfaces、Avalon Memory-Mapped Master Interfaces以及Slave Interfaces。重点阐述了接口的读写方式、数据传输特点和内存映射。同时,讨论了阻塞与非阻塞调用的区别,以及如何通过start、busy、stall和done信号进行交互。
摘要由CSDN通过智能技术生成

Pointer_arguments

  • 所有指针或引用参数都变成地址输入
  • 所有指针共享一个Avalon内存映射接口,用于从系统内存加载
    在这里插入图片描述
#include <stdio.h>
#include "HLS/hls.h"

component int dut(int a, int *b, int i) {
    return a*b[i];
}

int main()
{
    int a=3;
    int b[4] = {1,2,3,4};
    int ret;
    ret = dut(3,b,2);
    printf("ret:%d\n",ret);
    return 0;
}

在这里插入图片描述
通过字节使能ff 低8bit为有效,为什么是0000000400000003 因为从i=2后的地址读取数据了,但是因为字节使能的原因 ,所以 03 有效与a=3相乘,结果为9
在这里插入图片描述
如果组件dut把busy信号拉高,那么调用dut的模块需要把start信号拉高直到busy拉低;如果dut的下游部件把stall信号拉高,那么dut需要将done信号拉高直到stall信号拉低。

Avalon Streaming Interfaces

白嫖知识:

  • 阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
  • 非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
  • 组件可以具有符合Avalon-ST接口规范的输入和输出流。这些输入和输出流在C源中通过将对ihc::stream_in<>和ihc::stream_out<>对象的引用作为对组件的函数参数来表示。
  • 一个组件调用可以从一个流中读取多次。
  • 不能从流类派生新类,或将它们封装为其他格式,如结构或数组
  • 一个组件可以为一个流有多个读取站点,同样一个组件可以为同一流拥有多个写入站点。
  • 在组件中,不能保证不同流的执行顺序,除非流之间存在数据依赖性。

stream_in

#include <stdio.h>
#include "HLS/hls.h"

 // Blocking read    
component void foo (ihc::stream_in<int> &a) {
    int x = a.read();     //阻塞从组件内部使用的读调用  
}
 // Non-blocking read
component void foo_nb (ihc::stream_in<int> &a) {
    bool success = false;
    /*从组件内部使用的非阻塞读调用。
    如果读取是有效的,则将success bool设置为true。
    如果使用tryRead,则组件的x86-64结果可能与FPGA结果不匹配,因为仿真没有建模阻塞和非阻塞读取的硬件行为。*/
    int x = a.tryRead(success);  
    if (success) {
    // x is valid
    }
}
int main() {
    ihc::stream_in<int> a;
    ihc::stream_in<int> b;
    for (int i = 0; i < 10; i++) {
        a.write(i);    //从测试台中使用阻塞写入调用来填充要发送到组件的FIFO
        b.write(i);
    }
    foo(a);
    foo_nb(b);
}

在这里插入图片描述

stream_out

#include <stdio.h>
#include "HLS/hls.h"

// Blocking write
component void foo (ihc::stream_out<int> &a) {
    static int count = 0;
    for(int idx = 0; idx < 5; idx ++){
        a.write(count++); // Blocking write  阻塞组件的写调用
    }
}
// Non-blocking write
component void foo_nb (ihc::stream_out<int> &a) {
    static int count = 0;
    for(int idx = 0; idx < 5; idx ++){
        bool success = a.tryWrite(count++); // Non-blocking write 组件的非阻塞写调用。返回值表示写入是否成功。
        if (success) {
        // write was successful
        }
    }
}
int main() {
    ihc::stream_out<int> a;
    ihc::stream_out<int> b;
    foo(a); // or foo_nb(a);
    foo_nb(b);
    
    // copy output to an array
    int outputData[5];
    for (int idx = 0; idx < 5; idx++) {
        outputData[idx] = a.read();  //从测试台中使用阻塞读调用从组件中读回数据
    }

    int outputData_b[5];
    for (int idx = 0; idx < 5; idx++) {
        outputData_b[idx] = b.read();  //从测试台中使用非阻塞读调用从组件中读回数据
    }

}

在这里插入图片描述

使用包信号允许多个流调用站点

在这里插入图片描述
在流接口上公开starttofpacket和endofpacket边带信号,可以被基于读写的包访问
在这里插入图片描述
仅当设置了usesPackets时可用。
用带外的starttofpacket和endofpacket信号阻塞读取。

#include <stdio.h>
#include "HLS/hls.h"

component int reduce_sum(
    ihc::stream_in<int,ihc::usesPackets<true> > &int_in
)
{
    int val; int sum = 0;
    bool start_of_packet = false;
    bool end_of_packet = false;
    while(!start_of_packet)
        val = int_in.read(start_of_packet,end_of_packet);
    sum += val;
    while(!end_of_packet)
    {
        val = int_in.read(start_of_packet,end_of_packet);
        sum += val;
    }
    return sum;      
}

int main()
{
    ihc::stream_in<int,ihc::usesPackets<true> > a;
    int sum;
    
    for (int i = 0; i < 5; i++) {
        bool start_of_packet = (i==0);
        bool end_of_packet = (i==5-1);
        a.write(i,start_of_packet,end_of_packet);    //从测试台中使用阻塞写入调用来填充要发送到组件的FIFO
    }
    sum = reduce_sum(a);
    printf("sum:%d\n",sum);
    return 0; 
}

Avalon Memory-Mapped Master Interfaces

组件可以通过Avalon内存映射与外部内存接口mm_master<>。您可以使用函数指针参数或引用参数隐式指定Avalon MM Master接口,也可以显式使用“HLS/hls .h”头文件中定义的mm_master<>类。

在这里插入图片描述
在这里插入图片描述

Implicit Example

下面的代码示例仲裁加载和存储指令,这些指令来自组件顶级模块上单个接口的两个指针解引用。这个接口的数据总线宽度为64位,地址宽度为64位,固定延迟为1。

#include <HLS/hls.h>
#include <stdio.h>
component void dut(int *prt1,int *prt2)
{
    *prt1 += *prt2;
    *prt2 += prt1[1];
}
int main()
{
    int x[2]={0,1};
    int y = 2;
    dut(x,&y);
    return 0;
}

在这里插入图片描述

Explicit Example

这个示例演示了如何使用显式mm_master类为特定内存接口优化前面的代码片段。mm_master类有一个已定义的模板,它具有以下特征:

  • 每个接口都有一个唯一的ID,它推断出两个独立的接口,减少了组件中仲裁的数量。
  • 数据总线宽度大于默认的64位宽度。
  • 地址总线宽度小于默认的64位宽度。
  • 接口的延迟固定为2。

通过定义这些特征,可以声明系统在两个时钟周期之后返回有效的读数据,并且接口在读写时从不停止,但是系统必须能够提供两个不同的内存。一个唯一的空间被期望对应一个唯一的物理内存。如果将具有相同空间的多个Avalon-MM Master接口连接到相同的物理内存,那么Intel HLS编译器无法确保任何内存依赖项的功能正确性。

#include <HLS/hls.h>
#include <stdio.h>

// #ifndef DEBUG_TYPEDEF
#define DEBUG_TYPEDEF 1
// #endif 
//组件的每个参数都会生成地址的输入(参数)管道
#if DEBUG_TYPEDEF
typedef ihc::mm_master< int,ihc::dwidth<256>,
                            ihc::awidth<32>,
                            ihc::aspace<1>,
                            ihc::latency<2> >Master1;



typedef ihc::mm_master< int,ihc::dwidth<256>,
                            ihc::awidth<32>,
                            ihc::aspace<4>,
                            ihc::latency<2> >Master2;    


component void dut(Master1 &mm1,Master2 &mm2)
{
    *mm1 += *mm2;         
    *mm2 += mm1[1];
}
#else
component void dut(
    ihc::mm_master< int,ihc::dwidth<256>,ihc::awidth<32>,ihc::aspace<1>,ihc::latency<2> > &mm1,
    ihc::mm_master< int,ihc::dwidth<256>,ihc::awidth<32>,ihc::aspace<4>,ihc::latency<2> > &mm2)
{
    *mm1 += *mm2;         
    *mm2 += mm1[1];
}

#endif
int main()
{
    int x[2]={1,2};
    int y = 3;
    //使用Avalon内存映射(MM)主类实例的组件
    //(mm_master<>)来描述它们的内存接口,
    //必须在testbench中为每个mm_master参数创建一个mm_master<>对象。
    //创建构造函数,来实例化mm_master<>对象
    //ihc::mm_master<int, … > mm(void* ptr, int size, bool use_socket=false);
    #if DEBUG_TYPEDEF
    Master1 mm_x(x,2*sizeof(int),false);
    Master2 mm_y(&y,1*sizeof(int),false);
    #else
    ihc::mm_master<int,ihc::dwidth<256>,ihc::awidth<32>,ihc::aspace<1>,ihc::latency<2> > mm_x(x,2*sizeof(int),false);
    ihc::mm_master<int,ihc::dwidth<256>,ihc::awidth<32>,ihc::aspace<4>,ihc::latency<2> > mm_y(&y,1*sizeof(int),false);
    #endif
    //调用组件
    dut(mm_x,mm_y);
    return 0;
}

Slave Interfaces

Intel HLS Compiler提供了两种不同类型的从接口,您可以在组件中使用它们。一般来说,较小的标量输入应该使用从寄存器。如果您打算将大数组复制到组件中或从组件中复制出来,那么应该使用从属内存。
在这里插入图片描述

在这里插入图片描述

hls_avalon_slave_component

在这里插入图片描述

#include <HLS/hls.h>
#include <stdio.h>
hls_avalon_slave_component 
component int dut(int a,int b)
{
    return a*b;
}
int main()
{
    int a=2;
    int b=3;
    int y;
    y = dut(a,b);
    printf("y=%d",y);
    return 0;
}

在这里插入图片描述

hls_avalon_slave_register_argument

在这里插入图片描述

#include <HLS/hls.h>
#include <stdio.h>

hls_avalon_slave_component 
component int dut(
                int a,
                hls_avalon_slave_register_argument int b)
{
    return a*b;
}
int main()
{
    int a=2;
    int b=3;
    int y;
    y = dut(a,b);
    printf("y=%d",y);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

slave_memory_argument

在这里插入图片描述

#include <HLS/hls.h>
#include <HLS/stdio.h>

hls_avalon_slave_component 
component int dut(
    hls_avalon_slave_memory_argument(5*sizeof(int)) int *a,
    hls_avalon_slave_memory_argument(5*sizeof(int)) int *b
)
{
    int i;
    int sum=0;
    for(i=0;i<5;i++)
    {
        sum =  sum + a[i] * b[i];
        //printf("a[%d]%d",i,a[i]);
    }
    return sum;
}

int main()
{
    int a[5] = {1,2,3,4,5};
    int b[5] = {1,2,3,4,5};
    int sum;
    sum = dut(a,b);
    printf("sum=%d",sum);
    return 0;
}

在这里插入图片描述

stable_argument

在这里插入图片描述

#include <HLS/hls.h>
#include <stdio.h>

component int dut(
    hls_stable_argument int a,
    hls_stable_argument int b
)
{
    return a*b;
}
int main()
{
    int a=2;
    int b=3;
    int ret;
    ret = dut(a,b);
    return 0;
}

在这里插入图片描述

HLS编译器标准版组件调用接口参数总结

在这里插入图片描述

Intel HLS编译器标准版组件宏总结

FeatureDescription
hls_conduit_argumentImplement the argument as an input conduit that is synchronous to the component call (start and busy).将参数实现为与组件调用(start和busy)同步的输入管道。
hls_avalon_slave_register_argumentImplement the argument as a register that can be read from and written to over an Avalon-MM slave interface.将参数实现为一个可以通过Avalon-MM从接口读写的寄存器。
hls_avalon_slave_memory_argumentImplement the argument, in on-chip memory blocks, which can be read from or written to over a dedicated slave interface.在片上内存块中实现参数,它可以在专用的从接口上读取或写入。
hls_stable_argumentA stable argument is an argument that does not change while there is live data in the component (that is, between pipelined function invocations).稳定参数是当组件中有实时数据时(即在管道函数调用之间)不发生更改的参数。
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值