FPGA知识汇集-值得收藏的Verilog代码风格1-FPGA新闻资讯社区-FPGA CPLD-ChipDebug

FPGA知识汇集-值得收藏的Verilog代码风格1

01

使用`include 编译器指令

包含`include 编译器指令的文件用来在综合过程中将源文件的全部内容插人到另一个文件中,通常用于包含全局项目定义,不需要在多个文件中重复相同的代码。另一个应用举例是将部分代码插人到模块中,如下所示:

//文件test_bench_top . v

//顶层模拟测试平台

module test_bench_top;

`include “test_case.v”

endmodule

//文件test_case.v

initial beain

//.…

end

task my task;

//.…

endtask

`include编译器指令的语法定义为

`include<filename>

<filename>可以是文件名称,也可以包含一个绝对或相对路径

`include “test_case.v”

`include “../../includes/test_case.v”

`include “/home/myprojects/test/includes/test_case.v”

建议在`include中只使用文件名,而不要带有绝对或相对路径,这将使代码存放更自由,也更易于移植。路径名可以使用综合或仿真工具选项来确定,例如

XST -vlgincdir<directory_name>( Verilog的`Include目录)和

ModelSim +incdir+< directory_name >。

另一项建议是包含的文件越简单越好,而且不要使用嵌套的`include指令。

02

使用`define编译器指令、参数和局部参数

`define是宏文本替换编译器指令,定义为

`define < text_macro >

<text_macro>可以包含带可选参数列表的单行或多行文本。

`define具有全局功能。一旦定义了一个宏文本名称,就可以在该项目的任何地方使用。宏文本通常是简单的标识符,用于定义状态名、常量或字符串。

宏文本也可以定义为综合或仿真工具选项。例如,XST支持

“- define < text macro >”,ModelSim有“+define +< text_macro>”命令行选项。

与源代码中使用`define不同的是,使用命令行选项的优点是它独立于文件的编译顺序。

parameter关键字定义模块特有的参数,其作用范围为特定的模块实例。

parameter用来为模块实例提供不同的配置,例如输人或输出端口的宽度。下面是一个使用parameter关键字的例子。

module adder # (parameter WIDTH =8)

(input [WIDTH-1:0] a,b,

   output [WIDTH-1:0] sum ) ;).

   assignsum=a+b;

endmodule // adder

//adder 模块的一个实例

adder #(16) addr1

{.a(a[15:0]),.b(b[15:0]),.sum(sum[15:0]))};

localparam关键字与paramerer类似,赋值为一个常量表达式,只在特定模块范围内有效。

建议对于特定模块的常量(如状态值),不要使用`define和parameter,而是使用localparam。

03

操作数位宽不匹配

Verilog规范定义了一些规则来解决赋值或操作符左右位宽不匹配的问题。以下是几个例子。

reg [3:0] a;

reg [4:0] b;

reg c;

always @ (posedge clk)

If(a== b)  // a和b的位宽不同

      c <= 1’b1;

reg [3:0] a;

wire b;

wire [2:0] c;

wire [3:0] d;

a=b?c:d  // c和d的位宽不同

wire [9:0] a;

wire [5:0] b;

wire [1:0] c;

wire [7:0] d,

assign d = a|b|c; // a、b、c和d的位宽不同

解决位宽不同的规则非常复杂,并且难以遵循。当使用两个不同位宽的操作数时,对于无符号的一个或两个操作数,较小的操作数的最高有效位使用零进行扩展,以使得它与较大数的位宽相匹配。当右边数的位宽大于赋值目标的位宽时,,右边数的高位将被截去。

建议操作数与赋值符右边和左边的位宽应绝对匹配,以避免综合工具自动截去或扩展位宽。

04

连接模块实例的端口

Verilog定义了两种连接模块实例端口的方法:通过名称和通过端口顺序。使用有序端口连接方法时、端口列表中的第一个信号被连接到模块定义时的第一个端口,第二个信号连接到第二个端口,以此类推。通过名称连接端口时,允许更多的灵活性,例如可以省略一个未连接的输出端口。虽然它比“通过端口顺序”的方法需要的代码量更大,但更具有可读性且不容易出错,尤其适合于具有数百个端口的大型模块。端口连接选项在下面的例子中说明。

//低一级模块

module low(cutput [1:0]out, input inl, in2);

//  …

Endmodule

//高一级模块

module high (output[5:0]out1, input[3:0] inl,in2);

//通过顺序连接端口

low low1(out1[1:0], in1[0], in2[0] )

//通过顾序连接端口

//错误:交换了in2和inl

low low2(out1[3:2],in2[1], inl[1])

//通过名称连接

low low3 (.out (outl[5:4]), .inl(in1[2]).in2 (in2[2]))

//通过名称连接端口:一个输出未联接

low low4(.out(), .in1(in1 [3]),.in2(in2[3]))

endmodule

建议在模块实例中使用“通过名称”的方法进行端口连接.

未完待续。

请登录后发表评论

    没有回复内容