快讯
HOME
快讯
正文内容
verilog not nand Vivado使用技巧-支持的Verilog语法
发布时间 : 2024-11-24
作者 : 小编
访问数量 : 23
扫码分享至微信

Vivado使用技巧-支持的Verilog语法

复杂的电路设计通常使用自顶向下的设计方法,设计过程中的不同阶段需要不同的设计规格。比如架构设计阶段,需要模块框图或算法状态机(ASM)图表这方面的设计说明。一个框图或算法的实现与寄存器(reg)和连线(wire)息息相关。Verilog便具有将ASM图表和电路框图用计算机语言表达的能力,本文将讲述Vivado综合支持的Verilog硬件描述语言;

Verilog提供了行为化和结构化两方面的语言结构,描述设计对象时可以选择高层次或低层次的抽象等级。使用Verilog设计硬件时,可以将其视作并行处理和面向对象编程。Vivado综合支持IEEE 1364标准。Vivado综合对Verilog的支持可以用最有效的方式描述整体电路和各个模块。综合会为每个模块选择最佳的综合流程,将高层次的行为级或低层次的结构级转换为门级网表;

1.Variable Part Selects 可变部分选择

除了用两个明确的值限定选择边界外(如assign out = data[8:2]),还可以使用变量从向量中选择一组bit。设置一个起始点和截取的宽度,起始点可以动态变化,示例如下:

reg [3:0] data;

reg [3:0] select;

wire [7:0] byte = data[select +: 8]; //+、-表示从起始点开始增加或减少

2.Structural Verilog 结构化verilog

Verilog可以进行多个代码块设计,并按一定的设计层次组合起来,下面给出于此相关的重要概念:

组件(Component):结构化设计中的一个基本块;

申明(Declaration):组件与外部交流的信息;

主体(Body):组件内部的行为或结构;

端口(Port):组件的I/O;

信号(Signal):组件与组件之间的连线;

一个组件用常见的模块(module)来表示,组件之间的连接由实例化(instantiation)声明实现,实例化声明规定一个组件在另外一个组件或电路中的实例,赋予标识符,并用关系列表设定信号与端口之间的联系;

除了自己设计的组件外,结构化Verilog还支持实例化预定义的原语:逻辑门、寄存器、Xilinx特定的原语(如CLKDLL、BUFG),这些原语都定义在Xilinx Verilog库文件unisim_comp.v中,逻辑门原语包括AND、OR、XOR、NAND、NOR、NOT,实例化这些逻辑门来搭建更大的逻辑电路,示例如下:

//实现2输入或非逻辑功能

module build_xor

(

input a, b,

output c

);

wire a_not, b_not;

//每个实例必须有不同的实例化名称

not a_inv (a_not, a);

not b_inv (b_not, b);

and a1 (x, a_not, b);

and a2 (y, b_not, a);

or out (c, x, y);

endmodule

//实例化预定义的原语FDC和BUFG

module example (sysclk, in, reset, out);

input sysclk, in, reset;

output out;

reg out;

wire sysclk_out;

FDC register (out, sysclk_out, reset, in); //position based referencing

BUFG clk (.O(sysclk_out),.I(sysclk)); //name based referencing

3.Verilog Parameters verilog参数

参数化代码提高了可读性和代码紧凑型、容易维护和再使用。一个Verilog参数(parameter)就是一个常数(不支持字符串),且实例化参数化模块时可以改写参数值,下面给出示例:

//Verilog参数控制实例化块寄存器的宽度

module myreg #(parameter SIZE = 1)

(

input clk, clken,

input [SIZE-1:0]d,

output reg [SIZE-1:0]q

);

always @(posedge clk)

if (clken) q <= d;

endmodule

//顶层模块

module test #(parameter SIZE = 8)

(

input clk, clken,

input [SIZE-1:0] di,

output [SIZE-1:0] do

);

myreg #SIZE inst_reg (clk, clken, di, do);

endmodule

module parameter_generate_for_1 (clk, si, so);

parameter SIZE = 8;

input clk;

input si;

output so;

reg [0:SIZE-1] s;

assign so = s[SIZE-1];

always @ (posedge clk)

s[0] <= si;

genvar i;

generate

for (i = 1; i < SIZE; i = i+1)

begin : shreg

always @ (posedge clk)

begin

s[i] <= s[i-1];

end

end

endgenerate

endmodule

4.Verilog Usage Restrictions Verilog使用限制

在Vivado综合中用到的Verilog语法有如下3点限制:

大小写敏感:Verilog是一种大小写敏感的语言,但在Vivado中,只有实例和信号名称会区分大小写。如果两个module名称只有大小写不同,综合时会报错

阻塞和非阻塞赋值:不要混合使用阻塞和非阻塞赋值。尽管综合时可能不会报错,但在仿真时会出现错误

整数的处理 某些情况下,Vivado综合器处理整数时与其它综合工具方法不同,因此必须使用特定的代码编写方式。例如在Case语句或拼接语句中,使用未定义大小的整数都会导致无法预料的结果;

下面给出两个错误例子:

//同一信号不要混用阻塞和非阻塞赋值

always @(in1)

if (in2) out1 = in1;

else out1 <= in2;

//同一信号的不同bit不要混用

if (in2) begin

out1[0] = 1'b0;

out1[1] <= in1;

end

else begin

out1[0] = in2;

out1[1] <= 1'b1;

end

整数处理方式不当引起错误的情况:

reg [2:0] condition1; always @(condition1) begin

case(condition1)

4 : data_out = 2; // Generates faulty logic 未声明4的位宽,而condition1的位宽为3

3'd4 : data_out = 2; // Does work

endcase

end

//拼接语句

reg [31:0] temp;

assign temp = 4'b1111 % 2; //未确定位宽的运算用临时信号存储

assign dout = {12/3,temp,din}; //12/3运算位宽不确定,结果错误

5. Verilog System Tasks and Functions 系统任务和函数

Vivado综合支持的Verilog构造与系统任务包括:

整数、实数、assign(有限制)、deassign(有限制)、repeat语法(重复值必须是常数)、for语法(范围必须是静态的)、disable(不能用于for循环和repeat循环)、module定义、defparam、实例数组、`default_nettype、`define、`ifdef、`ifndef、`elsif、`include、`file、`line、$fclose、$fgets、$fopen、$fscanf、$readmemb、$readmemh、$signed、$unsigned、$floor(仅用于参数)、$ceil(仅用于参数)。

Vivado综合不支持和会忽视的的Verilog构造和系统任务包括:

字符串、网络类型(tri0、tri1、trireg)、驱动强度、实数和实时寄存器、命名事件、事件(@)、延迟(#)、force、release、forever语法、wait、并行块、设定块、macromodule定义、层次结构名称、`celldefine、`endcelldefine、`resetall、`timescale、`unconnected_drive、`nounconnected_drive、`uselib、$display、$fdisplay、$finish、$fwrite、$monitor、$random、$stop、$strobe、$time、$write、$clog2(仅SystemVerilog支持)、$rtoi、$itor、all others。

介绍其中几个非常常用的系统任务:

$signed和$unsigned可以强制规定输入数据为带符号数或无符号数,并作为返回值,不用管之前的符号。

$readmemb和$readmemh可以用于初始化块存储器,两者分别用2进制和16进制表示。如“$readmemb(“ram.data”, ram, 0, 7)”;

6.Verilog Primitives 原语

Vivado支持上文列出的Verilog门级原语,但不支持上拉下拉、驱动强度和延迟、原语矩阵这些类型的门级原语,也不支持如下转换级原语:cmos、nmos、pmos、rcmos、rnmos、rpmos、rtran、rtranif0、rtranif1、tran、tranif0、tranif1;

实例化门级原语的示例如下:

gate_type instance_name (output, inputs); //语法模板

and U1 (out, in1, in2);

bufif1 U2 (triout, data, trienable);

7.Behavioral Verilog 行为级verilog

行为级Verilog中的变量都申明为整数,数据类型可以是reg(程序块中赋值)、wire(连续赋值)和integer(会被转换为寄存器类型);所有变量的默认位宽为1bit,称作标量(scalar);定义的N bits位宽变量称作向量(Vector);reg和wire可以定义为带符号数signed或无符号数unsigned;变量的每个bit可以是如下值:1(逻辑1)、0(逻辑0)、x(未知逻辑值)、z(高阻);

reg [3:0] arb_priority;

wire [31:0] arb_request;

wire signed [8:0] arb_signed;

寄存器在定义时可以初始化,初始值是一个常数或参数,不能是函数或任务的调用;在全局复位或上电时,Vivado综合会将初始化值作为寄存器的输出(作为寄存器的INIT属性值);而且该初始值与本地复位是相互独立的 ;

reg arb_onebit = 1'b0;

reg [3:0] arb_priority = 4'b1011;

Verilog支持定义wire和reg的数组,支持一维数组和二维数组,但每次从数组中选择的元素不能超过一个,数组也不能作为任务或函数的传递参数。数组的定义示例如下:

//有32个元素的数组,每个元素4bits位宽

reg [3:0] mem_array [31:0];

//包含64个8bits位宽元素的数组

wire [7:0] mem_array [63:0];

//包含256*16个8bits位宽wire元素的二维数组

wire [63:0] array2 [0:255][0:15];

//包含256*8个64bits位宽reg元素的二维数组

reg [63:0] array2 [255:0][7:0];

Vivado支持的所有表达式列在下表中:

其中“===”和“!==”在综合时与“==”和“!=”功能相同,没有任何差别。但在仿真中,可以用来判断变量是否与’x’和’z’是否相等。下表给出常用操作符的运算结果,以供查阅:

initial和always是两个程序块,每个块内部组织了一些语法声明,用begin和end表示范围。块内部的语法声明按顺序执行。综合时只会处理always块,会忽略initial块 ;

8.模块module

Verilog中描述组件(component)的方法便是模块(module),模块必须申明与实例化。模块申明包括模块名称、电路I/O端口列表、定义功能的主体,并以endmodule结束;

每个电路I/O端口要有名称、端口模式(input、output、inout),如果端口是数组类型还要有范围信息。下面给出两种模块申明方法的示例:

//方法1

module example (A, B, O);

input A, B;

output O;

assign O = A & B;

endmodule

//方法2,推荐用法

module example

(

input A, B,

output O

);

assign O = A & B;

endmodule

实例化模块时,要定义一个实例化名称和一个端口关系表。列表要规定实例与顶层模块之间如何连接,列表中的每一个元素将模块申明中的一个形式端口(port)和顶层模块中的实际网络(net)连接在一起。下面给出一个实例化上述模块的例子:

module top

(

input A, B, C,

output O

);

wire tmp;

example inst_example (.A(A), .B(B), .O(tmp));//实例化

assign O = tmp | C;

endmodule

连续赋值 Continuous Assignments

连续赋值语句常用于组合逻辑中,在综合时vivado会忽略组合逻辑的延时和强度,并且连续赋值只能对wire和tri数据类型赋值;

直接连续赋值用assign关键词开头,紧跟一个已经申明过的网络:“wire mysignal; assign mysignal = select ? b : a;”;

简介连续赋值在申明时便完成赋值:“wire misignal = a | b;”;

9.Procedural Assignments 过程赋值

如上所述,wire和三态类型要用连续赋值,reg类型变量则需要用过程赋值,借助always块、任务(task)、函数(function)实现;

always块中的组合逻辑由Verilog时间控制语句有效地建模。其中,延迟时间控制语句[#]仅用于仿真,综合时会忽略;组合逻辑建模主要由事件控制时间控制语句[@]实现;

每个always块都有一个敏感列表,列在“always @”后面的括号中。如果敏感列表中一个信号的相关事件发生(值变化或边沿到来),就会激活该always块。在always块中,如果信号没有在if或case的所有分支中明确地赋值,综合会产生一个锁存器保持之前的值。一个程序块中可以使用如下语句:

[1] if-else:

使用true和false条件来执行语句,执行多条语句要使用begin…end关键词,注意在前面的分支优先级最高;示例如下:

module mux4 (sel, a, b, c, d, outmux);

input [1:0] sel;

input [1:0] a, b, c, d;

output [1:0] outmux;

reg [1:0] outmux;

always @(sel or a or b or c or d)

begin

if (sel[1])

if (sel[0])

outmux = d;

else

else

outmux = c;

if (sel[0])

outmux = b;

end endmodule

else

outmux = a;

[2] case:

比较表达式和分支的值,比较顺序按照编写分支的顺序进行,执行第一个匹配的分支,在前面的分支优先级最高;如果没有匹配项则执行default分支;case语句中不要使用未指定位宽大小的整数,否则可能会产生错误结果;

casez将分支的任意bit位上的z值视作不关心;casex将分支的任意bit位上的x值视作不关心;casez和casex中不关心的bit用‘?’代替;

下面给出一个使用case的示例代码:

module mux4

(

input [1:0] sel,

input [1:0] a, b, c, d,

output reg [1:0] outmux

);

always @ *

case(sel)

2'b00 : outmux = a;

2'b01 : outmux = b;

2'b10 : outmux = c;

2'b11 : outmux = d;

endcase

endmodule

上述代码在评估输入值时,按照一定的优先级顺序进行。如果希望能并行地处理这个过程,使用paralled_case属性,将case语句替换为“(* paralled_case *)” case(sel)”;

[3] For与Repeat:

For循环的边界必须是常数,停止循环条件需要使用>、<、>=、<=四种运算符。使用“var = var +或- step”来控制执行下一轮运算,var为循环变量,step是一个常数值;

repeat语句,重复次数也必须是常数值;

[4] While循环:

While的测试表达式可以是任意合法的Verilog表达式。为了避免造成无限循环,可以使用-loop_iteration_limit选项。该语法很少使用,下面给出一个示例代码:

parameter P = 4;

always @(ID_complete)

begin : UNIDENTIFIED

integer i;

reg found;

unidentified = 0;

i = 0;

found = 0;

while (!found && (i < P))

begin

found = !ID_complete[i];

unidentified[i] = !ID_complete[i];

i = i + 1;

end

end

[5] 顺序always块:

always块可以描述带有顺序性的电路,敏感列表中需要包含如下边沿触发事件(上升沿posedge或下降沿negedge):必须有一个时钟事件、可选的置位/复位事件。如果不需要异步信号,always块模板如下:

always @(posedge CLK)

begin

//同步部分

end

如果需要异步控制信号,always块模板如下:

always @(posedge CLK or posedge ACTRL1 )

begin

if (ACTRL1)

//异步部分

else

//同步部分

end

下面给出四个不同触发方式的顺序always块示例代码:

//上升沿触发时钟控制的8bits寄存器

module seq1

(

input [7:0]DI,

input CLK,

output reg [7:0] DO

);

always @(posedge CLK)

DO <= DI ;

endmodule

//添加一个高电平有效异步复位信号

module seq1

(

input [7:0]DI,

input CLK, ARST,

output reg [7:0] DO

);

always @(posedge CLK or posedge ARST)

if (ARST == 1'b1) DO <= 8'h00;

else DO <= DI ;

endmodule

//再添加一个低电平有效异步置位信号

module seq1

(

input [7:0]DI,

input CLK, ARST, ASET

output reg [7:0] DO

);

always @(posedge CLK or posedge ARST or negedge ASET)

if (ARST == 1'b1) DO <= 8'h00;

else if (ASET == 1'b1) DO <= 8'hFF;

else DO <= DI ;

endmodule

//不使用异步控制逻辑,使用同步复位

module seq1

(

input [7:0]DI,

input CLK, SRST,

output reg [7:0] DO

);

always @(posedge CLK)

if (SRST == 1'b1) DO <= 8'h00;

else DO <= DI ;

endmodule

最后再补充一些与赋值有关的内容。如果表达式左边位宽大于右边的位宽,赋值时需要在高位填充:

如果表达式右边为无符号数,则高位补0;

如果表达式右边为带符号数,则高位补符号位;

如果表达式右边的最高位为x或z,则无论该数为无符号数还是带符号数,高位都补充为x或z;

[6] Tasks and Functions 任务和函数

对于设计中要多次使用重复的代码,可以使用任务task和函数function来减少代码量,提升可维护性;

任务和函数必须在模块中申明和使用;

函数头只包含输入参数;

任务头包含输入、输出和双向参数;

函数的返回值可以申明为无符号数或带符号数,函数内容与always块类似;

下面分别给出一个函数和任务的示例代码:

//函数function使用示例

module test

(

input [3:0] A, B,

input CIN,

output [3:0] S,

output COUT

);

wire [1:0] S0, S1, S2, S3;

function signed [1:0] ADD;//输出

input A, B, CIN;//输入

reg S, COUT;

begin

S = A ^ B ^ CIN;

COUT = (A&B) | (A&CIN) | (B&CIN);

ADD = {COUT, S};

end

endfunction

assign S0 = ADD (A[0], B[0], CIN),//例化的时候只需要例化输入

S1 = ADD (A[1], B[1], S0[1]),

S2 = ADD (A[2], B[2], S1[1]),

S3 = ADD (A[3], B[3], S2[1]),

S = {S3[0], S2[0], S1[0], S0[0]},

COUT = S3[1];

endmodule

//任务task使用示例

module test

(

input [3:0] A, B,

input CIN,

output [3:0] S,

output COUT

);

reg [1:0] S0, S1, S2, S3;

task ADD;//ADD为task名称,这与上面的function不同

input A, B, CIN;//输入

output [1:0] C;//输出

reg [1:0] C;

reg S, COUT;

begin

S = A ^ B ^ CIN;

COUT = (A&B) | (A&CIN) | (B&CIN);

C = {COUT, S};

end

endtask

always @(A or B or CIN)

begin

ADD (A[0], B[0], CIN, S0);

ADD (A[1], B[1], S0[1], S1);

ADD (A[2], B[2], S1[1], S2);

ADD (A[3], B[3], S2[1], S3);

S = {S3[0], S2[0], S1[0], S0[0]};

COUT = S3[1];

end

endmodule

Verilog还支持递归任务和递归函数,要使用automatic关键词申明。递归次数由-recursion_iteration_limit选项设置,默认为64,以避免无限递归;下面给出一个计算阶乘的递归函数的例子:

function automatic [31:0] fac;

input [15:0] n;

if (n == 1) fac = 1;

else fac = n * fac(n-1);

endfunction

Vivado综合支持函数调用来计算常数值,将其称之为常数函数。下面给出一个使用常数函数的例子:

module test #(parameter ADDRWIDTH = 8, DATAWIDTH = 4)

(

input clk, we,

input [ADDRWIDTH-1:0] a,

input [DATAWIDTH-1:0] di,

output [DATAWIDTH-1:0] do

);

function integer getSize;

input addrwidth;

begin

getSize = 2**addrwidth;//2的次方

end

endfunction

reg [DATAWIDTH-1:0] ram [getSize(ADDRWIDTH)-1:0];

always @(posedge clk)

if (we) ram[a] <= di;

assign do = ram[a];

endmodule

Verilog中的常数可以用2进制、8进制、10进制和16进制表示,没有明确表示时默认为10进制;

11.Verilog宏

Verilog可以像这样定义宏“`define TESTEQ1 4’b1101”。定义的宏可以用在后面的代码中,如“if (request == `TESTEQ1)”。使用`ifdef和`endif可以检测是否定义了某个宏,相当于条件编译。如果`ifedf调用的宏被定义过,则内部的代码将会编译;如果宏没有定义,则会编译`else中的代码。`else不是必须的,但必须有`endif。

使用宏可以在不修改源代码的情况下修改设计,在IP核生成和流程测试中很有用。下面给出两个使用宏的例子:

//示例1

'define myzero 0

assign mysig = 'myzero;//注意要加宏符号

//示例2,条件编译

'ifdef MYVAR

module if_MYVAR_is_declared;

...

endmodule

'else

module if_MYVAR_is_not_declared;

...

endmodule

'endif

12 Include文件(不太理解)

Verilog可以将源代码分散在多个文件中,当需要引用另一个文件中的代码时,可以使用如下语句:“`include <path/file-to-be-included>”。该代码可以将指定文件的内容全部插入到当前文件的`include行中。Vivado首先会在指定路径中查找,如果没有找到则会在-include_dirs选项设置的目录中查找。可以同时使用多个`include语句

13 Generate

使用generate可以简化代码编写工作,generate…endgenerate中的内容再RTL分析阶段会被转换为对应的电路;

使用generate语法可以创建原语或模块实例、initial或always程序块、连续赋值、网络和变量申明、参数重定义、任务或函数定义。Vivado支持全部三种generate语法:generate循环(generate-for)、generate条件(generate-if-else)和generate情况(generate-case);

[1] generate-for

使用generate-for主要用来创建多个实例化,与for循环用法基本相同,但必须使用genvar变量,且begin语句必须有一个单独的命名;下面给出一个示例代码:

generate genvar i;

for (i=0; i<=7; i=i+1)

begin : for_name

adder add (a[8*i+7 : 8*i], b[8*i+7 : 8*i], ci[i], sum_for[8*i+7 : 8*i],

c0_or[i+1]);

end

endgenerate

[2] generate-if-else

主要用来控制生成哪一个对象,每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:

//根据数据位宽选择不同的乘法器实现方式

generate

if (IF_WIDTH < 10)

begin : if_name

multiplier_imp1 # (IF_WIDTH) u1 (a, b, sum_if);

end

else

begin : else_name

multiplier_imp2 # (IF_WIDTH) u2 (a, b, sum_if);

end

endgenerate

[3] generate-case

主要用来控制在哪种条件下生成哪个对象。case的每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:

generate

case (WIDTH)

1:

begin : case1_name

adder #(WIDTH*8) x1 (a, b, ci, sum_case, c0_case);

end

2:

begin : case2_name

adder #(WIDTH*4) x2 (a, b, ci, sum_case, c0_case);

end default:

begin : d_case_name

adder x3 (a, b, ci, sum_case, c0_case);

end

endcase

endgenerate

verilog部分基础语法

点击蓝字,关注我们

本文介绍仿真中testbench的编写,如果有错误的地方,欢迎指出,感谢。

简介

首先贴一个激励文件的图片先大致看一下:用来验证串口接收数据。testbench用来产生激励来验证电路的正确性,不需要可综合,以reg类型作为模块的输入激励,以wire型接收模块的输出。

01

仿真结果

1)可以直接看波形:使用仿真软件比如modelsim将电路逻辑的代码文件和激励文件加入工程进行编译和仿真即可。

2)将结果打印输出到控制台:比如$display(“%b”,a);是直接将结果输出到控制台,$mointor($time,”%b”,c);可以实时监控数据的变化。

02

系统任务

$display和$write均用来输出结果,区别在于$display输出后会自动换行,$write不会

$mointor和$strobe均可以用来输出和监控值,区别在于$strobe是在本时刻所有的赋值语句完成后才进行打印的,而$mointor会立刻在本时刻进行打印。

$time和$realtime均可返回当前的仿真的时刻,区别在于$time是以64位整数值的形式返回时间的,$realtime是以实数的形式返回的。

$finish和$stop均可用于对仿真的时间的控制,$finish会在执行到此时结束仿真,$stop会在执行到此时中断暂停仿真。

$random产生一个32位带符号的随机数,$random%a会得到在1-b~b-1范围内的整数。

03

延时语句

阻塞型和非阻塞型:阻塞型会从initial开始计时,然后依次延时,#4 a=1;非阻塞型是从initial开始各个延时同时开始,#4 a<=1;#5 b<=2;是在4单位长度时间后对a进行赋值,然后1个单位时间后对b进行赋值。

04

触发事件

边沿触发:@事件,事件包括posedge(上升沿),negedge(下降沿),信号(包括上升沿和下降沿)

电平触发:wait(信号在某个电平)执行操作。

05

任务和函数

任务:task 端口 begin end endtask在模块内进行定义,然后在模块中调用:任务名(端口),可以在多次重复同一个操作时调用任务减少代码量,但是任务里面不能出现initial和always过程块。

函数:function 位宽或者类型 函数名 输入信号 begin end endfunction

其中的类型有:integer:整数型 real:实数型 函数名相当于一个寄存器,在函数内部可以将返回值存到这个寄存器中,在调用时和任务的调用一样,区别在于任务只能用于过程块,函数可以用于过程块和赋值语句。

06

模块延时

模块延时:对模块从一个输入引脚到一个输出引脚的延时进行定义。

specify specparam定义常量 (输入端口=>输出端口)=延时时长 endspecify

specparam和parameter一样是用来定义的常量的,不同在于specaram是仅在模块延时中,parameter在外部。在specify中可以调用一些系统函数来检查时序是否正确,比如$setup(被检查的信号,参考的信号,规定的产生一次被检查信号所产生参考信号的最少数目)。

07

仿真时间标度

仿真时间标度:`timescale 单位/精度 比如截图中的表示#time中time是1ns的整数倍,且能够表示的最小时间单位是1ns。

英文翻译

Writing testbench

This article introduces the preparation of the testbench in the simulation. The author is also a beginner. If there are mistakes, please point out, thank you.

Introduction: The testbench is used to generate excitation to verify the correctness of the circuit. It does not need to be synthesizable. The reg type is used as the input excitation of the module, and the output of the module is received by the wire type.

First, paste a picture of the incentive file to take a general look: used to verify that the serial port receives data

Simulation results:

1) You can directly see the waveform: Use simulation software such as modelsim to add the code file and excitation file of the circuit logic to the project for compilation and simulation.

2) Print the result to the console: for example, $display("%b",a); directly outputs the result to the console, $mointor($time,"%b",c); can monitor the data in real time Variety.

System tasks:

Both $display and $write are used to output the result, the difference is that $display will automatically wrap after output, $write will not

Both $mointor and $strobe can be used to output and monitor values. The difference is that $strobe is printed after all assignment statements at this moment are completed, while $mointor will be printed immediately at this moment.

Both $time and $realtime can return the current simulation time, the difference is that $time returns the time in the form of a 64-bit integer value, and $realtime returns the time in the form of a real number.

Both $finish and $stop can be used to control the time of the simulation. $finish will end the simulation when it is executed, and $stop will interrupt the simulation when it is executed.

$random generates a 32-bit signed random number, $random%a will get an integer in the range 1-b~b-1.

Delay statement:

Blocking type and non-blocking type: The blocking type will start timing from the initial, and then delay in turn, #4 a=1; the non-blocking type will start each delay from the initial at the same time, #4 a<=1; #5 b< =2; is to assign a value to a after 4 units of time, and then assign a value to b after 1 unit of time.

Trigger event: edge trigger: @ event, events include posedge (rising edge), negedge (falling edge), signal (including rising edge and falling edge)

Level-triggered: wait (the signal is at a certain level) to perform an operation.

Tasks and functions:

Task: task port begin end endtask is defined in the module, and then called in the module: task name (port), the task can be called when the same operation is repeated many times to reduce the amount of code, but the initial and always process blocks cannot appear in the task .

Function: function bit width or type function name input signal begin end endfunction

The types are: integer: integer real: real function name is equivalent to a register, the return value can be stored in this register inside the function, and the call is the same as the call of the task, the difference is that the task can only be used for the process Blocks, functions can be used in procedural blocks and assignment statements.

Module Delay: Define the delay of the module from an input pin to an output pin.

specify specparam definition constant (input port => output port) = delay time endspecify

Specparam and parameter are used to define constants, the difference is that specaram is only in module delay, and parameter is external. Some system functions can be called in specify to check whether the timing is correct, such as $setup (checked signal, reference signal, the minimum number of reference signals generated by the specified generation of the checked signal at one time).

Simulation time scale: `timescale unit/precision For example, in the screenshot, time in #time is an integer multiple of 1ns, and the minimum time unit that can be represented is 1ns.

参考资料:《verilog数字系统设计教程》夏宇闻著

翻译:谷歌翻译

本文由Learning Yard新学苑原创,如有侵权,请联系沟通。

相关问答

verilog 模型分为哪几级?

veriloghdl是一种用于数字逻辑电路设计的语言。用veriloghdl描述的电路设计就是该电路的veriloghdl模型。veriloghdl既是一种行为描述的语言也是一种结构...

不同制程的芯片为什么需要重新设计?

但是,98%对于芯片制造来说依旧不够,仍需要进一步提升。因此,将再进一步采用西门子制程(Siemensprocess)作纯化,如此,将获得半导体制程所需的高纯度多晶硅...大...

什么工作会用到MATLAB编程?

鲁棒控制工具箱20ModelPredictiveControlToolbox模型预测控制工具箱21AerospaceToolbox航空航天工具箱图像处理与计算机视觉22Ima...

cadence和candence不同???-ZOL问答

CADENCE(Computer-aidedDesignandComputer-aidedEngineering)和CANDENCE的名称虽然相似,但它们在定义上存在明显差异。CADENCE...

全世界最强CPU-ZOL问答

英特尔XeonPlatinum8180,28核心56线程,主频2.5-3.8GHz,三级缓存38.5MB,内存支持六通道DDR4-2666ECC(最大768GB),热设计功耗205W,目前国内没...

vhdl ams有什么用

[回答]即IEEE1076.1标准。VHDL-AMS是VHDL的一个分支,它支持模拟、数字、数模混合电路系统的建模与仿真。http://www.eda.org/vhdl-ams/Verilog-...

在座的看官帮忙回一下!!东西湖好用的双开门集成水槽小红书...

[回答]字电路(闫石版比较好我们学的就...先明确是数字方向还是模拟方向,这两者相差还是蛮多的,不知道的你教育背景如何,从最基本的说起首先模电,数电这两...

 德阳五中  moto x 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2024  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部