Verilog中输入数据范围的判断

0.完整源码获得方式

订阅MATLAB/FPGA教程,免得获得教程案例以及任意2份完整源码

----------------------------------------------------------------------------------------------------

在系统设计的过程中,经常需要根据输入数据的值,对相关信号的值进行改变。如果输入数据的边界值数量比较少,可以用条件操作符、if...else、case等结构实现。但是如果数据边界值的数量很多,使用条件操作符和if...else会导致最差情况下的延时增加,使用case会导致代码量巨大。在这种情况下,使用不同的Verilog代码可以对系统的资源和速度产生很大影响。
比如在某MP3解码系统中,存在如下代码:

always@(Sample_reg_Temp0)
begin
 if(Sample_reg_Temp0==0||Sample_reg_Temp0==1)
   Is_Exp_Temp=5'b0;
 else if(Sample_reg_Temp0==2)
   Is_Exp_Temp=5'b00010;
 else if(Sample_reg_Temp0==3||Sample_reg_Temp0==4)
   Is_Exp_Temp=5'b00011;
 else if((Sample_reg_Temp0>4)&&(Sample_reg_Temp0<9))
   Is_Exp_Temp=5'b00100;
 else if((Sample_reg_Temp0>8)&&(Sample_reg_Temp0<14))
   Is_Exp_Temp=5'b00101;  
 //中间部分省略
 else if((Sample_reg_Temp0>2435)&&(Sample_reg_Temp0<4097))
   Is_Exp_Temp=5'b10000;//save 2^15
 else if((Sample_reg_Temp0>4096)&&(Sample_reg_Temp0<6889))
   Is_Exp_Temp=5'b10001;//save 2^14
 else          
   Is_Exp_Temp=5'b10010;//save 2^13
end

由于if...else结构是按照顺序的方法对每个条件进行一次判断,所以如果采用以上代码,在最差情况下Is_Exp_Temp的数据需要经过17级(中间部分省略)多路选择器的延时才能有效,这样会严重拖慢整个系统的速度。而且按照上述代码的写法,Is_Exp_Temp用到了33个16bit的比较器,也消耗了很多的系统资源。

方法一:二分法
Sample_reg_Temp0是16bit的,所以我们可以通过16级多路选择器,确定Sample_reg_Temp0的值的范围,根据其范围对Is_Exp_Temp进行赋值。这样最终会产生2^16=65536种可能性,代码量巨大。但是由于实际中Sample_reg_Temp0只有17个固定的边界,当Sample_reg_Temp0的值确定在一定范围内时就可以将该范围内的数据进行合并。
举例来说,当Sample_reg_Temp0 >= 6889时Is_Exp_Temp = 5'b10010,而Sample_reg_Temp0[15]==1'b1时,Sample_reg_Temp0的范围是[32768,65535],所以Sample_reg_Temp0[15]==1'b1时Is_Exp_Temp = 5'b10010,无需再对Sample_reg_Temp0[14:0]的值进行判断,可以大大减少代码的编写量。
采用这种方法,数据输出需要经过16级多路选择器的延时,在速度上改进不大,但是这种方法不需要用到比较器,对每一位的判断都需要一个多路选择器,而且每一级对下级一数据进行判断时需要用到2个多路选择器,增加了多路选择器的数量,最终的资源占用和实际的数据边界有很大关系。

方法二:优化哈夫曼树
通过对代码的分析,可以得知和Is_Exp_Temp有关的Sample_reg_Temp0边界值x有以下几个:
0
1
2
3
5
9
14
23
39
65
108
182
305
513
862
1449
2436
4097
6889
65536
当x[i] =< Sample_reg_Temp0 < x[i+1] (0<i<17)时,Is_Exp_Temp有一个固定的值。所以以边界值的序号做二分,建立一个哈夫曼树。然后使用if...else对每一个节点的值进行判断,最终确定Sample_reg_Temp0的范围,完成对Is_Exp_Temp的赋值。最终代码如下所示:
//为了减少占用的版面,去除了所有的begin...end关键字,只使用缩进来表示层次关系。
    always @(Sample_reg_Temp0)
        if(Sample_reg_Temp0 < 182)
            if(Sample_reg_Temp0 < 23)    
                if(Sample_reg_Temp0 < 9)
                    case(Sample_reg_Temp0)    //synopsys parallel_case
                        0, 1 : Is_Exp_Temp <= 5'b0;
                        2 : Is_Exp_Temp <= 5'b00010;
                        3, 4 : Is_Exp_Temp <= 5'b00011;
                        5, 6, 7, 8 : Is_Exp_Temp <= 5'b00100;
                        default : Is_Exp_Temp <= 5'b11111;
                    endcase
                else
                    if(Sample_reg_Temp0 < 14)    //9-13
                        Is_Exp_Temp <= 5'b00101;
                    else    //14-22
                        Is_Exp_Temp <= 5'b00110; 
            else
                if(Sample_reg_Temp0 < 65)
                    if(Sample_reg_Temp0 < 39)    //23-38
                        Is_Exp_Temp <= 5'b00111; 
                    else    //39-64
                        Is_Exp_Temp <= 5'b01000;
                else
                    if(Sample_reg_Temp0 < 108)    //65-108
                        Is_Exp_Temp <= 5'b01001;
                    else    //108-181
                        Is_Exp_Temp <= 5'b01010;
        else
            if(Sample_reg_Temp0 < 1449)
                if(Sample_reg_Temp0 < 513)
                    if(Sample_reg_Temp0 < 305)    //182-304
                        Is_Exp_Temp <= 5'b01011;
                    else    //305-512
                        Is_Exp_Temp <= 5'b01100;
                else
                    if(Sample_reg_Temp0 < 862)    //513-861
                        Is_Exp_Temp <= 5'b01101;
                    else    //862-1448
                        Is_Exp_Temp <= 5'b01110;
            else
                if(Sample_reg_Temp0 < 4097)
                    if(Sample_reg_Temp0 < 2436)    //1449-2435
                        Is_Exp_Temp <= 5'b01111;
                    else    //2436-4096
                        Is_Exp_Temp <= 5'b10000;
                else
                    if(Sample_reg_Temp0 < 6889)    //4097-6889
                        Is_Exp_Temp <= 5'b10001;
                    else    //6889+
                        Is_Exp_Temp <= 5'b10010;
在对小于9的值进行判断时,为了减少使用的if...else级数,使用了并行case对有限的几个值进行进行多路选择,这样就可以把if...else的层数控制在4层。
采用以上方法,使用14个16bit比较器、14个双路选择器、一个9选择的多路选择器,就实现了Is_Exp_Temp的改变,相对于最初的33个比较器,17个双路选择器,大大减少了所用的资源,同时将Is_Exp_Temp的有效延时从17级多路选择器减少到4级,提升了系统的运行速度。

猜你喜欢

转载自blog.csdn.net/ccsss22/article/details/97996784