原创 那些年,我们拿下了FPGA-第11章循环语句笔记(1)

2012-12-2 20:11 3301 12 12 分类: FPGA/CPLD 文集: 那些年,我们拿下了FPGA

 

第11章循环语句笔记

自打我们开始写程序,循环语句和条件语句就没有分离过,前面我们有了if、case语句,自然而然,循环语句该出现了。在Verilog中,跟C语言一样有着for循环、while循环,可是它还有着自己的循环语句,比如repeat、forever,它们共同组成了Verilog的循环语句大家庭,在这个大家庭中,它们扮演着自己的角色,讲述着自己的故事,我们一起来看看吧。

 

11.1只能仿真的循环

在Verilog中,总共有4种表示循环的方式,但并不是所有的循环都有机会在最终的电路中一展拳脚,比如下面我们要介绍的三种循环repeat、forever、while,它们就只能用于仿真,不能综合,也就是不能形成电路,但是即使是仿真,它们也发挥着不同的作用。

 

11.1.1 定数的repeat

用repeat表示的循环语句,其循环次数是固定的,不会受到外部条件的影响,始终坚持走自己的路,明文规定循环几次就循环几次,很是循规蹈矩,但是在使用时也需要明确指出循环的范围,有头有尾,一目了然,于是乎在这里再一次强调begin  end了。其表达形式如下所示:

repeat(循环次数表达式)

begin

end

这个“循环次数表达式”用于指定循环次数,可以是比较直白的整数,也可以用变量来表示,此时其数值只在第一次循环时得到计算以确定循环的次数,肯定有人会想到如果循环次数表达式中有我们前面提到的X或Z,repeat将会如何做出回应呢?且看下面的仿真程序和结果:

 

1.jpg

 

2.jpg

moduleTBLoopingRepeat;                 module TBLoopingRepeat;

 

regclk;                                 regclk;

reg [7:0] num;                           reg [7:0] num;

 

always #5 clk=~clk;                       always #5 clk=~clk;

 

initial begin                             initial begin

clk = 0;                                clk = 0;

num = 0;                               num =0;

 

repeat(8'bx)                            repeat(8’b0110111x)

begin                                 begin

         num = num+1;                         num = num+1;

end                                  end

end                                  end

其中,第一个图对应左边的代码,第二个图对应右边的代码,从图中我们可以一目了然,当循环次数表达式中含X时,将X视为“0”处理,如果遭遇Z呢?情况也是一样的,同样是“0”对待,大家可以自己来验证看看。

当我们确定循环次数后,repeat循环语句就要开始照章办事,其过程如下:首先计算循环次数并保存,然后执行块语句一次,之后循环次数减一,当结果为0时,循环结束,否则继续循环。下面是一个用移位加的方法来实现一个乘法器的例子。

initial begin

                  

                   data_a = 8'b10010101;

                   data_b = 8'b01100111;

                   shift_a = data_a;

                   shift_b = data_b;

                   result = 0;

 

                   repeat(Length)                          //循环开始,计数Length次

                   begin

                            if(shift_b[0])

                                     begin

                                               result = result+shift_a;

                                               shift_a = shift_a<<1;

                                               shift_b = shift_b>>1;

                                     end

                            else

                                     begin

                                               result = result;

                                               shift_a = shift_a<<1;

                                               shift_b = shift_b>>1;

                                     end

                   end

         end

 

结果如下图所示:

 

 

3.jpg

data_a和data_b所表示的十进制数分别是149和103,由repeat控制循环8次得到上图结果。但是,仍然需要强调的是repeat只能在仿真中使用,不能综合。

 

11.1.2 永远的forever

上面讲的repeat必须要确定循环的次数,否则无法正常工作,在verilog中还存在另一种循环,它与repeat有着截然相反的性子,那就是forever,也许有人会说现在的社会中还有什么事情是forever的,但是在这里,在Verilog里,除了软件停了,电脑死了,或者停电了,forever可以说实现了永恒,其中的语句将永远执行下去,其格式如下:

forever

begin

end

forever循环常用于产生周期性波形,如时钟,在仿真测试信号中常用forever语句产生时钟信号。见下

 

4.jpg

moduleTBLoopingForever;

 

reg clk0;

 

initial begin

         clk0 = 0;

forever

                   begin

                            #20 clk0=1;

                            #10 clk0=0;

                   end

end

上例中,用forever语句产生了一个占空比为1/3的时钟信号,它与用always来实现时钟的不同之处在于,它不能独立写在程序中,而必须写在initial块儿中。对于实现占空比可变的时钟信号forever语句还是比较方便的,但也仅仅限于仿真中,并且在同一过程块儿中forever之后的语句将永远不会执行,即forever是过程块儿中最后一条语句。例如,将上例稍作改动如下:

moduleTBLoopingForever;

 

reg clk0;

reg [7:0] num;

 

initial begin

         clk0 = 0;

num = 0;

forever

                   begin

                            #20 clk0=1;

                            #10 clk0=0;

                   End

 

repeat(8'b11100111)

                   begin

                            num = num+1;

                   end

end

结果如下:

 

5.jpg

可见,在同一过程块儿中,forever后的repeat语句块儿并没有执行,num输出结果还是初始化值0,那如何能让forever语句停止执行呢?会不会有像break这样的东东让forever不再那么执着呢?其实是有滴,可惜不是你(break),陪我(forever)到最后,还是来看看是谁俘获了咱forever的芳心吧,我们再将程序稍加改动,如下:

moduleTBLoopingForever;

 

reg clk0;

reg [7:0] num;

 

initial begin

         clk0 = 0;

num = 0;

 

begin: forever_test         //定义一个过程块儿,目的在于给该过程块儿命名

                   forever

                   begin

                            count_forever = count_forever+1;

                            #20 clk0=1;

                            #10 clk0=0;

                            if(count_forever>='d100)

                            begin

                                     disable forever_test;      //通过disable来终止过程块儿的执行

                            end                    

                   end

         end

 

repeat(8'b11100111)

                   begin

                            num = num+1;

                   end

end

结果如下:

 

6.jpg

由图中可知,num变量通过repeat语句最终输出8’b11100111,在forever语句块儿执行期间,其后的语句始终不执行,当计数满100后,通过disable语句将forever语句块儿终止执行,之后可以顺序执行forever之后的语句,即num变量开始计算。

所以说,如果需要在某个时刻跳出forever循环语句,可以通过在循环体语句块儿中用disable语句来实现。精诚所至,金石为开,只要你想,就没什么不能实现的。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /3 下一条