Verilog中输入数据范围的判断方法整理

本文介绍在Verilog中优化输入数据范围判断的三种方法:原始if...else结构、二分法和优化哈夫曼树。通过实例展示如何减少资源消耗和提升系统运行速度。

目录

1.概述

2.二分法

3.优化哈夫曼树


1.概述

        在Verilog中,输入数据的范围判断通常是通过模块的输入端口定义中的数据类型和位宽来实现的。以下是详细的解释和整理:

  1. 数据类型: Verilog中的常见数据类型有wireregintegerreal等。在输入端口中,通常会使用wirereg来表示输入信号的数据类型。

    • wire: 用于表示连续赋值的信号,通常用于组合逻辑。其范围判断较为灵活,可以通过逻辑表达式对信号值进行判断。
    • reg: 用于表示时序逻辑中的寄存器。其范围判断也可以通过逻辑表达式来实现。
  2. 位宽(Width): 输入数据的位宽指的是信号所占的比特数。位宽决定了信号可以表示的数值范围。

    例如,一个4位宽的二进制信号可以表示0到15之间的整数。

  3. 数值范围判断方法: 数据范围的判断通常涉及到比较运算符和逻辑运算符。

    • 比较运算符:常用的比较运算符有<><=>===!=等,用于比较信号的值与给定的阈值。
    • 逻辑运算符:逻辑运算符如&&(与)、||(或)、!(非)等可以在判断中使用,用于构建复杂的条件。

      在系统设计的过程中,经常需要根据输入数据的值,对相关信号的值进行改变。如果输入数据的边界值数量比较少,可以用条件操作符、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级,提升了系统的运行速度。

<think>好的,我需要帮助用户在FPGA仿真过程中正确添加信号数据。首先,我需要整理用户提供的引用内容,看看里面有哪些相关的信息可以引用。根据用户给的引用,有几个方法,比如使用Verilog系统函数、专用仿真软件如ModelSim,以及编写测试平台(Testbench)来生成信号数据。 首先,引用[1]提到两种方法:使用Verilog系统函数(速度较慢)和专用仿真软件(速度较快)。引用[3]详细介绍了ModelSim,作为业界优秀的仿真工具,支持VHDL和Verilog混合仿真,可能涉及如何在其中添加信号。引用[4]中的测试平台例子展示了如何通过穷举法测试,可能涉及如何生成输入信号并观察输出。 用户的问题是如何在仿真中添加信号数据,可能需要分步骤说明,包括测试平台编写、波形添加、使用仿真工具等。需要确保回答结构清晰,步骤详细,并引用相关的内容作为支持。 接下来,我需要组织回答的结构。可能分为几个步骤: 1. 编写测试平台(Testbench):引用[4]的例子,说明如何生成输入信号,比如使用initial块和循环来改变输入值,并添加延时。这部分需要详细说明代码的结构和各个部分的作用。 2. 使用仿真工具添加信号:引用[3]中的ModelSim教程,说明如何在仿真软件中添加信号到波形窗口。可能包括启动仿真、在波形窗口中手动添加信号,或者通过脚本自动添加。 3. 自动数据生成方法:引用[1]提到的Verilog系统函数,比如$readmemh,或者使用随机数生成。这部分需要给出代码示例,说明如何从文件读取数据或生成随机输入。 4. 验证信号正确性:引用[2]中的例子,如何将仿真波形转换为模拟形式,并与预期结果(如MATLAB仿真)对比。可能需要检查特定频率点或数据范围是否正确。 此外,需要确保使用正确的中文术语,并且行内公式用$...$,独立公式用$$...$$,如果有数学表达式的话。比如,在解释信号频率验证时,可能需要用到频率公式,如$f = \frac{N \cdot f_s}{FFT\_LENGTH}$,但根据用户的问题,可能这部分数学内容不多,但需留意。 还要注意引用标记的正确位置,例如在提到ModelSim时添加[^3],在提到测试平台时引用[^4],提到波形数据提取方法时引用[^1]和[^2]。 最后,生成相关问题,可能需要包括测试平台编写、仿真工具使用、自动化信号生成方法、验证方法等方向的问题。 现在需要检查是否有遗漏的步骤或引用内容,确保所有方法都被涵盖,并且引用正确。例如,测试平台部分正确引用了引用[4],波形添加引用了引用[3],数据生成引用了引用[1]和[4],验证部分引用了引用[2]。 确保回答中的代码块使用正确的格式,如示例中的Python代码用三个反引号包裹,并注明语言。但用户的问题中涉及的是Verilog和Testbench,所以需要用相应的语言标记。 现在开始撰写回答部分,分步骤说明,每个步骤结合引用内容,并自然添加引用标记。然后生成相关问题。</think>[用户可见层] ### FPGA仿真中添加信号数据的完整方法 #### 一、通过测试平台(Testbench)生成信号数据 1. **编写基础测试平台** 在Verilog测试平台中,使用`initial`块和循环生成信号序列。例如,引用中的测试代码通过穷举法生成6位输入信号: ```verilog initial begin data_6bits = 0; while (~(&data_6bits)) begin // 当输入未达到最大值时循环 data_6bits = data_6bits + 1; // 从0开始累加 #5; // 延时5个时间单位 end #20 $stop(); end ``` 此方法适用于小范围输入验证,直接控制信号变化。 2. **使用系统函数加载外部数据** 若需复杂波形(如正弦波),可通过`$readmemh`或`$readmemb`从文件加载数据: ```verilog reg [7:0] signal_data [0:999]; initial begin $readmemh("signal_input.txt", signal_data); // 从文本文件读取十六进制数据 for (int i=0; i<1000; i++) begin data_in = signal_data[i]; #10; // 每个数据持续10ns end end ``` 此方法适合批量数据注入,但速度较慢。 --- #### 二、在仿真工具中添加信号到波形窗口 1. **ModelSim手动添加信号** - 启动仿真后,在“Objects”窗口选中目标信号,右键选择**Add to Wave**。 - 支持信号分组、设置显示格式(二进制/十六进制等),如图1所示[^3]。 ![ModelSim波形添加示意图](https://via.placeholder.com/300x200?text=ModelSim+Waveform+Example) 2. **通过TCL脚本自动添加** 在ModelSim中执行TCL命令批量添加信号: ```tcl add wave -group "Top" /test_tb/data_6bits # 添加信号并分组 add wave -group "Output" /test_tb/data_4bits run -all # 运行仿真 ``` 此方法适合大型工程快速配置波形窗口。 --- #### 三、验证信号正确性 1. **观察关键节点信号** 例如在FFT应用中,检查输出频谱是否与预期频率匹配。引用中通过对比MATLAB仿真结果,验证横坐标$f=1\text{MHz}$和$f=7\text{MHz}$处的功率谱是否正确。 2. **使用断言(Assertion)自动检查** 在Testbench中添加条件判断,发现错误时立即报错: ```verilog always @(data_4bits) begin if (data_6bits > 15 && data_4bits != 15) $error("Saturation failed at input %d", data_6bits); end ``` 此方法结合穷举测试可快速定位问题。 --- ### 总结流程图 ```plaintext 编写Testbench生成信号 → 启动仿真工具 → 添加信号到波形窗口 → 运行仿真并验证结果 ↑ | | └── 外部数据/系统函数 ────┘ └── 断言/波形对比 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值