单线
创建一个具有一个输入和一个输出的模块,其行为类似于导线。
与物理导线不同,Verilog中的导线(和其他信号)是有方向的。这意味着信息只能从一个方向流动,即从(通常是一个)源到汇(源也常被称为将值驱动到导线上的驱动器)。在Verilog的“连续赋值”(assign left_side = right_side;)中,右侧信号的值被驱动到左侧的导线上。该赋值是“连续的”,因为即使右侧的值发生变化,赋值也会一直持续。连续赋值不是一个一次性事件。
模块上的端口也有方向(通常是输入或输出)。输入端口由模块外部的东西驱动,而输出端口则驱动外部的东西。从模块内部来看,输入端口是驱动器或源,而输出端口是汇。
下面的图表说明了电路的每个部分如何与Verilog代码的每个位相对应。模块和端口声明创建了电路的黑色部分。你的任务是通过添加一个assign语句来创建一条导线(绿色),以将输入连接到输出。方框外的部分与你无关,但你应该知道,你的电路是通过将我们测试工具中的信号连接到你的顶级模块(top_module)的端口上来进行测试的。
除了连续赋值外,Verilog还有三种在过程块中使用的赋值类型,其中两种是可综合的。在我们开始使用过程块之前,我们不会使用它们。
在Verilog中,过程块(Procedural Block)是指用于描述硬件时序电路和组合电路行为的代码块。这些过程块主要通过always和initial关键字来定义,它们允许在仿真过程中按照特定的时序或条件执行一系列的语句。
module top_module( input in, output out ); assign out = in; endmodule
四线
创建一个具有3个输入和4个输出的模块,其行为类似于导线,并实现以下连接:
a -> w
b -> x
b -> y
c -> z
下面的图表说明了电路的每个部分如何与Verilog代码的每个位相对应。从模块外部看,有三个输入端口和四个输出端口。
当你有多个assign语句时,它们在代码中出现的顺序并不重要。与编程语言不同,assign语句(“连续赋值”)描述的是事物之间的连接,而不是将一个值从一个事物复制到另一个事物的动作。
现在可能需要澄清的一个潜在混淆点:这里的绿色箭头代表导线之间的连接,但它们本身并不是导线。模块本身已经声明了7条导线(分别命名为a、b、c、w、x、y和z)。这是因为除非另有说明,否则输入和输出声明实际上会声明一条导线。编写input wire a
与编写input a
是等效的。因此,assign语句并没有创建导线,而是创建了已经存在的7条导线之间的连接。
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
非门
创建一个实现非门(NOT gate)的模块。
这个电路类似于导线,但有一个细微的差别。在从输入导线到输出导线的连接中,我们将实现一个反相器(或“非门”),而不是简单的导线。
使用assign
语句。assign
语句将连续地将in
的取反结果驱动到out
导线上。
module top_module( input in, output out ); // 使用assign语句实现非门逻辑 assign out = ~in; // 如果in为1,out为0;如果in为0,out为1 endmodule
与门
创建一个实现与门(AND gate)的模块。
这个电路现在有三条导线(a、b和out)。导线a和b已经通过输入端口被赋予了值。但是,导线out目前没有被任何东西驱动。编写一个assign
语句,使out输出a和b信号的与操作结果。
请注意,这个电路与非门非常相似,只是多了一个输入。如果你感觉它们有所不同,那是因为我开始描述信号是被驱动的(由连接到它的某个东西确定了一个已知的值)还是未被驱动的。输入导线是由模块外部的东西驱动的。assign
语句将逻辑电平驱动到导线上。
正如你可能预期的那样,一条导线不能有多个驱动器(如果有多个,它的逻辑电平是什么?),而没有驱动器的导线将具有未定义的值(在合成硬件时通常被视为0)。
module top_module( input a, input b, output out ); assign out = a & b; endmodule
或非门(NOR gate)
创建一个实现或非门(NOR gate)的模块。或非门是一个输出被取反的或门。在Verilog中编写NOR函数时,需要两个操作符。
assign
语句用于将一个值驱动到导线(或更正式地称为“网络”)上。这个值可以是你想要的任何复杂函数,只要它是一个组合逻辑(即无记忆功能,没有隐藏状态)函数。assign
语句是一个连续赋值,因为每当任何输入发生变化时,输出就会“重新计算”,这种计算是永无止境的,类似于一个简单的逻辑门。
module top_module( input a, input b, output out ); assign out = ~(a|b); endmodule
异或非门(XNOR gate)
创建一个实现异或非门(XNOR gate)的模块。
module top_module( input a, input b, output out ); // 使用assign语句实现异或非门逻辑 // 输出out是输入a和b的异或操作的取反,即当a和b相同时,out为1;当a和b不同时,out为0 assign out = ~(a ^ b); endmodule
Wire 声明
声明导线
到目前为止,电路已经足够简单,输出仅仅是输入的简单函数。
随着电路变得更加复杂,你将需要导线来连接内部组件。
当你需要使用导线时,你应该在模块的主体中声明它,在首次使用它之前的某个位置。
(在将来,你会遇到更多类型的信号和变量,它们也以相同的方式声明,但现在,我们将从类型为导线的信号开始。)
module top_module ( input in, // Declare an input wire named "in" output out // Declare an output wire named "out" ); wire not_in; // Declare a wire named "not_in" assign out = ~not_in; // Assign a value to out (create a NOT gate). assign not_in = ~in; // Assign a value to not_in (create another NOT gate). endmodule // End of module "top_module"
在上述模块中,有三个导线(in、out和not_in),其中两个已经作为模块的输入和输出端口的一部分进行了声明(这就是为什么你在之前的练习中不需要声明任何导线的原因)。
导线not_in需要在模块内部进行声明。它在模块外部是不可见的。
然后,使用两个assign
语句创建了两个非门。
注意,你先创建哪个非门并不重要:你最终会得到相同的电路。
练习
实现以下电路。创建两个中间导线(命名随意)来连接与门(AND gate)和或门(OR gate)。
请注意,供给非门(NOT gate)的导线实际上就是输出导线(out),所以你并不一定要在这里声明第三条导线。
请注意,导线正是由一个源(门的输出)驱动的,但可以供给多个输入。
如果你按照图中的电路结构来,你应该会用到四个assign
语句,因为有四个信号需要赋值。
(是的,不使用中间导线也可以创建一个具有相同功能的电路。)
`default_nettype none module top_module( input a, input b, input c, input d, output out, output out_n ); wire out_1, out_2; assign out_n = ~out; assign out = out_1 | out_2; assign out_1 = a & b; assign out_2 = c & d; endmodule
7458
7458 是一个包含四个与门和两个或门的芯片。这个问题比 7420 稍微复杂一些。
创建一个与 7458 芯片功能相同的模块。它有 10 个输入和 2 个输出。你可以选择使用 assign
语句来驱动每个输出导线,或者选择声明(四个)导线作为中间信号使用,其中每条内部导线都由一个与门的输出驱动。
为了额外练习,你可以尝试两种方法。
one
module top_module ( input p1a, p1b, p1c, p1d, p1e, p1f, output p1y, input p2a, p2b, p2c, p2d, output p2y ); assign p1y = (p1a & p1b & p1c) | (p1d & p1e & p1f); assign p2y = (p2a & p2b) | (p2c & p2d); endmodule
two
module top_module ( input p1a, p1b, p1c, p1d, p1e, p1f, output p1y, input p2a, p2b, p2c, p2d, output p2y ); wire a,b,c,d; assign a = (p1a & p1b & p1c); assign b = (p1d & p1e & p1f); assign c = (p2a & p2b); assign d = (p2c & p2d); assign p1y = a | b; assign p2y = c | d; endmodule
内容来自:https://hdlbits.01xz.net/wiki/7458