Verilog笔记
assign:
assign
相当于连线,一般是将一个变量的值不间断地赋值给另一个变量,就像把这两个变量连在一起,所以习惯性的当做连线用,比如把一个模块的输出给另一个模块当输入。
对wire
型变量赋值,wire
是线网,相当于实际的连接线,如果要用assign
直接连接,就用wire
型变量。wire
型变量的值随时变化。
(1)在Verilog module
中的所有过程块(如initial
块和always
块)、连续赋值语句(如assign
语句)和实例引用都是并行的
。在同一module
中这三者出现的先后顺序没有关系
。
(2)只有连续赋值语句assign
和实例引用
语句可以独立于过程块
而存在于module
的功能定义部分。
(3)连续赋值assign
语句独立于过程块,所以不能在always
过程块中使用assign
语句。只有连续赋值语句assign
和实例引用语句
可以独立于过程块而存在于模块的功能定义部分
通过连续赋值语句描述3位加法器 module adder ( count,sum,a,b,cin ); input [2:0] a,b; input cin; output count; output [2:0] sum; assign {count,sum} = a + b + cin; endmodule
通过连续赋值语句描述一个比较器 module compare ( equal,a,b ); output equal; //声明输出信号equal input [1:0] a,b; //声明输入信号a,b assign equal =(a = = b)?1:0; /*如果a、b 两个输入信号相等,输出为1。否则为0*/ endmodule //版本2 module compare_2 ( equal,a,b ); output equal; //声明输出信号equal input [1:0] a,b; //声明输入信号a,b reg equal;// always @(a,b) if(a==b) equal=1; else equal=0; /*如果a、b 两个输入信号相等,输出为1。否则为0*/ endmodule //版本3 module compare_3 ( equal,a,b ); output equal; //声明输出信号equal input [1:0] a,b; //声明输入信号a,b reg equal;// always @(a,b) begin // if(a==b) equal=1; else equal=0; end // assign equal =(a = = b)?1:0; /*如果a、b 两个输入信号相等,输出为1。否则为0*/ endmodule
always:
always @(a)
表示如果a有变化就执行下面的语句
always @(sl or a or b)
表示只要sl
或a
或b
,其中若有一个变化时就执行下面的语句
Verilog程序包括4个主要部分:
- 端口定义
I/O
说明- 内部信号声明
- 功能定义
I/O说明的格式:
- 输入口
input[范围]
; - 输出口
output [范围]
; - 输入/输出口
inout [范围]
; I/O
说明也可以写在端口声明里。
内部信号说明:
reg[范围] 变量1,变量2…
;wire[范围] 变量1,变量2…
;
模块中实现逻辑功能的3种方法:
(1)assign
: assign c=a&b;
(2)用实例元件 :and #2 u1(q,a,b);
(3)用always
块
assign
语句是描述组合逻辑最常用的方法之一。always
块既可用于描述时序逻辑,又可用于组合逻辑。
D触发器:
module new_dff(q,clk,d); input clk,d; output q; reg q; always @(posedge clk) q<=d; endmodule
D触发器(带异步清除端)
module new_dff2(q,clk,d,clr); input clk,d,clr; output q; reg q; always @(posedge clk or posedge clr) begin if(clr) q<=0; else q<=d; end endmodule
D触发器(带异步清除端和使能端)
module new_dff3(q,clk,d,clr,en); output q; input clk,d,clr,en; reg q; always @(posedge clk or posedge clr) begin if(clr) q<=0; else if (en) q<=d; end endmodule
数据类型及其常量和变量:
4种逻辑值 : 0
1
z
(高阻) x
(不定值)
常量:在程序运行过程中,其值不能被改变的量称为常量。
整数:
- 二进制整数
b
或B
- 十进制整数
d
或D
- 八进制整数
o
或O
- 十六进制整数
h
或H
数字表达方式: <位宽>'<进制><数字>
,默认位宽是32bit
4'b1110 //4位二进制数 12'habc //12位十六进制数 16'd255 //16位十进制数
负数: 一个数字可以被定义为负数,只需在位宽表达式前加一个减号,减号必须写在数字定义表达式的最前面。
-8'd5 //这个表达式代表5的补数(用八位二进制数表示)
参数(Parameter
)型:
用parameter
来定义一个标识符 代表一个常量,称为符号常量
,即标识符形式的常量,采用标识符代表一个常量可提高程序的可读性和可维护性。是一种常数型的数据,其说明格式如下:
parameter 参数名1=表达式,参数名2=表达式, …, 参数名n=表达式;
parameter
是参数型数据的确认符,确认符后跟着一个用逗号分隔开的赋值语句表。在每一个赋值语句的右边必须是一个常数表达式。也就是说,该表达式只能包含数字或先前已定义过的参数。
parameter msb=7; //定义参数msb为常量7 parameter e=25, f=29; //定义二个常数参数 parameter r=5.7; //声明r为一个实型参数 parameter byte_size=8, byte_msb=byte_size-1; //用常数表达式赋值 parameter average_delay = (r+f)/2; //用常数表达式赋值
参数型常数经常用于定义延迟时间和变量宽度。在实例引用时可通过参数传递改变在被引用模块中已定义的参数
module two_delay(a,b,c,d); output c,d; input a,b; reg c,d; parameter delay1=2,delay2=2; always @(a) c<= #delay1 a; always @(b) d<=#delay2 b; endmodule //调用版本1 module top_delay(a1,b1,c1,d1); input a1,b1; output c1,d1; two_delay #(.delay1(5),.delay2(10)) u1(.a(a1),.b(b1),.c(c1),.d(d1)); endmodule //调用版本2 module top_delay2(a1,b1,c1,d1); input a1,b1; output c1,d1; two_delay #(5,10) u1(.a(a1),.b(b1),.c(c1),.d(d1)); endmodule //调用版本3 module top_delay3(a1,b1,c1,d1); input a1,b1; output c1,d1; two_delay #(.delay2(10)) u1(.a(a1),.b(b1),.c(c1),.d(d1)); endmodule //调用版本4 module top_delay4(a1,b1,c1,d1); input a1,b1; output c1,d1; two_delay #(10) u1(.a(a1),.b(b1),.c(c1),.d(d1)); //参数被传给了delay1 endmodule
变量:
wire变量: wire [n-1:0] 数据名1,数据名2,…数据名i; //共有i条总线,每条总线内有n条线路 wire [n:1] 数据名1,数据名2,…数据名i; wire a; //定义了一个一位的wire型数据 wire [7:0] b; //定义了一个八位的wire型数据 wire [4:1] c, d; //定义了二个四位的wire型数据 /////////////////////////////////////////////////////// reg是最常用的寄存器型数据。默认初始值是x: reg [n-1:0] 数据名1,数据名2,… 数据名i; reg [n:1] 数据名1,数据名2,… 数据名i; reg rega; //定义了一个一位的名为rega的reg型数据 reg [3:0] regb; //定义了一个四位的名为regb的reg型数据 reg [4:1] regc, regd; //定义了两个四位的名为regc和regd的reg型数据
运算符按其功能可分为以下几类:
1) 算术运算符(+,-,×,/,%)
2) 赋值运算符(=,<=)
3) 关系运算符(>,<,>=,<=)
4) 逻辑运算符(&&,||,!)
5) 条件运算符(?:)
6) 位运算符(~,|,^,&,^~)
7) 移位运算符(<<,>>)
8) 拼接运算符({ })
9) 其它
下面是Verilog HDL中使用的关键词:
always, and, assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive,endspecify, endtable, endtask, event, for, force, forever, fork, function,highz0,highz1, if,initial, inout, input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,notifl, or, output, parameter, pmos, posedge,primitive, pull0, pull1, pullup, pulldown, rcmos, reg, releses, repeat, mmos, rpmos,rtran, rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0, strong1,supply0, supply1, table, task, time, tran, tranif0, tranif1, tri, tri0, tri1, triand,trior, trireg,vectored,wait,wand,weak0,weak1,while, wire,wor, xnor, xor
块语句:
begin_end语句 通常用来标识顺序执行的语句,用它来标识的块称为顺序块
。
顺序块有以下特点:
(1) 块内的语句是按顺序执行的,即只有上面一条语句执行后下面的语句才能执行。 (2) 每条语句的延迟时间是相对于前一条语句的仿真时间而言的。 (3) 直到最后一条语句执行完,程序流程控制才跳出该语句块。
块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句。
module ex4_5; parameter d=50; reg[7:0] r; reg[3:0] a; event end_wave; always @(end_wave) a=4'hf; initial begin a=4'h2; end initial begin #d r='h35; #d r='hE2; #d r='h00; #d r='hF7; #d ->end_wave; end endmodule
逻辑判断:
module counter10b(q,clk,clr); output[3:0] q; input clk,clr; reg[3:0] q=4'b0000;//ModelSim仿真用,QuartusII不用初值 always @(posedge clk or posedge clr) begin if(clr) q<=4'b0000; else begin if (q==4'b1001) q<=4'b0000; else q<=q+1'b1; end end endmodule
case语句:
case语句是一种多分支选择语句,if语句只有两个分支可供选择,而实际问题中常常需要用到多分支选择,Verilog语言提供的case语句直接处理多分支选择。
case语句的所有表达式的值的位宽必须相等,只有这样控制表达式和分支表达式才能进行对应位的比较。一个经常犯的错误是用’bx, ‘bz 来替代 n’bx, n’bz,这样写是不对的,因为信号x, z的缺省宽度是机器的字节宽度,通常是32位(此处 n 是case控制表达式的位宽)
module test_case; reg[1:0] select; initial begin select=2'b01; case (select) 2'b01:$display("second 2b01..."); 2'b01:$display("third 2b01..."); 2'b01,2'b00:$display("2b01"); 2'b11:$display("2b11"); default:$display("default..."); endcase end endmodule
initial
和 always
说明语句在仿真的一开始即开始执行。
initial
语句只执行一次。相反,always
语句则是不断地重复执行,直到仿真过程结束。
always
语句后面跟着的过程块是否运行,则要看它的触发条件是否满足,如满足则运行过程块一次,再次满足再运行一次,直至仿真过程结束。
在一个模块中,使用initial
和 always
语句的次数是不受限制的。
task
和function
语句可以在程序模块中的一处或多处调用。
@*
和 @(*)
,它们都表示对其后面语句块中所有输入变量的变化时敏感的。
版权声明:《 Verilog硬件编程基础语法笔记 》为DYBOY原创文章,转载请注明出处!
最后编辑:2018-11-17 10:11:06