HDLBits_Verilog学习笔记Ⅰ——Verilog Language_Basics
谢谢谢同学鸭
编辑于 2021年11月01日 03:37
收录于文集
共5篇

本专栏集是基于HDLBits上的Verilog练习题的分析与总结,上篇地址:


  • 注:可以搭配上述视频食用,先做题再看答案,网址:https://hdlbits.01xz.net/


ps:B站还不支持Verilog代码,所以就随便选了一个,本来高亮的应该是module input output  wire assign等。


2. Simple wire

小知识点:与现实中的导线不同,Verilog中的wire是一种信号,和其余信号一样,它是有方向性的。其承载的信息值只向一个方向流动,通常从一个source流向一个或多个sinks(source“源”也常被称为driver“驱动”,它将某个值驱动至导线上)。在Verilog中,“连续赋值”(assign left_side = right_side; )将wire信号right_side的值驱动至左边的wire信号left_side。由于赋值是“连续的”(即连了一根导线),所以right_side的任何变化都会立即在left_side中体现出来。这与软件的赋值不同,连续赋值不是一次性事件。

       模块上的端口也有方向性(通常是inputoutput)。输入端口由模块外的信号驱动,而输出端口驱动模块外的信号。从模块内部看时,输入端口是驱动或源,而输出端口是接收器。

浅出:assign left = right; 在现实中就是用一根导线(wire)将两个引脚连起来,电信号从right流向left,所以Verilog里就把right和left定义为wire类型的信号(此外还有reg等),其中right是源或驱动,left是被驱动的sink。


Practice: Create a module with one input and one output that behaves like a wire.

大白话:搞一个极简单的电路模块,它有两个端口,一进一出,Verilog中对应两个wire类型的信号,in是source,out是sink,通过assign语句把这两wire信号用一根导线wire连起来。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( input in, output out );

	assign out = in;
    
endmodule
复制成功

BB两句:你可能会有疑惑,上面的代码也没体现出wire信号啊。这是因为Verilog在定义input和output时可以省略wire,即相当于(input wire in, output wire out),以后还会接触到output reg out等。


3. Four wires

小知识点:这道题需要用到不止一条assign语句,而Verilog中的多条assign语句间的顺序是不会影响结果的(大部分Verilog代码都是这样),这与按顺序执行的软件代码不同,Verilog是并行的。

       另外再重申一遍,图中的绿线是两个wire信号之间的连接,在现实中它可以是一根导线(英语单词wire),但在Verilog中的wire表示的是某一种类型的信号。

浅出:可综合的Verilog代码本质上是在描述现实中的硬件电路,电路中的导线或器件先连后连基本没有区别,硬件系统中的模块也都是相互独立且并行运行的,所以用来描述硬件结构的Verilog也具有并行性(always和initial行为语句块内部的begin...end顺序语句组是顺序执行的,这个后面会细讲)。


Practice: Create a module with 3 inputs and 4 outputs that behaves like wires that makes these connections: a->w,b->x,b->y,c->z.

大白话:用assign语句连线呗,得注意谁驱动谁。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( 
	input a,b,c,
	output w,x,y,z );

	assign w = a;
	assign x = b;
	assign y = b;
	assign z = c;

endmodule
复制成功

 BB两句:上题有提到source通常只有一个,而sinks可以有多个,比如这题的x和y就同时被b驱动。Why?因为一个wire信号不能被多个信号同时驱动,假设x同时连了a和b,如果a来了个高电平,b来了个低电平,那x是高还是低呢。又如果一个wire信号没有其他信号驱动它,此时综合器会将其默认为0。


4. Inverter

小知识点:Verilog中有两种取反,逻辑取反 ! 和按位取反 ~ ,前者只能用于一位的信号,即!1=0, !0=1,在电路中对应一个反相器;后者还可用于多位宽的信号,如~101=010。


Practice: Create a module that implements a NOT gate.

大白话:搞一个非门(反相器)。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( input in, output out );

	assign out = !in;	//也可以用~

endmodule
复制成功

5. And gate

小知识点:也分两种,按位与 & 和逻辑与 && 。

浅出:按位与很简单,就是一位一位地与运算过去,最后产生的输出肯定也是n位的(例如 1011 & 0110 = 0010)。而逻辑与就是把所有位作为一个整体,只有每一位都为0(整体等于零),它才可记成一位的“0”,不然它整体就不等于零,也就记“1”,最后的输出也仅剩1位(例如 10 && 11=1,10 && 00=0)。这个在下一篇的13题还会细讲。


Practice: Create a module that implements an AND gate.

大白话:建一个与门。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( 
	input a, 
	input b, 
	output out );

	assign out = a && b;	//或用&

endmodule
复制成功


6. NOR gate

小知识点:也分两种,按位或 | 和逻辑或 || ,类似上题的与。


Practice: Create a module that implements a NOR gate. A NOR gate is an OR gate with its output inverted. A NOR function needs two operators when written in Verilog.

大白话:或非门包括或门和非门。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( 
    input a, 
    input b, 
    output out );

    assign out = ~ (a | b);

endmodule
复制成功

7. XNOR gate

小知识点:异或只有按位异或 ^ ,没有逻辑异或,另外还有个同或运算符 ^~。


Practice: Create a module that implements an XNOR gate.

大白话:XNOR表示同或,XOR是异或。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
module top_module( 
    input a, 
    input b, 
    output out );

    assign out = ~ (a ^ b);
	// 或assign out = a ^~ b;

endmodule
复制成功

BB两句:同或就是异或的非。


8. Declaring wires

小知识点:前面我们对wire信号blabla地讲了一大堆,但是貌似并没有用到过它(input和output除外),那是因为前面的电路太简单了。这次我们就要在模块内定义wire类型的信号,来描述更复杂一丢丢的电路。格式如下 👇

代码块
C++
自动换行
复制代码
	wire your_signal_1, your_signal_2;
复制成功


Practice: Implement the following circuit. Create two ... 

大白话:实现下面的电路,创建两个中间信号把与门和或门连起来。非门的输入信号已经存在(就是out),所以没必要定义第三个中间信号。另外不要忘了上面反复强调的一个wire信号只能由一个信号驱动,但能驱动多个其它信号。

转自HDLBits

答案(先做再看哦,且不唯一,仅供参考):

代码块
C++
自动换行
复制代码
`default_nettype none
module top_module (
	input a,
	input b,
	input c,
	input d,
	output out,
	output out_n );
	
	wire and1, and2;		// wire信号声明时也可直接赋值,这样就能少写一句

	assign and1 = a & b;	// 省略上一句后,可改成 wire and1 = a & b;
	assign and2 = c & d;	// 省略上一句后,可改成 wire and2 = c & d;

	assign out = and1 | and2;	
	assign out_n = ~out;	
	
endmodule
复制成功

BB两句:`default_nettype none是一个宏定义,下一篇的11题会讲到。可以在定义wire信号的时候直接赋值(如wire and1 = a & b;),Verilog也支持这种语法。


9. 7458 chip

Practice: Create a module with the same functionality as the 7458 chip.

大白话:写一块7458芯片模块,如图所示。

转自HDLBits

答案(方法一,使用中间信号):

代码块
C++
自动换行
复制代码
module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    
    wire and_1abc, and_1def, and_2ab, and_2cd;
    
	assign and_1abc = p1a & p1b & p1c;
    assign and_1def = p1d & p1e & p1f;
    assign and_2ab = p2a & p2b;
    assign and_2cd = p2c & p2d;
    assign p1y = and_1abc | and_1def;
    assign p2y = and_2ab | and_2cd;
    
endmodule
复制成功

 (方法二,不用中间信号,直接assign):

代码块
C++
自动换行
复制代码
    assign p1y = (p1a & p1b & p1c) | (p1d & p1e & p1f);
    assign p2y = (p2a & p2b) | (p2d & p2c);
复制成功


重点:①信号的声明:类型 信号名1, 信号名2, ..., 信号名n;

          ②assign语句的格式:assign left_side = right_side;

          ③assign连续赋值语句中wire信号的驱动关系与规则;

          ④Verilog中的常用逻辑运算符(布尔操作符):

             (按位)非~,与&,或|,异或^;(逻辑)非,与&&,或||