彻底弄懂乒乓操作与并行化
乒乓操作可以看做成另一种形式的流水线技术。乒乓缓存结构如下图所示。
输入数据流通过输入数据选择单元时,时间等分地将数据流分配到两个数据缓冲模块。数据缓冲模块可以是RAM,FIFO等。通过将数据交替存放到数据缓冲模块1、数据缓冲模块2。并交替从数据缓冲模块1、数据缓冲模块2读取数据送入到数据流运算处理模块。工作过程如下:
第一段乒乓缓冲周期:将数据流缓存到数据缓冲模块1。
第二段乒乓缓冲周期:将数据流缓存到数据缓冲模块2,并从数据缓冲模块1读取数据送入数据流运算处理模块。
第三段乒乓缓冲周期:将数据流缓存到数据缓冲模块1,并从数据缓冲模块2读取数据送入数据流运算处理模块。
接下来就是上面描述的第二段、第三段乒乓缓冲周期的循环往复。
这样的结构应用于哪比较好呢?比如,对于LSTM(RNN)神经网络里面的上下timestep的输入数据以及输出数据就可以采用这种乒乓缓存。在WCDMA基带应用中,1帧由15个时隙组成,当需要将一帧数据延时一个时隙后处理时,也可以采用内存空间为一个时隙数据量的数据缓冲模块进行乒乓访存。
基于上面的乒乓缓存结构,可以得出一个乒乓操作结构如下图。这样的结构可以达到用低速模块处理高速数据流的效果,提高电路的吞吐率。
假设端口A的输入数据流的速率为 100Mbps,而一个数据预处理模块运算速度只有50Mbps,如果不采用乒乓操作结构,很明显数据预处理模块是处理不了数据端口A的数据流的。
当采用上图的乒乓操作方式之后。假设两个数据缓冲模块的内存大小都是1Mb,故每段乒乓缓冲周期为10ms。但是此时留给每个数据预处理模块的运算时间不再是10ms,而是20ms了,20ms内数据预处理模块是可以处理掉1Mb数据的。为什么留给数据预处理模块的时间有20ms呢?这20ms等于往自己写入数据的10ms加上往另外一个缓冲模块写入数据的10ms。因为这20ms内数据预处理模块都可以从自己本级的缓冲模块读取数据做运算。
这就做到了采用低速的数据预处理模块处理高速的数据流。上图是2级乒乓操作结构(因为数据流速率是预处理模块速率的2倍),如果数据流速率是预处理模块速率的n倍,就可以采用n级乒乓操作结构。这也是面积换速度的方法。
下面给出一个乒乓操作的特殊示例。假设原始电路如下图所示。组合逻辑加法器的运算时间需要3个时钟周期,而数据流a,b每个时钟都会有新的需要处理的数据。明显,这个电路处理不了。
那么我们可以采用如下电路来进行处理。这就是3级乒乓操作的特例,其中好比缓冲模块的内存大小为32bit(a,b均为16bit数据)。其中输入数据a,b按时钟周期依次送入三个不同的加法器;第三个时钟周期后,此时第一个加法器正好完成第一个时钟周期送进来的数据的运算,那么新来的数据又可以送入第一个加法器,以此循环往复。这样就做到了对数据的实时处理。
这里想分享下我设计的一段代码,首先是源代码。
module pingpang
(
input clk,
input rst_n,
input [7:0] data_in, // 输入数据
output reg [7:0] data_out // 输出数据
);
// ------------------------------------------------------ //
reg [7:0] buffer1; // 缓存1
reg [7:0] buffer2; // 缓存2
reg wr_flag; // 写标志,wr_flag=0,写buffer1,wr_flag=1,写buffer2
reg rd_flag; // 读标志,rd_flag=0,读buffer2,rd_flag=1,读buffer1
reg state; // 状态机,0:写1读2,1:写2读1,状态转移和输出分开编码
// ------------------------------------------------------ //
// 状态转移
always @ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
state <= 1'b0;
end
else
begin
case(state)
1'b0 : state <= 1'b1; // 写1读2->写2读1
1'b1 : state <= 1'b0; // 写2读1->写1读2
default : state <= 1'b0;
endcase
end
end
// ------------------------------------------------------ //
// 状态输出
always @ (state)
begin
case(state)
1'b0:
begin
wr_flag = 1'b0; // 写1
rd_flag = 1'b0; // 读2
end
1'b1:
begin
wr_flag = 1'b1; // 写2
rd_flag = 1'b1; // 读1
end
default:
begin
wr_flag = 1'b0;
rd_flag = 1'b0;
end
endcase
end
// ------------------------------------------------------ //
// 写buffer数据
always @ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
buffer1 <= 8'b0;
buffer2 <= 8'b0;
end
else
begin
case(wr_flag)
1'b0 : buffer1 <= data_in; // wr_flag = 0,写buffer1
1'b1 : buffer2 <= data_in; // wr_flag = 1,写buffer2
default:
begin
buffer1 <= 8'b0;
buffer2 <= 8'b0;
end
endcase
end
end
// ------------------------------------------------------ //
// 读buffer数据
always @ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
data_out <= 8'b0;
end
else
begin
case(rd_flag)
1'b0 : data_out <= buffer2; // rd_flag=0,读buffer2
1'b1 : data_out <= buffer1; // rd_flag=1,读buffer1
default : data_out <= 8'b0;
endcase
end
end
// ------------------------------------------------------ //
endmodule
其次是仿真测试代码:
module tb_pingpang();
// ------------------------------------------------------ //
// Inputs
reg clk;
reg rst_n;
reg [7:0] data_in;
// Outputs
wire [7:0] data_out;
// ------------------------------------------------------ //
pingpang pingpang_ins
(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in), // 输入数据
.data_out(data_out) // 输出数据
);
// ------------------------------------------------------ //
initial
begin
clk = 0;
rst_n = 0;
data_in = 0;
#100;
rst_n = 1;
end
// ------------------------------------------------------ //
always #10 clk = ~clk;
// ------------------------------------------------------ //
always @ (posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
data_in <= 8'b0;
end
else
begin
data_in <= data_in + 1'b1;
end
end
// ------------------------------------------------------ //
endmodule
最后是仿真波形:
从仿真波形中可以看出按照0、1、2、3递增的方式输入数据,两个缓存区交替存储数据,最后依次输出数据,不过输出数据会有两个时钟的延迟。
彻底弄懂乒乓操作与并行化相关推荐
- 《繁凡的深度学习笔记》前言、目录大纲 一文让你完全弄懂深度学习所有基础(DL笔记整理系列)
<繁凡的深度学习笔记>前言.目录大纲 (DL笔记整理系列) 一文弄懂深度学习所有基础 ! 3043331995@qq.com https://fanfansann.blog.csdn.ne ...
- 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述
<繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...
- 一文简单弄懂tensorflow_【TensorFlow】一文弄懂CNN中的padding参数
在深度学习的图像识别领域中,我们经常使用卷积神经网络CNN来对图像进行特征提取,当我们使用TensorFlow搭建自己的CNN时,一般会使用TensorFlow中的卷积函数和池化函数来对图像进行卷积和 ...
- 硬核艿艿,新鲜出炉,直接带你弄懂 Spring Boot Jar 启动原理!
" 摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/jar/ 「芋道源码」欢迎转载,保留摘要,谢谢! 1. 概述 2. MANIFEST.MF 3. J ...
- 程序员,想要彻底弄懂Redis,这15点你一定要明白~(纯干货)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多 作者:耿直的小码农 来源:https://s ...
- php 函数有命名空间吗_一篇弄懂PHP命名空间及use的使用
最近一段时间在研究php框架,一直想的什么时候才能开发出自己的框架,当然这是为了提升自己的编程水平,同时能把平时学的零散的东西糅合在一块熟练应用.但是开发一个框架根本不知道如何做起,先开发什么,虽然p ...
- 一文弄懂String的所有小秘密
文章目录 简介 String是不可变的 传值还是传引用 substring() 导致的内存泄露 总结 一文弄懂String的所有小秘密 简介 String是java中非常常用的一个对象类型.可以说ja ...
- 一文弄懂EnumMap和EnumSet
文章目录 简介 EnumMap 什么时候使用EnumMap EnumSet 总结 一文弄懂EnumMap和EnumSet 简介 一般来说我们会选择使用HashMap来存储key-value格式的数据, ...
- Cookie 从入门到进阶:一文彻底弄懂其原理以及应用
大家好,我是若川.持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...
- hwt字体转换ttf_五分钟教你弄懂了字体反爬是个啥
今天的文章内容主要是关于字体反爬. 目前已知的几个字体反爬的网站是猫眼,汽车之家,天眼查,起点中文网等等. 以前也看过这方面的文章,今天跟个老哥在交流的时候,终于实操了一把,弄懂了字体反爬是个啥玩意. ...
最新文章
- matlab怎么求残余误差,误差理论与数据处理实验报告.doc
- HTML5 叠加布局
- 高达82 fps的实时文本检测,可微分二值化模块
- asp用于取代什么技术_ASP是不是已经被淘汰了?
- c++学习笔记之静态成员函数
- C/C++ 指针小结——指针的概念和如何使用指针
- 792. 高精度减法
- nina数据库的采样频率_基于深度学习模型的表面肌电信号手势动作识别算法研究...
- html app5 仿微信朋友圈,uniapp仿微信聊天App界面|仿微信朋友圈|uniapp仿微信
- 搞清楚模数、数模转换中的AGND和DGND
- c语言二级安卓软件,C语言二级考试题库安卓下载-C语言二级考试题库APK下载 - Iefans...
- python dlib caffe人脸相似度_人脸检测学习笔记(数据集-DLIB人脸检测原理-DLIBOpenCV人脸检测方法及对比)...
- lwj_C#_homework 攻城车 攻击 WASD移动
- Merged region B8 must contain 2 or more cells
- MYSQL 的配置文件
- 64个数据分析常用术语
- 微信小程序 环形进度条_微信小程序实现圆形进度条实例分享
- 软件工程中五种常用的软件开发模型整理
- vue实现修改用户信息的全过程
- css 高度塌陷_css中父元素高度塌陷是什么意思,如何解决?(附代码)