verilog教程(6)—— verilog的三种建模方式-Anlogic-安路社区-FPGA CPLD-ChipDebug

verilog教程(6)—— verilog的三种建模方式

国内verilog教程最出名的就是夏宇闻老先生的书,我个人也是用这本书入门,但是实话讲从后来的工作经验中看,夏先生的书更多的是从软件仿真角度来讲的,verilog它毕竟是硬件描述语言而不是软件语言,不利于初学者将verilog与硬件联系起来,写出来的代码可能仿真没问题但上板根本运行不起来,因为工具没有办法综合出来。网上也有不少人有类似看法。

既然verilog是硬件描述语言,硬件描述从某种角度讲不就是用verilog给电路建模嘛,因此从建模角度理解更合适一点。HDL的建模中,主要有结构化描述方式、数据流描述方式和行为描述方式,下面分别举例说明三者之间的区别。

结构化描述方式

结构化的建模方式就是通过对电路结构的描述来建模,即通过对器件的调用( HDL概念称为例化),并使用线网来连接各器件的描述方式。这里的器件包括Verilog HDL的内置门如与门and,异或门xor等,也可以是用户的一个设计。 结构化的描述方式反映了一个设计的层次结构。 

[1]:一位全加器

20240406095535500-image

module FA_struct (A, B, Cin, Sum, Count);
    input A;
    input B;
    input Cin;
    output Sum;
    output Count;
    wire S1, T1, T2, T3;
    // -- statements -- //
    xor x1 (S1, A, B);
    xor x2 (Sum, S1, Cin);
    and A1 (T3, A, B );
    and A2 (T2, B, Cin);
    and A3 (T1, A, Cin);
    or O1 (Cout, T1, T2, T3 );
endmodule

该实例显示了一个全加器由两个异或门、三个与门、一个或门构成。 S1、 T1、 T2、 T3则是门与门之间的连线。代码显示了用纯结构的建模方式,其中xor 、 and、 or 是Verilog HDL 内置的门器件。以 xor x1 (S1, A, B) 该例化语句为例: xor 表明调用一个内置的异或门,器件名称xor ,代码实例化名x1(类似原理图输入方式)。 括号内的S1, A, B 表明该器件管脚的实际连接线(信号)的名称 ,其中 A、 B是输入, S1是输出。其他同。

[2]:两位的全加器

两位的全加器可通过调用两个一位的全加器来实现。该设计的设计层次示意图和结构图如下:

20240406095933210-image

module Four_bit_FA (FA, FB, FCin, FSum, FCout ) ;
    parameter SIZE = 2;
    input [SIZE:1] FA;
    input [SIZE:1] FB;
    input FCin;
    output [SIZE:1] FSum;
    output FCout;
    wire FTemp;
    FA_struct FA1(
    .A (FA[1]),
    .B (FB[1]),
    .Cin (FCin) ,
    .Sum (FSum[1]),
    .Cout (Ftemp)
    );
    FA_struct FA2(
    .A (FA[2]),
    .B (FB[2]),
    .Cin (FTemp) ,
    .Sum (FSum[2]),
    .Cout (FCount )
    );
endmodule

该实例用结构化建模方式进行一个两位的全加器的设计,顶层模块Four_bit_FA 调用了两个一位的全加器 FA_struct 。在这里,以前的设计模块FA_struct 对顶层而言是一个现成的器件,顶层模块只要进行例化就可以了。 注意这里的例化中,端口映射(管脚的连线)采用名字关联,如 .A (FA[2]) ,其中.A 表示调用器件的管脚A,括号中的信号表示接到该管脚A的电路中的具体信号。 wire 保留字表明信号Ftemp 是属线网类型。 另外,在设计中,尽量考虑参数化的问题。 器件的端口映射尽量采用名字关联。

数据流描述方式

数据流的建模方式就是通过对数据流在设计中的具体行为的描述的来建模。最基本的机制就
是用连续赋值语句。在连续赋值语句中,某个值被赋给某个线网变量(信号),语法如下:
assign [delay] net_name = expression;
如: assign #2 A = B

在数据流描述方式中,还必须借助于HDL提供的一些运算符,如按位逻辑运算符 :逻辑与
&),逻辑或(|)等。
以上面的全加器为例,可用如下的建模方式:

20240406100233727-image

`timescale 1ns/100ps
module FA_flow(A,B,Cin,Sum,Count)
    input A,B,Cin;
    output Sum, Count;
    wire S1,T1,T2,T3;
    assign # 2 S1 = A ^ B;
    assign # 2 Sum = S1 ^ Cin;
    assign #2 T3 = A & B;
    assign #2 T1 = A & Cin;
    assign #2 T2 = B & Cin ;
endmodule

注意在各assign 语句之间,是并行执行的,即各语句的执行与语句之间的顺序无关。如上,当A有个变化时,S1T3T1 将同时变化, S1的变化又会造成Sum的变化。

行为描述方式

行为方式的建模是指采用对信号行为级的描述(不是结构级的描述)的方法来建模。在表示方面,类似数据流的建模方式,但一般是把用initial 块语句或always 块语句描述的归为行为建模方式。行为建模方式通常需要借助一些行为级的运算符如加法运算符(+),减法运算符()等。

以下举个例子,对initial always 语句的具体应用可看相关章节的介绍,这里,先对行为建模方式有个概念。
[1] 一位全加器的行为建模

module FA_behav1(A, B, Cin, Sum, Cout );
input A,B,Cin;
output Sum,Cout;
reg Sum, Cout;
reg T1,T2,T3;
always@ ( A or B or Cin )
begin
    Sum = (A ^ B) ^ Cin ;
    T1 = A & Cin;
    T2 = B & Cin ;
    T3 = A & B;
    Cout = (T1| T2) | T3;
end
endmodule

需要先建立以下概念: 1、只有寄存器类型的信号才可以在always和initial 语句中进行赋值,类型定义通过reg语句实现。 2、 always 语句是一直重复执行,由敏感表(always 语句括号内的变量)中的变量触发。 3、 always 语句从0 时刻开始。 4、在begin 和end 之间的语句是顺序执行,属于串行语句。

[2]:一位全加器的行为建模

module FA_behav2(A, B, Cin, Sum, Cout );
input A,B,Cin;
output Sum,Cout;
reg Sum, Cout;
always@ ( A or B or Cin ) begin
    {Count , Sum} = A + B + Cin ;
end
endmodule

在例2中,采用更加高级(更趋于行为级)描述方式,即直接采用 “ +”来描述加法。 {Count, Sum}表示对位数的扩展,因为两个1bit 相加,和有两位,低位放在Sum 变量中,进位放在Count 中。

混合设计描述

在实际的设计中,往往是多种设计模型的混合。一般来说,对复杂的设计,采用结构描述方式,对低层模块,可采用数据流、行为层级或两者的结合。如上面的两位全部加器,对第四模块(Four_bit_FA)采用结构描述方式对低层进行例化,对低层模块(FA)可采用结构描述、数据流描述或级行为描述。

请登录后发表评论

    没有回复内容