Verilog初级教程(14)Verilog中的赋值语句

举报
李锐博恩 发表于 2021/07/14 23:36:20 2021/07/14
【摘要】 文章目录 前言正文合理的左值过程性赋值(Procedural assignment)连续赋值过程连续性赋值 往期回顾 前言 何为赋值语句?即将值放到线网或者变量上,这种操作称为赋值,英文:assignment. 它有三种基本形式: 过程性赋值连续赋值过程连续赋值 正文 合理的左值 一个赋值语句有两个部分–右值(RHS)和左值(LHS),中间有...

前言

何为赋值语句?即将值放到线网或者变量上,这种操作称为赋值,英文:assignment.
它有三种基本形式:

  • 过程性赋值
  • 连续赋值
  • 过程连续赋值

正文

合理的左值

一个赋值语句有两个部分–右值(RHS)和左值(LHS),中间有一个相等的符号(=)或一个小于相等的符号(<=)。
下一节博文将看到,=为阻塞赋值,<=为非阻塞赋值。

在过程性赋值中,合理的左值应该是:

  • 变量(矢量/标量)
  • 向量reg、integer或time变量的位选择部分选择
  • 存储器(Memory word)
  • 上述任何一项的合并

过程赋值通常发生在块语句中,例如initial块,always块,还有task以及function中。

连续性赋值中,合理的左值应该为:

  • 线网(矢量/标量)
  • 矢量线网的位选择或部分选择。
  • 位选择和部分选择的合并

连续性赋值通常发生在assign中。

过程连续性赋值:

  • 线网或者变量(向量/标量)
  • 线网向量的位选择或者部分选择

RHS可以包含任何计算为最终值的表达式,而LHS表示一个线网或一个变量,RHS中的值被赋值给它。
例如:

module tb;
	reg clk;
	reg a, b, c, d, e;
	wire f, y;
	reg  z;

	// clk is on the LHS and the not of clk forms RHS
	always #10 clk = ~clk;

	// y is the LHS and the constant 1 is RHS
	assign y = 1;

	// f is the LHS, and the expression of a,b,d,e forms the RHS
	assign f = (a | b) ^ (d & e);

	always @ (posedge clk) begin
		// z is the LHS, and the expression of a,b,c,d forms the RHS
		z <= a + b + c + d;
	end

	initial begin
		// Variable names on the left form LHS while 0 is RHS
		a <= 0; b <= 0; c <= 0; d <= 0; e <= 0;
		clk <= 0;
	end
endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

过程性赋值(Procedural assignment)

过程性赋值发生在过程(procedures)中,如always、initial、task和函数中,用于将值放到变量上。变量将保持该值,直到下一次对同一变量的赋值。

当仿真在仿真时间内的某一时刻执行该语句时,该值将被放到变量上。这可以通过使用控制流语句,如if-else-if、case语句和循环机制来控制和修改我们想要的方式。

reg [7:0]  data;
integer count;
real period;

initial begin
	data = 8'h3e;
	period = 4.23;
	count = 0;
end

always @ (posedge clk)
	count <= count + 1;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

变量声明赋值

一个初始值可以在变量声明时被放置到变量上,如下图所示。这个赋值没有持续时间,并且在下一次对同一变量的赋值发生之前保持这个值。

注意,不允许将变量声明赋值用给数组。

module my_block;
	reg [31:0] data = 32'hdead_cafe;

	initial begin
		#20  data = 32'h1234_5678; // data will have dead_cafe from time 0 to time 20 // At time 20, data will get 12345678
	end
endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
reg [3:0] a = 4'b4;

// is equivalent to

reg [3:0] a;
initial a = 4'b4;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果变量在声明过程中和initial块中的时间0被初始化,如下例所示,则不保证赋值顺序,因此变量值可以有8’h05或8’hee。

module my_block;
	reg [7:0]  addr = 8'h05;

	initial
		addr = 8'hee;
endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这种方式是不推荐的,正常人是不会这么做的。

reg [3:0] array [3:0] = 0; // illegal
integer i = 0, j; // declares two integers i,j and i is assigned 0
real r2 = 4.5, r3 = 8; // declares two real numbers r2,r3 and are assigned 4.5, 8 resp.
time startTime = 40; // declares time variable with initial value 40

  
 
  • 1
  • 2
  • 3
  • 4

连续赋值

这用于将值分配到标量线网和矢量线网上,只要RHS发生变化就会发生。它提供了一种不需要指定门的互连就能建立组合逻辑模型的方法,并使其更容易用逻辑表达式来驱动线网。

// Example model of an AND gate
wire  a, b, c;

assign a = b & c;

  
 
  • 1
  • 2
  • 3
  • 4

每当b或c的值发生变化时,RHS中的整个表达式将被计算,a将被更新为新的值。

注意:我们仍然可以在线网声明的时候进行连续赋值,例如:

wire  penable = 1;

  
 
  • 1

但我们必须谨慎使用,因为一个网只能声明一次,所以一个网只能有一次声明赋值。

也就是说,一旦我们在声明wire变量的时候进行了连续赋值,后面则不能再次连续赋值,否则就是多驱动。

过程连续性赋值

这种赋值类型貌似很少听过,但却是存在。
有两种类型:

  • assign ... deassign
  • force ... release

assign … deassign

这将覆盖变量的所有过程性赋值,并通过使用与deassign相同的信号来停用。变量的值将保持不变,直到变量通过过程化或过程化连续赋值获得新的值。赋值语句的LHS不能是位选择、部分选择或数组引用,但可以是一个变量或变量的连接。

reg q;

initial begin
	assign q = 0;
	#10 deassign q;
end

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

为了测试,我仿真了一下,仿真文件:

module assign_tb();

reg q;

initial begin assign q = 0; #10 deassign q; #10 q = 1; #10 $finish; end

endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

按照语法描述,应该是前20ns都保持为assign赋值0,之后为1;
assign deassign

仿真结果显示也为如此。

force…release

这些语句与assign… deassign语句类似,但也可以应用于网和变量。LHS可以是网的位选择、网的部分选择、变量或网,但不能是数组的引用和变量的位/部分选择。force语句将覆盖所有其他对变量的赋值,直到使用释放关键字释放它。

reg o, a, b;

initial begin
	force o = a & b;
	...
	release o;
end

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

为了测试,我们设计如下仿真文件:

`timescale 1ns / 1ps
//
// Engineer:reborn lee
// Create Date: 2020/07/18 17:36:02
// Module Name: assign_tb
//

module assign_tb();

reg o, a = 1, b = 1;

initial begin force o = a & b; #10 a = 0; b = 0; o = 1; #10 a = 1; b = 1; o = 0; #20 release o; #10 a = 1; b = 1; o = 0; #10 a = 0; b = 1; o = 1; #10 $finish; end

endmodule


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

现在对这段简单的测试程序进行分析:
在一开始的时候,由于a和b的初始值都为1,又:

  force o = a & b;

  
 
  • 1

因此,o的值为1;
经过10ns,a和b的值被赋值为0,因此o应该为0,但是此刻:

// force o = a & b; #10 a = 0; b = 0; o = 1;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

我们尝试将o拉高;
同样在过10ns:

//initial begin //  force o = a & b; //#10 a = 0; //b = 0; //o = 1; #10 a = 1; b = 1; o = 0;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们再次尝试将o拉低;
从如下仿真图中可以看出均为成功。
release之前
这说明,在release之前,对变量o的所有操作都被忽视了。

继续看,在release之后,我们对o的操作都是成功的:

release之后

往期回顾

Verilog初级教程(13)Verilog中的块语句

Verilog初级教程(12)Verilog中的generate块

Verilog初级教程(11)Verilog中的initial块

Verilog初级教程(10)Verilog的always块

Verilog初级教程(9)Verilog的运算符

Verilog初级教程(8)Verilog中的assign语句

Verilog初级教程(7)Verilog模块例化以及悬空端口的处理

Verilog初级教程(6)Verilog模块与端口

Verilog初级教程(5)Verilog中的多维数组和存储器

Verilog初级教程(4)Verilog中的标量与向量

Verilog初级教程(3)Verilog 数据类型

Verilog初级教程(2)Verilog HDL的初级语法

Verilog初级教程(1)认识 Verilog HDL

芯片设计抽象层及其设计风格

Verilog以及VHDL所倡导的的代码准则

FPGA/ASIC初学者应该学习Verilog还是VHDL?

  • 个人微信公众号: FPGA LAB

交个朋友

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/107431511

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。