这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】+FPGA基本语法语句if…else与case语句分析分享

共3条 1/1 1 跳转至

【换取手持数字示波器】+FPGA基本语法语句if…else与case语句分析分享

菜鸟
2024-05-23 18:45:16   被打赏 30 分(兑奖)     打赏

if…else case 语句分析

两者结构完全一致的情况 两段代码,EX1使用if……else语句,EX2使用case语句,它们综合的结果有多大差异呢?最终布局布线后的结构又有多大差异呢?二者代码如下:

input clk;  
input rst_n; // 修正了rst_n的命名  
input [3 :0] data;  
output [2:0] add;  
reg [2 :0] add; // 修正了方括号的字符  
  
always @(posedge clk) begin  
    if (!rst_n) begin  
        add <= 0;  
    end else begin  
        if (data < 4) add <= 1;  
        else if (data < 8) add <= 2;  
        else if (data < 12) add <= 3;  
        else add <= 4;  
    end  
end


我们可以分析一个等价的case语句版本的代码(EX2):

input clk; 
input rst_n; 
input [3 :0] data; 
output [2:0] add; 
reg [2 :0] add; 
 
always @(posedge clk) begin 
    if (!rst_n) begin 
        add <= 0; 
    end else begin 
        case  
            {4{data[3]}}: // 假设data永远不会大于11,这里是为了确保case的完整性 
                add <= 4; 
            {3{data[3]}, ~data[2]}: // data在8到11之间 
                add <= 4; 
            {2{data[3]}, ~data[2], ~data[1]}: // data在4到7之间 
                add <= 3; 
            {data[3], ~data[2], ~data[1], ~data[0]}: // data在0到3之间 
                add <= 1; 
            default: // 如果data不在上述范围(实际上这是不可能的,因为data是4位) 
                add <= 0; // 或者你可以省略这一行,因为上面已经覆盖了所有情况 
        endcase 
    end 
end


两者结构完全一致的情况

在功能逻辑上,如果两个代码段都是正确编写的,并且覆盖了所有可能的情况,那么它们将产生相同的结果。但是,case语句通常用于更明确地表示多个离散的条件,而if...else语句则用于表示更复杂的逻辑或条件序列。

最终布局布线后的结构差异

布局和布线(placement and routing)是编译器和合成器在将高级描述(如Verilog)转换为实际硬件配置时执行的过程。这些过程可能会受到多种因素的影响,包括目标硬件架构、编译器优化、代码质量等。

在大多数情况下,如果if...elsecase语句在功能上等价,并且没有其他因素(如其他逻辑或资源限制)影响布局和布线,那么它们最终产生的硬件结构应该是相似的。然而,由于编译器和合成器的实现细节,可能会存在微小的差异。

 

 

一个是基于if...else结构的(在您最初的提问中)和另一个是基于case结构的。不过,具体的数字在case结构的描述中并未给出,但我们可以基于一般的理解来推测它们之间的潜在差异。

理解这些资源使用指标的含义:

  • Total logic elements:总的逻辑元素数量,包括组合逻辑和寄存器。

  • Combinational with no      register:没有寄存器的组合逻辑元素数量。

  • Register only:只有寄存器的逻辑元素数量(但这里没有给出实际数值,通常这是为了配置纯存储功能)。

  • Combinational with a      register:带有寄存器的组合逻辑元素数量。

  • Logic element usage by      number of LUT inputs:根据查找表(LUT)输入数量分类的逻辑元素使用。

  • Logic elements by mode:根据操作模式(如正常模式、算术模式等)分类的逻辑元素。

  • Total registers:总的寄存器数量。

  • I/O pins:输入输出引脚数量。

  • Maximum fan-out node:具有最大扇出(即连接到其他逻辑元素的数量)的节点。

  • Maximum fan-out:任何节点的最大扇出值。

  • Total fan-out:所有扇出的总和。

  • Average fan-out:每个节点的平均扇出值。

关于if...elsecase结构在资源使用上的差异:

  1. LUT输入数量:对于if...elsecase语句,如果它们实现相同的逻辑功能,并且编译器/合成器足够智能,那么它们可能会使用相同数量的LUT输入。但是,如果case语句的分支非常多,它可能会需要更多的LUT输入或更多的LUT实例。

  2. 操作模式:对于简单的if...elsecase结构,它们可能主要处于正常模式。然而,如果case语句包含了更复杂的算术或特殊操作,它可能会使用更多的算术模式或特殊模式。

  3. 寄存器使用:如果if...elsecase结构都涉及到寄存器的使用(即Combinational with a      register),那么寄存器的数量将取决于逻辑功能的实现方式。如果case语句的分支导致了更多的寄存器使用(例如,每个分支都需要存储不同的值),那么它可能会使用更多的寄存器。

  4. I/O引脚:对于相同的逻辑功能,if...elsecase结构通常会有相同的I/O引脚数量,因为它们都需要相同的输入和输出。

  5. 扇出:扇出主要取决于逻辑功能的连接方式和目标硬件的架构。如果if...elsecase结构在硬件中产生了类似的连接,那么它们的扇出可能会很相似。

if…else语句和case语句综合后的RTL视图。单从RTL,视图来看,二者综合后的结果是有明显区别的。if…else趋向于有优先级的结构,而case则是并行的结构。

if…else 语句综合的 RTL视图:

blob.png

case 语句综合的 RTL视图:

blob.png

 

基于if...else结构的资源使用描述(我假设这是您提供的第一个描述):

UsageResource 

Total logic elements 

-Combinational with no register: 0 

-Register only: 0 

-Combinational with a register: ? (这个值没有给出,但假设存在

Logic element usage by number of LUT inputs 

--4 input functions: 0

--3 input functions: 2 

--2 input functions: 1 

--1 input functions: 0 

--0 input functions: 0 

Logic elements by node 

-- normal mode: 3 

-- arithmetic mode: 0 

-- qfbk mode: 0(这可能是个打字错误,应为"qfbk mode: 0"或其他有效值

-- register cascade mode: 0 

-- synchronous clear/load node: 0 (同样,这个值没有给出

-- asynchronous clear/load mode: 3 

Total registers: 0 (这个值没有给出

I/O pins: 9 

Maximum fan-out node: rst_n 

Maximum fan out: 3 

Total fan-out: 14 

Average fan-out: 1.17

 

 

注释:

  • Combinational with no      register  Register only 都是0,意味着没有纯组合逻辑或纯寄存器逻辑。

  • Combinational with a      register 的值没有给出,但假设存在。

  • LUT输入的使用情况表明,有两个3输入的函数,没有1输入或0输入的函数(这通常是合理的,因为1输入或0输入的函数很少用LUT实现)。

  • 操作模式表明主要是正常模式和异步清除/加载模式。

  • 寄存器总数和同步清除/加载节点的值没有给出。

 

再看它们的TechnologyMapViewer,分别如图所示。二者完全一致,所以,可以明确的说,在这个例子中,if…elsecase语句最终的实现都是并行的,而且完全·致。

if…else 的Technology Map Viewer:

blob.png

 

case 的Technology Map Viewer:

blob.png

 

记得特权同学过去也曾认为if…else和case综合实现的结果是不一样的,也曾就这个实例写过博文,分析得头头是道。但是现在的结果似乎推翻了这样一种思想,过去使用的是Quartus Ⅱ 7.1i做这个测试,现在使用了9.1版本,8.1的也测试了,也许if…else和case 语句的优化随着软件的升级,已经不再简单地交给用户的代码来决定,而是默认优化了。就像状态机中讨论独热码好还是格雷码好一样,其实这个优化已经成为软件选项了。而综合的RTI,视图到Technology Map Viewer 其实也还是有差距的,它们之间的优化就是映射所要干的活。

总之,if…else和case语句实现的结构到底是怎样还是要看开发工具,具体问题具体分析,不能片面地强调if…else和case语谁好谁坏。

最后引用网友riple兄的一段话,不仅可以应用在if…else和case的讨论中,对于任何的代码风格问题都是一样的:

具体逻辑具体分析,如果你要表达的是同一个逻辑问题,那么if…else和 case 只不过是形式上的不同。综合工具的优化能力足够强的话,就能看穿这个形式上的不同,实现逻辑上的相同。

 

下面再看看它们综合后的RTL视图,如图所示。从RTL视图看,二者的实现确确实实也正如早先所预期的,一个带优先级,一个并行处理。

if…else 综合后 RTL视图:

blob.png

case 综合后 RTL 视图:

blob.png

 

再看看布局布线后的结构吧,如图所示。从最终布局布线后的结构看,和RTL视图很接近,这两个实例代码所使用的if…else和case最终实现的结构是有差异的。从之前的实例分析看这并不稀奇,意外的是使用if…else实现的结构资源消耗居然比。case要来得少(只是相对而言)。这样的结果似乎能够很好地反驳不少人提出的所谓“多用case语句,少用if…else语句,因为实现带优先级的结构比并行结构更耗费资源”的论断。特权同学提出这一点,并不是认为实现带优先级的结构更节省资源,而是想强调一点,任何代码的实现都不是绝对的,所谓好的代码风格也不是一成不变的,是需要设计者在实践中更多地进行具体问题具体分析。

另外,补充一点,该例子中使用多个if…if…语句实现的结果会和case语句的结果一致。

 

if…else布局布线后Technology Map Viewer:.

 

blob.png

case布局布线后Technology Map Viewer:

blob.png

input clk;input rst n;
input close,wr,rd;
output[2:0] db;
reg[2;0] dbr;
always @(posedge clk or negedge rst_n) beginif(!rst n)begindbr<= 3'd0;
endelse begin
dbr <= 3'd0;
if({close,rd,wr)== 3b100)dbr<= 3'bl11;
if({close,rd,wr)==3'b010)dbr <= 3'b101;
if({close,rd,wr)==3b001)dbr<= 3'b011;
end
assigndb=dbr;

 

总结:Verilog代码示例(EX1使用if...elseEX2使用case)中,两者在功能上是等价的,并且假设输入data的范围是011(由于它是一个4位宽的输入),那么两个代码片段都会为add输出正确的值。

关于布局布线后的结构差异,确实取决于多种因素,包括编译器/合成器的实现、优化级别、目标硬件架构等。但通常,如果逻辑是等价的,那么生成的硬件结构在资源使用和性能上也应该是相似的。

然而,对于case语句,它通常被设计用于处理多个离散值的情况,并且对于合成器来说可能更容易进行某些优化,尤其是当条件表达式是简单的常量比较时。另一方面,if...else语句在处理更复杂的逻辑条件时可能更灵活。

在您提供的case语句示例中,有一些地方可能需要澄清或修改:

  1. {4{data[3]}} 这个条件实际上永远不会为真,因为data[3]只有01两种可能,而{4{data[3]}}会生成一个4位宽的向量,其所有位都是data[3]的值。您可能想要直接比较data的值。

  2. 您的case语句中的条件表达式使用了位扩展和取反来匹配data的不同范围,这在某些情况下可能不是最高效的方法。通常,case语句的条件表达式会直接使用data的值。

  3. case语句的default分支中,由于您已经覆盖了所有可能的data值(从011),所以这个default分支实际上是不必要的。

至于资源使用指标:

  • Total logic elements:表示实现整个逻辑功能所需的总逻辑元素数量。

  • Combinational with no      register:表示仅包含组合逻辑(没有存储元素)的部分。

  • Register only:表示仅包含寄存器(没有组合逻辑)的部分,但在这个例子中不太可能出现,因为add是一个寄存器,但它也参与组合逻辑。

  • Combinational with a      register:表示包含组合逻辑和寄存器的部分,这是最常见的类型。

  • Logic element usage by      number of LUT inputs:这提供了根据查找表(LUT)输入数量分类的逻辑元素使用情况的统计信息。LUT是用于实现组合逻辑的基本构件,其大小(即输入数量)会影响资源使用和性能。

 



院士
2024-05-24 06:45:11     打赏
2楼

谢谢楼主的分享~!


高工
2024-05-24 12:01:53     打赏
3楼

谢谢楼主的分享


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]