别乱用 FULL_CASE 和 PARALLEL_CASE

文章目录

写在前面

1、FULL_CASE的用法

1.1、使用default语句

1.2、不使用default语句 

1.3、使用综合属性 FULL_CASE

1.4、综合前后电路仿真不一致

1.5、陷阱

2、PARALLEL_CASE的用法

3、总结


写在前面

        case语句可以说是我们在FPGA开发中使用频率非常高的一条语句。同时,Verilog还提供了语句 casex 和 casez供我们使用。在使用case语句的时候,各类综合工具都提供了以下类似的两句综合语句供我们使用(以Xilinx为例):FULL_CASE  和  PARALLEL_CASE

        这两条综合属性可以帮助我们在一定程度上减少资源,但是其使用也比较容易引入BUG--前后仿真不匹配。接下里就一起看看这把双刃剑的正反两面吧。


1、FULL_CASE的用法

        在case语句的使用中,我们通常会加上default语句来说明未使用状态的输出赋值,如果不加上default语句则通常会产生锁存器LATCH。


1.1、使用default语句

        在如下的8位独热码编码器中,我们用default语句指令了所有除8个有用状态的其他状态。8位2进制数可以一共表示256个状态,这其中只有这8个状态是独热码,剩余的都是我们不需要的。使用default语句全给其输出接到了统一的0。但是,虽然我们不需要使用其他状态,但是综合出来的电路也会有其他状态的编码部分。

module one_hot(
    input 		[7:0] sel,
    output	reg	[2:0] out
);

always @(*) begin
    case(sel)
        8'b0000_0001 : out = 3'b000;
        8'b0000_0010 : out = 3'b001;
        8'b0000_0100 : out = 3'b010;
        8'b0000_1000 : out = 3'b011;
        8'b0001_0000 : out = 3'b100;
        8'b0010_0000 : out = 3'b101;
        8'b0100_0000 : out = 3'b110;
        8'b1000_0000 : out = 3'b111;
        default : out = 3'b001;
    endcase
end

endmodule

        下图是综合出来的电路结构,就是一个纯组合逻辑的编码电路。

        使用的资源情况:6个LUT。 


1.2、不使用default语句 

        接下来把default语句注释掉,这样在非独热码状态的情况下,输出就只能保持之前的状态不变了,也就是说3bit输出应该会输出3个锁存器LATCH。

        综合出来的电路结构如下,和料想的一致,组合逻辑LUT+锁存器LATCH。

        使用的资源情况:5个LUT + 3个FF(FF转变的LATCH)。


1.3、使用综合属性 FULL_CASE

        那么综合属性 FULL_CASE是干啥的?

        FULL_CASE的作用就是告诉综合工具,在这个case语句中,我已经把所有需要的情况都列出来的,剩下的那些是我不需要,你可别再生成多余的电路了。

        还是上面的例子,8bit的独热码编码器,我已经把8个独热码都列出来了,剩下的那256-8=248个臭鱼烂虾都不是独热码编码形式的,我肯定不会用,所以我警告你(综合工具)最好识相点儿,不要生成对应剩余编码的编码电路了。

module one_hot(
    input 		[7:0] sel,
    output	reg	[2:0] out
);

always @(*) begin
    (* full_case *)case(sel)				//所有需要的情况都列出来了
        8'b0000_0001 : out = 3'b000;
        8'b0000_0010 : out = 3'b001;
        8'b0000_0100 : out = 3'b010;
        8'b0000_1000 : out = 3'b011;
        8'b0001_0000 : out = 3'b100;
        8'b0010_0000 : out = 3'b101;
        8'b0100_0000 : out = 3'b110;
        8'b1000_0000 : out = 3'b111;
        //default : out = 3'b001;
    endcase
end

endmodule

        综合出来的电路,比上面两种情况少用了很多资源。因为多余的248个状态vivado不需要编码了,只需要对8个独热码状态进行编码即可。

         使用的资源情况:3个LUT。 


1.4、综合前后电路仿真不一致

        优点是显而易见的,就是节省资源。缺点同样明显,那就是 FULL_CASE 语句是一条综合属性,只能在vivado对RTL进行综合,translate成电路的时候才使用,在做功能仿真的时候是不适用的,也就是说会造成前后仿真结果不一致的问题,容易引入BUG。

        我们可以写个简单的testbench分别对综合前、综合后的功能仿真做下测试。

`timescale 1 ns/ 1 ns
module one_hot_tb();

reg		[7:0] sel;
wire	[2:0] out;
 
                          
one_hot	one_hot_inst(
    .sel	(sel),
    .out    (out)
);

initial	begin                                                  
	sel=8'b0;	
	# 400 $finish;				//200ns后结束仿真		 
end 

always #10 sel = {$random}%256;	//没10ns生成一个0~255的随机数
 
endmodule

        综合前功能仿真结果如下:

        由于之前sel值均不是独热码值,所以输出out无法被编码,又没有使用default语句,所以此时的输出均为x。直到第一个独热码00000001出现,输出开始编码到000。后面又不符合独热码规则,无法编码,所以输出值一直保持之前的值不变,成为了事实上的锁存器。

        直到输入重新变成了10000000和00100000后,输出才开始变成对应的编码值 。

        综合后功能仿真结果如下:

         这个结果是没有生成锁存器的,即使对于非独热码,也有默认的编码值。


1.5、陷阱

        一般情况下,FULL_CASE 语句是不建议使用的,除非你对自己的RTL代码和电路结构有很深的理解。下面是一些使用该语句的陷阱。

(情况一:可能还会存在的锁存器)

        有种说法是:FULL_CASE 语句技能减少资源使用,也能消除锁存器。实则不然,在某些情况下FULL_CASE 语句并不能消除锁存器,比如:

module addrDecode1a (mce0_n, mce1_n, rce_n, addr);

output mce0_n, mce1_n, rce_n;
input [31:30] addr;

reg mce0_n, mce1_n, rce_n;

always @(addr)
	(* full_case *)casez (addr) 
	2'b10: {mce1_n, mce0_n} = 2'b10;
	2'b11: {mce1_n, mce0_n} = 2'b01;
	2'b0?: rce_n = 1'b0;
	endcase
endmodule

        综合出来的电路结构:可以看到还是综合出了2个锁存器。这是因为在case执行语句中,同时出现了对多个变量和单个变量进行赋值,这使得在某些条件下某些变量是无法执行输出的。

        解决这一情况的办法,就是在case语句之前对所有变量均进行赋值,后者直接使用default语句,让所有的情况都有一个入口。 

(情况二:非预期的电路结构) 

        有些时候,如果不注意电路的结构,非要使用FULL_CASE 语句的话,甚至会综合出与预期功能完全不一样的电路。比如:

// no full_case
module code4a (y, a, en);
    output [3:0] y;
    input [1:0] a;
    input en;

    reg [3:0] y;
    always @(a or en) begin
		y = 4'b0;		//初始赋值,防止其他情况无入口产生锁存器
        case ({en,a})
            3'b1_00: y[a] = 1'b1;
            3'b1_01: y[a] = 1'b1;
            3'b1_10: y[a] = 1'b1;
            3'b1_11: y[a] = 1'b1;
        endcase
    end
endmodule

        上面的例子中,首先通过 y = 4'b0;为所有情况都提供了一个赋值的入口,防止了锁存器的产生。然后en作为使能信号,只有在其高电平有效的情况下,才能将地址选择信号a对应的输出y[a]的值拉高。

        综合出来的电路如下:可以看到每一位y的输出都有en参与运算。

         因为地址选择信号只有2位,所以其最大只有4种情况,在上述代码中,这四种情况刚好都列出来。于是,你觉得这个时候可以使用FULL_CASE 语句了,说不定能节省点电路面积。所以,让我们看看接下来会发生什么。

        这是使用了FULL_CASE 语句后综合出来的电路:

        注意看,这个电路最离谱的是,使能信号en已经和整个电路完全没关系了。这是为什么呢?

        这是因为,虽然在使能信号置位时,地址选择信号a只有4个状态;但是在使能信号无效时, 地址选择信号a同样有4个状态。如果使用了FULL_CASE 语句,综合工具可能就会认为此时地址选择信号a已经列出了所有的情况,那么case语句中的{en,a}就从一个3bit信号变成了2bit信号,而自动把使能信号en给忽略掉了!


2、PARALLEL_CASE的用法

        在学习综合语句PARALLEL_CASE的使用之前可能需要复习一下casex和casez语句的使用。Verilog中case,casez,casex语句的用法

        有时在用case语句时,产生的电路会有优先级。如果希望没有优先级,即所有的输入都是并行的情况,要怎么办呢?答案就是使用综合属性PARALLEL_CASE。

        PARALLEL_CASE的作用就是告诉综合工具,在这个case语句中,所有已经被我列出来的情况都是并行的,不需要优先级,你可别按优先级给我生成电路了!

        比如下面使用casez语句的例子,如果不使用PARALLEL_CASE属性,则综合出来的电路肯定是有优先级的:

module intctl2a (int2, int1, int0, irq);
	output int2, int1, int0;
	input [2:0] irq;
	reg int2, int1, int0;
	
always @(irq) begin
	{int2, int1, int0} = 3'b0;
    casez (irq)
		3'b1??: int2 = 1'b1;
		3'b01?: int1 = 1'b1;
		3'b001: int0 = 1'b1;
	endcase
end

endmodule

        综合出来的电路如下。可以看到 int2 只由 irq[2] 决定,int1 由 irq[2] 和 irq[1] 决定,int0 则由irq[2], irq[1] 和 irq[0] 决定。这是因为 case 语句是有优先级的,写在前面的优先级最高。

        接下来我们加入综合属性语句:(* parallel_case *)。

module intctl2a (int2, int1, int0, irq);
	output int2, int1, int0;
	input [2:0] irq;
	reg int2, int1, int0;
	
always @(irq) begin
	{int2, int1, int0} = 3'b0;
	(* parallel_case *)casez (irq)
		3'b1??: int2 = 1'b1;
		3'b01?: int1 = 1'b1;
		3'b001: int0 = 1'b1;
	endcase
end

endmodule

        综合的电路如下。修改后的电路已经不存在优先级了,都是对应bit的irq信号直接控制对应的int信号。

        parallel_case与full_case综合属性一样,存在的一个最大问题就是综合前后的仿真结果不一致的问题,容易引入BUG。


3、总结

  • casez语句的使用要要谨慎,而casex语句则尽量不要使用
  • 如果计划在Verilog代码中添加“full_case parallel_case”指令,则需要更对设计的RTL有全面深入的了解
  • 不要滥用仅full_case和parallel_case,一般情况下只用来来优化独热码的状态机设计
  • 最重要的一点,比起使用“full_case”和“parallel_case”指令,更好的方法是编写完整和并行的case语句!

.

猜你喜欢

转载自blog.csdn.net/wuzhikaidetb/article/details/125361811