新建Vivado工程

设置clock,10表示一个周期10ns,带宽100M

vivado工具比较保守,计算需要的延迟是14,实际优化可以在10,设置大一点,优化的计算更多,一般约束设置大一点在30-50

选择开发板 xc7z020clg400-1

Source:描述功能模块的cpp和h代码

Test Bench:测试代码的main.cpp

C Code

matrix_mul.h

#ifndef __MATRIX_MUL__
#define __MATRIX_MUL__#include "ap_fixed.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4]);#endif
  • #ifndef __xxxx__ #define __xxxx__ #endif 用于放置重复引入头文件
  • ap_fixed.h :arbitrary precision data types 用于自定义精度整形(FPGA的浮点数运算很慢,在后面的模型推理的时候 整形数运算比较快)
  • 两个8位数相乘,结果最大可以是16位

.h文件包含了一个矩阵乘法的函数声明

matrix_mul.cpp

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}

i行k列乘k行j列

main.cpp

#include "matrix_mul.h"
#include <iostream>int main()
{ap_int<8> A[4][4], B[4][4];ap_int<16> C[4][4];// initial A&Bfor(int i = 0; i < 4; ++ i)for(int j = 0; j < 4; ++ j)A[i][j] = B[i][j] = i*4 + j;// inferencematrix_mul(A, B, C);// print C matrixfor(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){std::cout << "C["<<i<<"] = " << C[i][j] << "\t";}std::cout << std::endl;}return 0;
}

C Simulation

当有许多模块的时候需要指定顶层函数,设置顶层模块(top function):

C仿真主要用于编译C代码与HLS无关,测试功能是否与预期一致。使用C++完成testbench,同样地,C语言可以编译为对应的激励,驱动上一步骤完成的电路模块

_csim.log 文件显示仿真结果

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.Compiling ../../../main.cpp in debug modeCompiling ../../../matrix_mul.cpp in debug modeGenerating csim.exe
C[0] = 56  C[0] = 62  C[0] = 68  C[0] = 74
C[1] = 152 C[1] = 174 C[1] = 196 C[1] = 218
C[2] = 248 C[2] = 286 C[2] = 324 C[2] = 362
C[3] = 344 C[3] = 398 C[3] = 452 C[3] = 506
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************

C Synthesis

C++代码综合成RTL逻辑,生成综合报告,包括时序,延时,资源占用,端口信息等。

  • Loop Latency:完成所有循环需要的时钟周期

  • Iteration Latency:循环里面,迭代一次需要的周期

  • Initiation Interval(II):两次迭代之间的时钟间隔

  • Trip Count:循环次数


工程的资源占用情况(工程使用的资源数目&FPGA的总可用资源):


端口信息,ABC数组默认存在存储器ap_memory中,以下ap_clk、ap_rst、ap_start、ap_done、ap_idle、ap_ready都是控制信号

端口分析

  1. 控制端口用于控制和显示该模块的工作状态。各个端口的功功能如下,默认情况下会生成下面四个控制端口。

    • ap_start(in):为高时,该模块开始处理数据。
    • ap_done(out):为高时,表示模块处理数据完成。
    • ap_idle(out):表明模块是否处于空闲态。高电平有效。为高时,该处于空闲态。
    • ap_ready(out):为高时,表示模块可以接受新的数据。
  2. 数据端口用于传递模块的输入输出参数。
    参数d_o,d_i 为数组类型,故默认状态下回生成内存接口。内存接口 (数组类型参数)数据来自外部的memory,通过地址信号读取相应的数据,输入到该模块中。输入数组从外部内存中读源数据,输出数组从向外部内存写入结果数据。各个端口的定义如下。

    • address:地址信号
    • ce0:片选信号
    • we0:写使能信号
    • d0 :数据信号

并行优化

A和B的四个数同时相乘,让原先一行乘一列需要8个周期完成,变成一个周期完成

两种实现方法:

  • unroll,手动展开循环
  • pipline,系统自动推断展开
    • partiotion,切分数组
    • reshape,改变存储长度

unroll

source文件自动添加优化代码:#pragma HLS UNROLL

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){C[i][j] = 0;for(int k = 0; k < 4; ++ k){#pragma HLS UNROLLC[i][j] += A[i][k]*B[k][j];}}}
}

运行C综合的结果:((1+2)*4+2)*4+1 =57

pipeline

选择第二个for循环,设置pipeline的迭代间隔等于1

自动添加优化语句:#pragma HLS PIPELINE II=1

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}

C综合结果:

计算一共需要34个周期,这已经比以前的169个周期快了不少了,但是我们希望16个周期就能计算完。

没有达到预期的目标是因为没有指定数组A和B的端口类型,默认为双端口。读取数据时一次只能读取2个,所以16次计算,每次读取4个数据,一共16*4个数据需要花费16*4/2=32个周期

端口只有ce0和ce1:

所以需要同时取出四个数据,可以通过ArrayPartition和ArrayReshape实现

Array_Partition

数组分割:A竖着切割(按照维度2),分成4份分别存储在4个存储器里面;B横着切割(按照维度1)分别存储在4个存储器里面;

计算时同时各取出4个进行运算:

注意维度:高是维度1,宽是维度2

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{// partiton 优化语句#pragma HLS ARRAY_PARTITION variable=B complete dim=1#pragma HLS ARRAY_PARTITION variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}

C综合结果:

1*16+2 = 18

数组A和B都有四个端口同时读数据了:

Array_Reshape

重定义数组在存储器中的排列方式。原来默认一个地址行放一个数据,宽度只占8位。

A每次计算取一行,所以按照维度 2的方向放置数据:

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{#pragma HLS ARRAY_RESHAPE variable=B complete dim=1#pragma HLS ARRAY_RESHAPE variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}

C综合结果:

latency约束

这里Latency指的是每次迭代的花费的周期数

设置计算消耗的周期数设置为5

#include "matrix_mul.h"void matrix_mul(ap_int<8> A[4][4], ap_int<8> B[4][4], ap_int<16> C[4][4])
{#pragma HLS ARRAY_RESHAPE variable=B complete dim=1#pragma HLS ARRAY_RESHAPE variable=A complete dim=2for(int i = 0; i < 4; ++ i){for(int j = 0; j < 4; ++ j){#pragma HLS LATENCY min=5 max=5#pragma HLS PIPELINE II=1C[i][j] = 0;for(int k = 0; k < 4; ++ k){C[i][j] += A[i][k]*B[k][j];}}}
}

所以最后使用的周期数一共是:16×( Initiation Interval -1 ) + Latency = (16-1)×1+5 = 20

原来不加latency时,延时是1,所以是(16-1)*1+1=16

FPGA HLS Matrix_MUL 矩阵乘法的计算与优化相关推荐

  1. HLS:矩阵乘法单元设计与SDK测试

    目录 一.引言 二.程序框架 三.初步设计 四.报告分析 五.优化操作 六.接口优化 七.上板测试 八.补充部分 九.时间与参考 一.引言 矩阵乘法,涉及数组优化.循环优化和接口优化等.是一个学习HL ...

  2. 矩阵乘法的计算和来源

    矩阵乘法的计算 矩阵,是线性代数中的基本概念之一.一个m×n的矩阵就是m×n个数排成m行n列的一个数阵. 矩阵乘法是一种高效的算法可以把一些一维递推优化到log(n),还可以求路径方案等,所以更是一种 ...

  3. 矩阵乘法的计算规则,为什么是A矩阵的行元素分别乘以B矩阵的列元素?

    转:https://www.cnblogs.com/alantu2018/p/8528299.html Matrix 相关api: https://blog.csdn.net/gb702250823/ ...

  4. 矩阵乘法递推的优化艺术

    对于一个线性递推式,求它第项的值,通常的做法是先构造一个的矩阵,然后在时间内求出. 其实,由于这个矩阵的特殊性,可以将时间优化到.接下来我会以一个题目来讲解矩阵乘法递推的优化. 题目:http://w ...

  5. 基于FPGA的脉动阵列矩阵乘法

    部分信号的时序图: 模块代码: `timescale 1ns / 1ps /////////////////////////////////////////////////////////////// ...

  6. c语言定义int 输出4386,C语言 · 矩阵乘法

    问题描述 输入两个矩阵,分别是m*s,s*n大小.输出两个矩阵相乘的结果. 输入格式 第一行,空格隔开的三个正整数m,s,n(均不超过200). 接下来m行,每行s个空格隔开的整数,表示矩阵A(i,j ...

  7. python实现矩阵叉乘_矩阵乘法的纯Python实现 | 离开Python库!!

    点击关注我哦 一篇文章带你了解矩阵乘法的纯Python实现 在<这篇文章>中,我们有简单提到"矩阵乘法"的相关知识,如果你不记得了,可以复习一下这张图片. 想起来了没? ...

  8. 【C语言】矩阵乘法(二维数组)

    编写程序,实现矩阵乘法.计算两个矩阵A和B的乘积.输入要求:第一行三个正整数m.p和n,0<=m,n,p<=10,表示矩阵A是m行p列,矩阵B是p行n列:接下来的m行是矩阵A的内容,每行p ...

  9. 分治-Strassen矩阵乘法

    A和B的乘积矩阵C中的元素C[i,j]定义为: 若依此定义来计算A和B的乘积矩阵C,则每计算C的一个元素C[i][j],需要做n次乘法和n-1次加法.因此,算出矩阵C的个元素所需的计算时间为O(n3) ...

最新文章

  1. 2021春季每日一题【week6 未完结】
  2. 流控制、FlowControl
  3. javafx爬取网页并且初始化网页数据
  4. perl数组硬引用_Perl 继续前行,Perl 7 将是下一代(硬核老王点评版)
  5. linux 物理内存用完了_调整linux内核尽量用内存,而不用swap
  6. 【STL学习】堆相关算法详解与C++编程实现(Heap)
  7. pcb只开窗不镀锡_FPC、PCB和FFC的关系和区别-美好精密
  8. Sql UNION 合并多个结果集并排序
  9. 不知不觉 CDSN 也有了百万访问量了
  10. mysql查询所有男生中姓王的_数据库6.22
  11. Windows10安装ubuntu18.04双系统教程(双硬盘)
  12. 计算机命令无法到达打印机,单击打印命令时打印机无响是怎么回事
  13. ps修改图像像素压缩图片大小
  14. 利用FFmpeg合并音频和视频
  15. HDU 5745 La Vie en rose(水~)
  16. 笔记本电脑外接显示屏的分辨率设置,外接显示屏分辨率总是低一点的解决方法
  17. HDU 6411 带劲的and和
  18. request to https://registry.npm.taobao.org/jsprim failed, reason: connect ETIMEDOUT 错误解决方案
  19. OllyDbg断点详解
  20. MRI血管造影技术之最大密度投影法(maximum intensity projection)重建

热门文章

  1. 产品经理学习手册(一)产品经理:挖掘发现用户需求、满足用户需求;让世界变得更美好
  2. PDF与word互相转换
  3. Python3 使用企业微信 API 发送消息
  4. 三星a5000刷Android原生,Samsung-A5000安卓5.0刷机包
  5. PowerDesigner常见使用
  6. 鱼眼:一:一分钟详解鱼眼镜头标定基本原理及实现
  7. 免费开源的建站程序大全,不会编程也可以自助搭建网站了哦
  8. 小程序textarea在ios中内边距的解决办法
  9. BORLAND 在“迫害”程序员?
  10. c++找出1000以内的完数