目录
1.概述
在Verilog中,输入数据的范围判断通常是通过模块的输入端口定义中的数据类型和位宽来实现的。以下是详细的解释和整理:
-
数据类型: Verilog中的常见数据类型有
wire
、reg
、integer
、real
等。在输入端口中,通常会使用wire
或reg
来表示输入信号的数据类型。wire
: 用于表示连续赋值的信号,通常用于组合逻辑。其范围判断较为灵活,可以通过逻辑表达式对信号值进行判断。reg
: 用于表示时序逻辑中的寄存器。其范围判断也可以通过逻辑表达式来实现。
-
位宽(Width): 输入数据的位宽指的是信号所占的比特数。位宽决定了信号可以表示的数值范围。
例如,一个4位宽的二进制信号可以表示0到15之间的整数。
-
数值范围判断方法: 数据范围的判断通常涉及到比较运算符和逻辑运算符。
- 比较运算符:常用的比较运算符有
<
、>
、<=
、>=
、==
、!=
等,用于比较信号的值与给定的阈值。 - 逻辑运算符:逻辑运算符如
&&
(与)、||
(或)、!
(非)等可以在判断中使用,用于构建复杂的条件。
- 比较运算符:常用的比较运算符有
在系统设计的过程中,经常需要根据输入数据的值,对相关信号的值进行改变。如果输入数据的边界值数量比较少,可以用条件操作符、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的比较器,也消耗了很多的系统资源。
2.二分法
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个多路选择器,增加了多路选择器的数量,最终的资源占用和实际的数据边界有很大关系。
3.优化哈夫曼树
通过对代码的分析,可以得知和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级,提升了系统的运行速度。