想想从今后开始就在这里把自己的所学到的归纳一下吧。
这里只是本人自己的设计过程中的所得,对于一些高手来讲只是小儿科
所以,你认为很幼稚的,请就此忽略。假若你认为看了后学到了些东西,那就回帖顶顶给个支持吧。
这里声明一下,虽然是幼稚的文字,但也是一个个字碼出来的,所以也算是个版权吧。
万一谁想转载或引用,麻烦请先告知一声,谢谢!
个人习惯,今后所有默认触发以下降沿为准 -- negedge
鲁棒(Robutness)
“鲁棒”这个词,就是让设计更安全,但这个翻译我一直认为翻译的挺恶心。所以,今后就用“更R”来代替吧。
怎么样让设计更R呢?
举个例子。在设计中会用到许多计数器,是计数器就要reset吧。
那你会怎么样让它reset呢?(reset也是你自己产生的,非外部进入)
大家看看下面这个reset有没有问题呢:
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """""""""|___|""""""""""""""""""""""""""""""""""""
cnt: ========x0__x1__x2__x3.............................
我开始设计的时候就是这么做的,而且很长时间都是这么做的,没出过问题。
下降沿来1个clk的reset,设0,下一个下降沿开始计数,这不就行了么,一点问题也没有。
的确,很久都没有出过问题,但有一次,发现有个计数器总是少计一个数,苦恼许久。
这帖暂时先写到这,各位也可以一起想想会出现什么问题吧。
高手知道的请不要那么快回答,让和我们一样曾经是初学者的朋友先想想。

[ 本帖最后由 leolf 于 2008-7-21 15:18 编辑 ]



最新回复
wanynal (2008-7-20 16:23:15)
是来这里学习的
希望以后能够得到楼主的帮助
像您这样能够把自己的经验无私的传授给我们这些新手
我衷心地感谢您
希望您以后能够坚持多发这种帖子
新手 还没有进行过什么实质性的编程工作
因此我只能是猜一猜了
个人感觉应该是延时的问题
估计是由于延时的原因
使reset的为0的时间与cnt要进行计数的时间有冲突
因此造成了少计一个数
leolf (2008-7-20 17:59:00)
因为同是用下降沿触发,所以reset信号也同样用下降沿来结束的话,就会有可能因为内部延迟和下一个计数产生冲突。
所以,计数结果很可能少一个。例如:
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """"""""""|___|""""""""""""""""""""""""""""""""""""
cnt: ========x0__x0__x1__x2.............................
就是这样,设计越多,你就会越来越感觉芯片内部的信号的延迟是那么的可怕。
如果你追求"更R“的设计,那首先你要打破芯片内部的信号是理想的方波这一个幻想!!
2. 解决
好的,问题找到了,那我们怎么才能处理好这个reset呢?
当然,最简单的,产生reset的时候,用上一个上升沿,例如底下的波形:
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """"""|___|""""""""""""""""""""""""""""""""""""
cnt: ========x0__x1__x2__x3.............................
当然,对于上一个问题,这应该可以满足了。
但是,我们再想想计数器之后的器件。因为判断计数器数值的比较器也是用下降沿的,那这样的设计就会产生一个问题。
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """"""""""""|___|""""""""""""""""""""""""""""""""""""
cnt: ........x8__x9_x0000_x1__x2__x3.............................
?eq9: .....x7__x8___x0__x0__x1................................... (where is the 9?)
因为我们的判断器也是用下降沿来触发的(目标数是9然后reset)。所以,当计数器来到9的时候,比较器还没来得及将9这个数拿走,
就已经被复位了。哎呀呀,这不就出错了么。对了!!将比较器的触发沿也改成下降沿不就行了么!!
各位,真的可以将比较器的触发沿也改成下降沿来解决这个问题么??我们有没有更好的方法来解决呢?
先去吃饭呀。
[ 本帖最后由 leolf 于 2008-7-20 18:09 编辑 ]
jiangwei (2008-7-20 21:03:20)
kevin249 (2008-7-20 21:41:32)
然后再用同步采
leolf (2008-7-20 23:35:42)
这延迟一个clk,多麻烦呀。计数器结果一出来我就直接比较不就好了么?比如像下面这样
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """"""""""""|___|""""""""""""""""""""""""""""""""""""
cnt: .......x8__x9_x0000_x1__x2__x3.............................
?eq9: ....?9__=9__?9__?9__?9...................................
结果一出来就能比较到了,方便又快速。用register先锁存一下是否多此一举呢?
答案是否定的!因为计数器是由多个级联的器件产生,“多个器件”这个词语会不会给了你一些提示呢?
是的,因为最终结果是由多个器件的值产生的。所以,这几个器件都有它本身的反应时间,而且反应时间肯定是
不一样的,这就造成了在最后有稳定的结果之前,计数器会产生意想不到的数。
假设有一个4位的简单计数器,我们把时钟下降沿计数器跳变的那一刻的延迟放大来看看:
clk: """"""""""""""""""""|________|""""""""""""""|_________________
cnt1: ____________|""""""""""""""""""""""""""""|___________________
cnt2:"""""""""""""""""""""""""""""""""""""""""""""""""""|__________________
cnt3:"""""""""""""""""""""""""""""""""""""""""""""""""""""|__________________
cnt4:"""""""""""""""""""""""""""""""""""""""""""""""""""""""|__________________
cntresult: 14_14_!4_14_15_15_15_15_15141280000000000000
这只是一个4位计数器。但在最后的跳变中,在到达稳定的0之前,它会产生14,12,8,这几个数字。
这个,和一般的计算机语言编程不一样吧。
套用周星驰一句感慨“有没有搞……错!”变0就变0嘛,竟然会自己跑那么多数出来!!
所以,直接使用计数器跳变边沿的结果来比较是十分危险的!!因为这会产生很多的"glitch"!“glitch"就是中文中著名的“毛刺”!
在电路设计中,“毛刺”可以定义为:贬义的,不受欢迎的,不请自来的,看到要绕着走的,总之就是一个不好的东西。
所以,我们要在它稳定之后再使用这个结果。这也就是为什么我们要先锁存一下,以确定我们取的是稳定值。
上面有朋友说先比较后锁存,其实也是一样的。没有太大分别。
[ 本帖最后由 leolf 于 2008-7-20 23:50 编辑 ]
leolf (2008-7-21 00:53:18)
在这里,怎么样能产生一个安全的reset呢?其实之前所说的上升沿reset是可以拿来参考的。
但是,使用和整个系统不同的触发边沿是会造成混乱的。所以,假如我们能把这个混乱控制在一个小范围之内。
就可以既安全,又不影响其它人。
所以,我们可以产生一个半周期的reset,那样就能满足我们的应用。波形如下:
clk: __|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|__|""|
reset: """""""""""""""|__|""""""""""""""""""""""""""""""""""""
cnt: ........x8__x9__x0___x1__x2__x3.............................
?eq9: .....x7__x8__=9___x0__x1................................... (9 is safety!)
怎么样,看了这个波形,是不是觉得很容易呀。一切事物在我们知道之后都会觉得很容易。
比如说牛顿的三大定律,可是在牛顿之前的数千年里,为什么没人总结出来呢?人类的思维发展真是有些奇怪……
下面简单写下verilog语句。
假设triger是一个下降沿产生的1个clk负pulse
always @(negedge clk)
rstb1 <= triger;
always @(posedge clk)
rstb2 <= rstb1;
wire reset = rstb1 | ~rstb2;
clk: __|""|__|""|__|""|__|""|__|""|__|""|
triger: """""""""|____|"""""""""""""""""
rstb1: """""""""|____|""""""""""""""""
~rstb2: ________|""""""|________
reset: """"""""""|__|""""""""""""""""""""""
这样子,一个相对来说安全的reset就诞生了。
虽然硬件上来说会多一个register。
但一个regsiter就能够让你周末放心睡大觉。不用担心被叫回公司debug!
那是多么值得呀!!
好了,今天算是圆满了,睡觉喽!!
[ 本帖最后由 leolf 于 2008-7-21 00:58 编辑 ]
wanynal (2008-7-21 08:58:26)
ishock (2008-7-21 09:30:52)
在FPGA领域,最好还是用上升沿做设计,因为器件内部的寄存器本来就是上升沿触发的。用下降沿做设计,外部时钟进去后要先经过一个反相器才驱动内部寄存器。
leolf (2008-7-21 11:26:48)
QUOTE:
这个例子的确很有局限性,但并不是只给计数器复位的。因为一些类似的设计也会遇到这种问题。
总得来说,我写这些只是为了提醒大家,在一些细节方面要多加注意。大家可以举一反三。
tenggui (2008-7-21 11:30:08)
多谢
x512775199 (2008-7-21 12:15:13)
caiyuxiang (2008-7-21 14:40:28)
zou132 (2008-7-21 15:35:59)
时钟走全局网络所造成的时延可以忽略不计,
starguoxia (2008-7-21 15:48:45)
QUOTE:
还是有可能出现楼主说的情况的吧?时延不一定是时钟引起的吧,门电路自己本事也有时延的。不知道说的对不对
yel27 (2008-7-21 16:29:23)
新手
wu.weihai (2008-7-21 16:44:29)
店小二 (2008-7-21 16:47:23)
hover_edacn (2008-7-21 17:11:34)
很多公司对异步复位的使用都有严格限制,而这种由内部逻辑产生的异步复位危害更大。
qingchuyu (2008-7-21 17:24:54)
if these timing is meeting
there will not be race condition like that.
leolf (2008-7-21 17:45:06)
QUOTE:
The enviroment that our product apply to may meet some extreme enviroment such as unexpect voltage drop or bad process.And in IC design, the asynchronous "rst" also need EDA to help to place and route.
In large scale design, the EDA is not 100% creditable.
That's why we need to think a little more.