verilog代码中避免出现latch方法

一:出现latch的情况?

在组合逻辑中,有时候往往不需要生成latch,所以必须知道某些信号会综合为latch,通过实践发现下面两类会出现latch:
1.在if-else和case中没有else和default将会导致产生latch。这个在夏宇闻的verilog中有讲到。
2.即使if-else 和case语句都满足if都有else,caes都有default,此时还是有可能出现latch,例如:
代码A:

always @(enable or ina or inb) begin
    if (enable) begin
        data_out = ina;
    end
    else begin
        data_out = inb;
    end
end

代码B:

input[3:0] data_in;
always @(data_in)
begin
case(data_in)
    0:         out1 = 1'b1;
    1,3:       out2 = 1'b1;
    2,4,5,6,7: out3 = 1'b1;
    default:   out4 = 1'b1;
endcase
end

verilog代码中避免出现latch方法
在上图两段代码都是标准的if-else 和case语句,但是第二段代码却可以生产latch,通过将第二段代码综合后看RTL就可以清楚看到:
verilog代码中避免出现latch方法_第1张图片

第二段代码产生了4个latch。第二段代码之所以会出现latch,是因为:
out1,out2,out3,out4仅仅在data_in一种情况下赋值,当data_in在非条件下,就没有对该信号赋值。

二、怎么使得代码中消除不需要的latch呢?

   由上面发现即使使用了if-else和 case-default这样标准的代码风格,还是会导致latch的产生的。通过测试可以发现要使得组合逻辑中,特别是在三段式状态机中代码不产生latch,必须做到下面几点:

1. if-else 和case-default必须配套,也就是出现if 必须出现else与之配套;有case必须在后面写一个default。
2.在所有条件下,对信号都进行赋值
下面解释一下第二点,还是按照前面的代码为例,如果将out1在所有条件下都赋值,也就是将代码修改为:

input[3:0] data_in;
always @(data_in)
begin
case(data_in)
    0:         out1 = 1'b1;
    1,3:       begin
                    out1 = 1,b0;
                    out2 = 1'b1;
                end
    2,4,5,6,7: begin
                        out3 = 1'b1;
                        out1 = 1'b0;
                    end
    default:   beign
                    out4 = 1'b1;
                    out1 = 1'b0;
                   end
endcase
end

然后综合后查看RTL,可以发现:
verilog代码中避免出现latch方法_第2张图片
verilog代码中避免出现latch方法
可以看出out1没有产生latch。所以在信号不多的情况下,可以讲每个信号在所有条件下都进行赋值,这样就会消除latch的产生。
但是,在三段式状态机代码中,特别是状态机多,信号特别多的情况下,在每个条件下都给每个信号赋值,这样就会导致代码很冗长,此时可以给每个信号一个初值。修改方法为:

input[3:0] data_in;
always @(data_in)
begin
    out1 = 1'b0;
    out2 = 1'b0;
    out3 = 1'b0;
    out4 = 1'b0;
    case(data_in)
    0:         out1 = 1'b1;
    1,3:       begin
                    out2 = 1'b1;
                end
    2,4,5,6,7: begin
                    out3 = 1'b1;
                end
    default:   beign
                    out4 = 1'b1;
               end
    endcase
end

verilog代码中避免出现latch方法
这样就是在选择语句之前给信号赋一个初值,这样就不需要在所有条件都给信号赋值,减少代码的重复和代码量。上图代码综合后的RTL图为:

verilog代码中避免出现latch方法_第3张图片
可以发现这种方法也是可行的。

所以总结为:

   1.如果代码简单,信号少,直接在每个条件下都赋值
   2.如果代码复杂,信号多,就可以在case或是if语句前给信号赋一个初值。

关于第二条,估计会产生一些迷惑,例如在前面代码中data_in为1,out2赋值为0还是赋值为1呢?
这里就涉及到阻塞赋值和非阻塞赋值的区别。在上面代码中一般都是阻塞赋值,也就是上面一句赋值都完成了,才进行第二条语句的赋值。在上面的代码中,就是先给out2赋值为0,然后再赋值为1。这个不同于非阻塞赋值,如果是非阻塞赋值的话,就会导致同时给out2赋值两个值,导致亚稳态。
最后需要注意的是:在组合逻辑中,always@()的括号里面,使用*代替敏感变量,这是在verilog2001中的代码风格,这样可以避免敏感变量不全的情况,建议在写组合逻辑中这样书写代码。

附加

组合逻辑赋值给自己也会产生latch

    always @(*) begin
        if(condition)
            aa = 1'b0;
        else
            aa = aa; //generate latch
    end

你可能感兴趣的:(FPGA)