Menu Close

3/8译码器的不同实现在FPGA上综合后逻辑比较

前面在Verilog语言编程与FPGA应用教材中介绍了3/8译码器及Verilog不同实现方法。本文将在之前讨论3/8译码器不同Verilog实现方法的基础上,在Vivado IDE中对不同的实现代码进行综合,分析比较对FPGA逻辑资源的消耗(注意以下消耗逻辑资源的分析是基于FII-PRX100-D开发板的真实逻辑资源)。

 

图1所示为3/8译码器的真值表。

%title插图%num

图1  3/8译码器真值表

 

第一种方法:与或非并发赋值

module dec3t8
(
    input  a, b, c,
    output y0, y1, y2, y3, y4, y5, y6, y7
);
assign    y0 = ~a & ~b & ~c;
assign    y1 = ~a & ~b &  c;
assign    y2 = ~a &  b & ~c;
assign    y3 = ~a &  b &  c;
assign    y4 =  a & ~b & ~c;
assign    y5 =  a & ~b &  c;
assign    y6 =  a &  b & ~c;
assign    y7 =  a &  b &  c;
 
endmodule

 

综合后的电路图如图2所示。

%title插图%num

图2 与或非并发赋值电路图

 

从图2的电路图中可以看出,这个3/8译码器的逻辑组成主要是LUT和I/O buffer。

 

消耗的逻辑资源如表1所示:

资源 估值 FPGA可用资源 利用率%
LUT 4 63400 0.01
IO 11 300 3.67

表1 与或非并发赋值资源消耗表

 

从表1可以看出,Vivado只使用了4个查找表(LUT,lookup table)来构建3/8译码器的逻辑。11个IO口是因为输入向量a加上输出向量y总共有11比特。这里FPGA可用资源陈列的是FII-PRX100-D的芯片xc7a100tfgg676-2的硬件资源。从利用率上来看,这个模块十分小,LUT只占FPGA总资源的0.01%

 

第二种方法:在always过程中采用if语句译码

module dec38if
(
    input      [2:0] a,
    output reg [7:0] y
);
 
always@(*)  
begin
    y = 8'b0;
 
    if(a[2])    
    begin
        if(a[1]) 
        begin
            if(a[0]) y[7] = 1'b1;
            else     y[6] = 1'b1;
        end
        else  
        begin
            if(a[0]) y[5] = 1'b1;
            else     y[4] = 1'b1;
        end
    end
    else 
    begin
        if(a[1])    
        begin
            if(a[0]) y[3] = 1'b1;
            else     y[2] = 1'b1;
        end
        else    
        begin
            if(a[0]) y[1] = 1'b1;
            else     y[0] = 1'b1;
        end
    end
end
 
 
endmodule

 

综合后的电路图如图3所示。

%title插图%num

图3 if语句电路图

 

通过观察if语句综合后的电路图后发现,if语句的优先级在图3中没有体现出来

 

消耗的逻辑资源如表2所示:

资源 估值 FPGA可用资源 利用率%
LUT 4 63400 0.01
IO 11 300 3.67

表2 if语句资源消耗表

 

到目前为止,比较第一种方法:与或非并发赋值和第二种方法:在always过程中采用if语句译码的综合后电路图和资源消耗表后发现,这两种方法在Vivado综合器后的逻辑一模一样。

 

第三种方法:always 过程中case语句实现

module dec38case
(
    input      [2:0] a,
    output reg [7:0] y
);
 
always@(*)  
begin
    case(a)
    7: y = 8'b1000_0000;
    6: y = 8'b0100_0000;
    5: y = 8'b0010_0000;
    4: y = 8'b0001_0000;
    3: y = 8'b0000_1000;
    2: y = 8'b0000_0100;
    1: y = 8'b0000_0010;
    0: y = 8'b0000_0001;
    default: y = 8'bxxxx_xxxx;
    endcase
 
end
 
endmodule

综合后的电路图如图4所示。

%title插图%num

图4 case语句电路图

消耗的逻辑资源如表3所示:

资源 估值 FPGA可用资源 利用率%
LUT 4 63400 0.01
IO 11 300 3.67

表3 case语句资源消耗表

 

通过第三种方法综合后电路图和资源消耗表后发现,以上三种方法在Vivado综合器后的逻辑一模一样。

 

第四种方法:不考虑输入有z,x 的情况

module dec38case
(
    input [2:0] a,
    output reg [7:0] y
);
always@(*)
begin
    y = 0;
    y[a] = 1'b1;
end
endmodule

综合后的电路图如图5所示。

%title插图%num

图5 向量索引电路图

消耗的逻辑资源如表4所示:

资源 估值 FPGA可用资源 利用率%
LUT 4 63400 0.01
IO 11 300 3.67

表4 向量索引资源消耗表

 

这里还补充一种可以实现3/8译码器的方法,通过位移:

module dec38case
(
    input      [2:0] a,
    output     [7:0] y
);

assign y = 1'b1 << a;

endmodule

综合后的电路图如图6所示。

%title插图%num

图6 位移电路图

消耗的逻辑资源如表5所示:

资源 估值 FPGA可用资源 利用率%
LUT 4 63400 0.01
IO 11 300 3.67

表5 位移资源消耗表

 

通过比较上述五种方法实现3/8译码器综合后的电路图和资源消耗表发现:五种不同实现方法综合后的电路都是一模一样。观察到这里,实验结果有些令人疑惑。之前在学习Verilog语法时,我们提到过if条件语句带有优先性,会产生延时,case语句综合后的逻辑会小一些。。。但是通过以上的图表,结果似乎与之前学习到的规律相悖。其实,出现上述无论什么代码实现,综合后的逻辑都是一样的原因,是因为当前的模块过于小,Vivado综合器的智能程度足以优化Verilog代码,并按照优化后的最优解分配资源。

Vivado的综合器因为不开源,所以这里只能通过实验现象进行分析其特点。从以上的实验来说,对于小模块,综合器可能会自动将用户的Verilog代码优化为更省资源的形式,这就是为什么对于3/8译码器,理论上更好的实现方式和最不好的实现方式综合结果是一样的。但是注意,Verilog实现方法的算法差异往往在大工程中就会明显体现出来,这就是为什么我们需要学习体会不同实现方法的特点和差异。针对Verilog代码综合后的逻辑,分析学习实战项目中的设计技巧,之后将会在其它例子中和大家继续分享。

 

 

Posted in FPGA, Verilog, Verilog, Vivado, 开发工具, 开发语言, 文章, 编程语言

1 Comment

发表评论

相关链接