` 折腾了一个多月,大学生的考试月总算是结束了,一个月来,小墨同学一共复习了6门专业课,整天就是看书看书,不过总算是结束了这学期的课程,剩下的时间才是真正属于我的时间~昨天还把6本专业书放在一起拍了个照,来纪念一下这一个多月的奋斗史... 好快,迎来了2015年,想想自己2014年的经历,还算是蛮丰富的,别的我们不说,我看了一下自己以前写的东西,好像是2014年的这个时候开始写的第一篇文章,一年了,自己的文章数量也有了20篇,访问量嘛~也还可以,毕竟拿了ednchina 的两个奖,还是挺高兴的。2014前半年可以说还没怎么开始学FPGA,前半年都去搞labview ,主要是大二下学期加上这个学期才开始的,算算也就大半年的时间了,半年的时间小墨同学还是收获蛮多的,虽然博客更新的慢了点...不过今天开始在未来的2个月里,不用复习的我会相继给大家更新这段时间小墨的学习经历以及学习过程,这几天更新的就快了,也希望大家多多关注哈~ 承蒙至芯科技的雷老师厚爱,小墨也暂时加入至芯科技,与那里的老师一起带领更多的想从事FPGA开发的人来进入这个领域,1月18号小墨同学也要奔赴北京,去做至芯科技十几天的实习生,对于我这个刚上大三的大学生来说,一切都是陌生,也不知道会发生什么,之前也没去过京城,只希望这次行程能够给小墨带来想要的收获吧~ 今天给大家带来的是我们在FPGA设计中经常要遇到的设计技巧与思想,即乒乓操作,串并转换,流水线操作和跨时钟域信号的同步问题。 之前也看过一些书,也在网上找过一些资料,不过小墨发现大部分都是理论讲解,仅仅是给一个框图就没事了,或者是好几个网站的资料都是一样的,都是复制的一个地方的,仅仅是讲解,没有实例,要不就是某个网站提供源码,但是要注册,还要花什么积分,没有积分还得要钱...很不利于初学者的学习(人与人之间怎么就不能多点信任呢~还要钱...)。所以小墨想写这么一篇文章来介绍一下这4种思想,理论部分书上多得是,我就不过多的解释,主要给大家讲一些实例型的帮大家理解。
一、乒乓操作 乒乓操作主要用于数据流的处理,是用面积换取速度的体现之一,要知道面积与速度的互换贯穿FPGA设计的始终,下面先给一个框图
我先来解释一下乒乓操作的过程:
首先数据需要通过一个2选一数据选择器,在第一个时钟周期将数据缓存到缓存模块1,常用的缓存模块可以是fifo,双口RAM(DPRAM),单口RAM(SPRAM),第二个时钟周期的时候,数据流开始往缓存模块2里面写数据,与此同时,预处理模块会从缓存模块1里面读取数据,到了第三个时钟周期数据流再往缓存模块1里面写数据,与此同时,预处理模块2开始从缓存模块2读取数据,周而复始...这样,输入数据流和输出数据流按节拍来回切换,可以使数据没有停顿的进行传输,使传输速率大大提高。
小墨同学发现,在给这个框图配实例的时候,几乎所有的网站都是这个解释,我用红字标出,个人感觉解释的不怎么样,还有些地方是错的
假设端口 A 的输入数据流的速率为 100Mbps ,乒乓操作的缓冲周期是 10ms 。以下分析各个节点端口的数据速率。
A 端口处输入数据流速率为 100Mbps ,在第 1 个缓冲周期 10ms 内,通过 “ 输入数据选择单元 ” ,从 B1 到达 DPRAM1 。 B1 的数据速率也是 100Mbps , DPRAM1 要在 10ms 内写入 1Mb 数据。同理,在第 2 个 10ms ,数据流被切换到 DPRAM2 ,端口 B2 的数据速率也是 100Mbps , DPRAM2 在第 2 个 10ms 被写入 1Mb 数据。在第 3 个 10ms ,数据流又切换到 DPRAM1 , DPRAM1 被写入 1Mb 数据。
仔细分析就会发现到第 3 个缓冲周期时,留给 DPRAM1 读取数据并送到 “ 数据预处理模块 1” 的时间一共是 20ms 。有的工程师困惑于 DPRAM1 的读数时间为什么是 20ms ,这个时间是这样得来的:首先,在在第 2 个缓冲周期向 DPRAM2 写数据的 10ms 内, DPRAM1 可以进行读操作;另外,在第 1 个缓冲周期的第 5ms 起 ( 绝对时间为 5ms 时刻 ) , DPRAM1 就可以一边向 500K 以后的地址写数据,一边从地址 0 读数,到达 10ms 时, DPRAM1 刚好写完了 1Mb 数据,并且读了 500K 数据,这个缓冲时间内 DPRAM1 读了 5ms ;在第 3 个缓冲周期的第 5ms 起 ( 绝对时间为 35ms 时刻 ) ,同理可以一边向 500K 以后的地址写数据一边从地址 0 读数,又读取了 5 个 ms ,所以截止 DPRAM1 第一个周期存入的数据被完全覆盖以前, DPRAM1 最多可以读取 20ms 时间,而所需读取的数据为 1Mb ,所以端口 C1 的数据速率为: 1Mb/20ms=50Mbps 。因此, “ 数据预处理模块 1” 的最低数据吞吐能力也仅仅要求为 50Mbps 。同理, “ 数据预处理模块 2” 的最低数据吞吐能力也仅仅要求为 50Mbps 。换言之,通过乒乓操作, “ 数据预处理模块 ” 的时序压力减轻了,所要求的数据处理速率仅仅为输入数据速率的 1/2 。 虽然各个网站上都是这么解释的,但是个人感觉解释的不怎么样,下面我用我自己的理解给大家解释一下这个例子 先看我给大家画的一个图,虽然画的不怎么样
这里我们只计算缓存模块1的速率 首先看第一个周期10ms,数据流往缓存模块1里面写数据,到第5ms时,预处理模块1开始从缓存模块1里面读数据,到10ms时,缓存模块1写了1M数据,读了5K数据,下面切换到第二个周期,由于在第二个周期的时候预处理模块1还可以从缓存模块1里面读数据,所以到第15ms时,缓存模块1里面的数据被读完
到了第三个时钟周期,也就是从第20ms开始数据流往缓存模块1写数据,到第25ms时,预处理模块开始从缓存模块读数据,直到35ms时才读完,这样我们来算一下,在第一个时钟周期读了5K数据,注意我上面画的时钟周期数,就是那个半圆形的,
在第三个时钟周期读了5k数据,注意每个时钟周期只有5K,另外5K到了下一个时钟周期了,所以我们不考虑,我们只考虑缓存模块1的速率。再看一下时间,从第10ms读完第一个5K,到第30ms读完第2个5k,共用了20ms,读了1M数据,所以速率为1M/20ms=50M/s。
下面再给大家讲一个实例,具体代码我会附在文章后面
用state来控制乒乓操作的来回切换
根据刚才讲的,控制缓存器的读写,这里只列些部分代码,具体代码请大家在文章后面下载
下面附上 仿真时序图,我在testbench中将数据设为从0 递增的,可以看到仿真波形中是将奇偶数分开的,证明我们代码是正确的
二、串并转换
串并转换总的来说就是将串行输入信号转换为并行输出,也是用面积换取速度的一种方法,串并转换总的来说比较简单,小墨就只给大家讲一下我自己写的代码吧
首先要先对串入信号进行采集,加入我们是8位一输出,每进来一位数据,我们便将原数据左移一位,保证数据是高位在前
然后再将数据并行输出即可,下面附上仿真波形,我在testbench中给串入信号设为随机数,看仿真图的,第一串信号为1101_1011,一位一位的移进寄存器可以由波形的,分别是1,3,6……所以我们的代码是正确的
三、流水线操作
流水线操作是高速设计中的一种常用手段,如果摸个设计的处理流程分为若干个步骤,而且数据处理是单向流的,也就是没有反馈或者迭代运算,前一个步骤是后一个步骤的输出,我们就可以采用流水线设计的方法来提高设计速率。
举个例子,假如我们要计算A+B+C的值,如果不用流水线操作的话,那么需要先计算A+B的值,再计算A+B+C的值,需要两个时钟周期,如果我用了流水线操作那么我需要在两个always块中分别计算sum1= A+B,sum2= sum1+C,由于两个always块是并行的,输出数据只需要等待一个时钟周期,以后就可以有数据源源不断的输出,就像流水线一样,从而提高系统速率
下面我们来设计一个实例,假如我要采集一系列的32位数据,要对它进行处理,处理方式假如是,先对这个数据进行加16运算,再进行压缩为16位数据运算,再进行减10运算
,最后进行取低8位运算,采用流水线设计的话,输出结果只需要等待几个时钟周期,以后就会有源源不断地数据输出,流程框图如下,代码请在后面下载
我在testbench中定义输入信号是随机的32位信号,分别进行分级处理,每处理完一级要给下一级发使能信号,并把数据送到下一级,例如当第一级使能信号到来时,数据为29,29加16为45,即第一级输出信号,对45取前16位仍为45,45减10为35,35取低8位仍为35,对照波形,证明我们的设计是对的
四、跨时钟域信号同步
先来看一张图
这个图的意思就是,脉冲信号为一个时钟信号,FPGA要对其进行计数,在CPU给FPGA发送读信号的时候,将计数器的值送至CPU的数据总线, 这里就涉及三个时钟信号,一个脉冲信号,一个CPU的读信号,一个FPGA的自身时钟,这三个时钟是不同步的,我们这样想,假如在脉冲计数的时钟,cnt是自加1的,由于三个时钟不同步,CPU的读信号随时都有可能来,加入当cnt自加的时候,也就是cnt = cnt +1,这是对cnt的写状态,突然来一个CPU的读信号,即那么就要把cnt送到数据总线,即data < = cnt,这是一个读状态,试问,一个数据既要读又要写,那读的是写之前的数据呢还是写之后的数据呢?这就是亚稳态,确切就是不确定的意思,所以,我们要将不同的时钟尽心同步处理,即在一个时钟的控制下进行脉冲计数和读操作,这样就不会发生亚稳态了,要知道,在一个大的系统中,亚稳态的危害是很大的
要解决同步问题,我们可以用FIFO,DPRAM 进行同步,即用其他时钟域对fifo进行写操作,再用FPGA对fifo进行读操作,但要注意是否有数据溢出,还有一种方法就是边沿脉冲检测法,这里我们讲第二种
即采用两级寄存器,这两级寄存器均有FPGA的时钟控制,具体操作就是将不同域的信号都先赋值给第一级寄存器,再在另一个always块中把第一级寄存器的值赋给第二级寄存器,如果是信号是高脉冲,那么就把第二级寄存器取反与第一级寄存器相与,便会得到一个高的脉冲采样信号,用这个信号在检测其他域信号的到来,如果是信号是低脉冲,那么就把第一级寄存器取反与第二级寄存器相与,同样得到一个高的脉冲采样信号,用这个信号在检测其他域信号的到来,小墨同学把它记为“上2下1”原则,方便记忆~
具体代码在前面键盘部分已经有所讲解,这里就不副代码了
写了好几个小时,手都敲酸了,还望各位大神多多指教,有什么讲的不对的地方还请指出,一起进步~
小墨QQ:584642877 微信:LYZ1023569 欢迎交流~
`
4
|
|
|
|
没想到小墨同学大学hai没有毕业就可以当老师了,讲解的真好,不过乒乓操作有张图看不了
|
|
|
|
|
乒乓操作那个,读取速度如果是50M/s的话,应该是从5s一直读到25s才读完吧,然后25s的时候正好开始读新写入的5K数据
|
|
|
|
|
xiexie louzhu , louzhu hao ren .
|
|
|
|
|
zhe shi hao tie bixu ding
|
|
|
|
|