打印

初学Verilog,一段代码大家帮分析一下

[复制链接]
2451|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
代码中截取的一部分,主要是红色字体部分

reg [1:0]    SpiClk_flag;
reg [1:0]    Spi_State;

always @ ( posedge SysClk)
  begin
        if( SysRst )
        begin            
               SpiClk_flag   <= 'd0;
              Spi_State    <= idle;
        end
       else  begin
       case( Spi_State )
       idle :begin  
              SpiClk_flag   <= 'd0;
              Spi_State    <= idle;
              end
       send_cmd :begin                           //主要是以下的非阻塞赋值,有些晕
               SpiClk_flag <=SpiClk_flag+1; //每次进入send_cmd状态下,都先对SpiClk_flag寄存器加1
              if(SpiClk_flag == 'd1)             //是否执行完上条语句后,就满足SpiClk_flag == 'd1的条件

                 begin
                   SpiClk_flag <=0;               //能在一个系统时钟下,对SpiClk_flag执行加1,然后又写入0,同一时钟进行两次赋值?

                end
             else     //  下一个系统时钟后,SpiCli_flag=0时才会执行else下面语句,但每次进入send_cmd状态都是SpiClk_flag加1,面
            
  begin
                 SpiClk  <= 1'b1;
                。。。。//省略的代码
               end
       end
           //省略以下代码   

   估计还是非阻塞理解的不好,请各位帮忙指点,多谢!

相关帖子

沙发
GoldSunMonkey| | 2011-6-18 12:28 | 只看该作者
你的理解是对的。但是这个并没有错。你在一个进程中让a<=b,然后再让a<=c,那么这个进程结束后,
a<=c如果你还是迷糊,那么我就给你好好看下面我写的东西:)

使用特权

评论回复
板凳
GoldSunMonkey| | 2011-6-18 12:33 | 只看该作者
本帖最后由 GoldSunMonkey 于 2011-6-18 12:37 编辑

阻塞sigin和非阻塞out4语句作为verilogHDL语言时钟延迟HDL的最大time难点之一,一直out4困扰着FPGA设计里面设计者,即使是begin一个颇time富经验的out4设计工程师,也阻塞赋值很容易在这个设计里面点上犯语句运用下begin一些不必要的逻辑电路错误。阻塞和设计里面非阻塞可以设计里面说end是血脉相连,两个时钟但是又有着本质time的差别。begin理解不清或time运用不当verilog,都往往会out2导致设计工程out3达不到always预期的verilog效果,语言而其中逻辑建模的错误又很隐晦逻辑建模。begin下面我给大家end谈谈阻塞和逻辑建模非阻塞out2语句的本质区别语言和在FPGA设计sigin中的HDL不同运用。
阻塞语句
顾名思义,sigin即本条always语句具有begin影响下一条语句sigin的作用HDL,在HDL同一个进程always中,out4一条阻塞赋值out3语句的执行time是立刻影响语句运用out3着下条语句HDL的执行情况和赋值结果。如果begin该条语句阻塞语句没有执行out3完,那么sigin下条语句进程里面不可能进入执行状态out4的verilog,因此,设计里面从字面out3层上理解,时序逻辑该条进程里面语句阻塞了触发进程下面语句的执行。阻塞时序逻辑语句最能HDLreg体现verilogHDL和阻塞赋值C语言之间的b0血缘关系,时钟延迟比如,在时钟b0沿out2触发的语句运用always进程里,always若先执行b阻塞语句=c,两个时钟再执行进程里面a=out3b,那么本质上,HDL在阻塞赋值一个时钟沿触发out2里面,begina=cout2成立,即b0是说,begin不要b变量逻辑电路,直接语句运用在进程里赋值averilog=out4c,结果是out2一样out1的。这和c语言语句运用中b=endc触发进程,a=时钟延迟b性质相同。
非阻塞赋值阻塞语句
非verilog阻塞语句应该来说时序逻辑,更能体现阻塞赋值硬件电路时钟延迟的特点time。这正是非阻塞out4语句广泛进程里面应用于时序设计里面逻辑电路触发进程的原因语句运用。接上面的例子时序逻辑,always如果在一个时钟sigin沿触发的always赋值进程里面,赋值b<=逻辑建模c,时序逻辑a<=b那么就阻塞赋值不设计里面可能直接在进程end里面赋值a<时序逻辑=c.因为阻塞赋值c的sigin值要经过verilog两个时钟end延迟才out1传到a里面,即clkc若end从0变为1sigin,那么要out3经过逻辑电路两个clk上升end沿out1才传到a,进程里面a的值才赋值从0变为b0语言1。两次赋值正逻辑建模逻辑电路是体现了两个时钟两个时钟延迟逻辑建模的特点clk。这种特点即是非设计里面阻塞语句非阻塞赋值阻塞的HDL的原因导致的clk,就是说,begina<=b设计里面,不会out3因为b<out4=c没有执行进程里面完毕逻辑建模而不执行,end只要逻辑电路时钟触发进程reg,那么a<=bsigin,b<=触发进程c同时执行。设计里面所以,verilog如果c为sigin1end,b为always0,aout3为1的话逻辑建模,
那么在在非sigin阻塞语句的阻塞赋值进程里面,一个verilog时钟沿逻辑建模到来,语句运用由于他们之间是同时设计里面执行的逻辑电路,所以把cregalways的1赋b0给了bout3,把b的触发进程0赋给逻辑电路了a,时序逻辑但是在阻塞语言语句里面,c时序逻辑的1先给regclk了b,然后b0b把新赋值的sigin1out2又给了enda,那么aout1在一个时钟时钟延迟之后即变成end了1。时序逻辑(在逻辑建模一次触发进程sigin里,无论是verilog阻塞clk和非阻塞语句out1,每条语句b0只能执行逻辑建模一次)
  所以从上面的介绍里面,可以看出,阻塞语句是顺序执行的,而非阻塞语句是同时执行的,那么,如何在设计里面运用好阻塞语句和非阻塞语句呢,总体上来讲,遵循大体原则:。阻塞语句运用在组合逻辑电路设计里面,非阻塞语句运用在时序逻辑电路设计里面。但是一般来讲,一个设计往往包含着组合逻辑和时序逻辑。可以再细分为以下几个情况,并可以用阻塞语句和非阻塞语句不同的设计来区别讨论它们之间的优缺点,进一步理解清楚。。。。。。(最直观的说法就是如下仿真一下:。观察out1~out4的变化,就明白了!
`timescale1ns/100ps
moduletest1阻塞语句();
regclk;
regsigin;
regout1;
regout2;
regout3;
regout4;
//assign#10siginout3=sigin;
always#10时钟延迟clk=~clk;
always#70时序逻辑sigin=~sigin;
initial
begin
sigin=1'b0;
clk赋值=1'b0;
out1out1=1'b0;
out2=1'b0;
end
out1always@(sigin)
begin
$displayalways('%d',语句运用$time);
out1<=timesigin;
out2<=两个时钟out1;
out3阻塞语句=sigin;
out4=进程里面out3;
$display('%d'sigin,$timeclk);
end
endmodule

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
星星之火红 + 1
地板
GoldSunMonkey| | 2011-6-18 12:40 | 只看该作者
本帖最后由 GoldSunMonkey 于 2011-6-18 12:41 编辑

总结以上可以得到
#1:当赋值为时序触发进程逻辑建模always,使用“out2非阻塞语句运用赋值”。
#2:当为锁存器(latch)建模,使用“非阻塞赋值”。
#3:两个时钟当用always时序逻辑块为组合HDL逻辑建模逻辑电路,使用time“阻塞赋值”
#4:当在同一个always块里面既为组合逻辑又为时序逻辑建模,使用“非阻塞赋值”。
#5:不要out3在clk同一个always块里面混合b0使用时序逻辑“阻塞赋值”和out4clk“非阻塞时序逻辑赋值”
#6:不要在两个或两个以上always块里面对同一个变量进行赋值。
#7:使用$strobe以时序逻辑显示已被逻辑电路“非阻塞赋值赋值”的out2值。
#8:不要使用#0延迟的赋值。

使用特权

评论回复
5
GoldSunMonkey| | 2011-6-18 12:41 | 只看该作者
还有不明白的回帖问我~

使用特权

评论回复
6
星星之火红| | 2011-6-18 12:42 | 只看该作者
GSM大侠的**,就是透彻~

使用特权

评论回复
7
foreverly| | 2011-6-19 18:22 | 只看该作者
不错。长知识了。谢谢。

使用特权

评论回复
8
AutoESL| | 2011-6-19 19:50 | 只看该作者
学习了,讲的很透彻

使用特权

评论回复
9
AutoESL| | 2011-6-19 20:26 | 只看该作者
1# andy_mqy
    send_cmd :begin                           //主要是以下的非阻塞赋值,有些晕
               SpiClk_flag <=SpiClk_flag+1; //每次进入send_cmd状态下,都先对SpiClk_flag寄存器加1
              if(SpiClk_flag == 'd1)             //是否执行完上条语句后,就满足SpiClk_flag == 'd1的条件

                 begin
                   SpiClk_flag <=0;               //能在一个系统时钟下,对SpiClk_flag执行加1,然后又写入0,同一时钟进行两次赋值?

                end
             else     //  下一个系统时钟后,SpiCli_flag=0时才会执行else下面语句,但每次进入send_cmd状态都是SpiClk_flag加1,面
            
  begin
                 SpiClk  <= 1'b1;
                。。。。//省略的代码
               end

在这里,进入send_cmd状态后,flag寄存器加1并不能认为是立即有效,也就是说并不能保证满足flag==1的条件。
比如:flag初值是0,那么进入send_cmd状态后,flag==1的条件不满足,这时执行else语句。
这里不知道是不是楼主的笔误,clk <= 1?如果不是,那应该是flag<=1?如果这样,那么这里的flag <= flag + 1;这一语句没有实际作用。

使用特权

评论回复
10
jxgxlm2008| | 2011-7-18 09:33 | 只看该作者
恩,这个说的确实够详细了,还要靠自己去慢慢的体会才行

使用特权

评论回复
11
dan_xb| | 2011-7-18 10:52 | 只看该作者
这个代码有歧义,还是最好不要这么写吧
if(SpiClk_flag == 'd1)
    SpiClk_flag <=0;
else
  SpiClk_flag <=SpiClk_flag+1;

使用特权

评论回复
12
hjjnet| | 2011-7-18 11:34 | 只看该作者
呵呵,基本功啊,大家一起努力了

使用特权

评论回复
13
GoldSunMonkey| | 2011-7-18 12:57 | 只看该作者
:D基本功最考验人:)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

86

帖子

3

粉丝