HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道

目录

1 GettingStarted(开始)

1.1 GettingStarted(开始)

1.2 OutputZero(输出零点 )

 2 Verilog Language(开始)

2.1 Basics 

2.1.1 Simple wire (简单电线)

2.1.2 Four wires (四线)

2.1.3 Inverter  (逆变器)

2.1.4 AND gate  (和门)

 2.1.5 NOR gate  (或非门)

 2.1.6 XNOR gate  (异或非门)

2.1.7 Declaring wires(声明导线)

2.1.8 7458 chip( 7458芯片)  

 2.2 Vectors(矢量)

 2.2.1 Vectors(矢量) 

2.2.2 Vectors in more detail(更详细的矢量) 

2.2.3 Vector part select(矢量部分选择) 

2.2.4 Bitwise operators(按位运算符) 

2.2.5 Four-input gates(四输入门) 

2.2.6 Vector concatenation operator(矢量串联运算符) 

2.2.7 Vector reversal1(矢量反转) 

2.2.8 Repliction operator(复制操作员) 

2.2.9 More replication(更多复制) 

​​​2.3  Modules: Hierarchy(模块:层次结构)

 2.3.1 Modules(模块)

2.3.2 Connecting ports by position(按位置连接端口)

2.3.3 Connecting ports by name(按名称连接端口)

2.3.4 Three modules(三个模块)

2.3.5 Module and vectors(模块和矢量)

2.3.6 Adder1(加法器 1)

2.3.7 Adder2(加法器 2)

2.3.8 Carry-select adder(携带选择加法器)

2.3.9 Adder-subtractor(加法器减法器


1 GettingStarted(开始)

1.1 GettingStarted(开始)

问题描述 

构建一个没有输入和一个输出的电路。该输出应始终驱动 1(或逻辑高电平)。 

verilog代码

module top_module( output one );

// Insert your code here
    assign one = 1'b1;

endmodule

1.2 OutputZero(输出零点 )

问题描述

构建一个没有输入的电路和一个输出的电路,输出一个常数0

verilog代码

module top_module(
    output zero
);// Module body starts after semicolon
    assign zero = 1'b0;
endmodule

 2 Verilog Language(开始)

2.1 Basics 

2.1.1 Simple wire (简单电线)

 问题描述

创建一个具有一个输入和一个输出的模块,其行为类似于电线。

与物理导线不同,Verilog 中的导线(和其他信号)是定向的。这意味着信息只在一个方向上流动,从(通常是一个)接收器(该源通常也称为将值驱动到导线上的驱动程序)。在Verilog"连续赋值"(assign left_side = right_side;)中,右侧信号的值被驱动到左侧的导线上。分配是"连续的",因为即使右侧的值发生变化,分配也会一直继续。连续分配不是一次性事件。assign left_side = right_side;

模块上的端口也有一个方向(通常是输入或输出)。输入端口由模块外部的东西驱动,而输出端口则驱动外部的东西。从模块内部查看时,输入端口是驱动器或源,而输出端口是接收器。

下图说明了电路的每个部分如何对应于Verilog代码的每个位。模块和端口声明创建电路的黑色部分。您的任务是通过添加要连接到 的语句来创建一条线路(绿色)。开箱即用的部件不是您关心的问题,但您应该知道,通过将测试线束的信号连接到顶部_模块的端口,可以测试您的电路。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第1张图片

verilog代码

module top_module( input in, output out );
    assign out = in;
endmodule

2.1.2 Four wires (四线)

 问题描述

创建一个具有 3 个输入和 4 个输出的模块,其行为类似于建立这些连接的电线:

a -> w
b -> x
b -> y
c -> z

下图说明了电路的每个部分如何对应于Verilog代码的每个位。从模块外部,有三个输入端口和四个输出端口。当您有多个赋值语句时,它们在代码中的显示顺序无关紧要。与编程语言不同,赋值语句("连续赋值")描述事物之间的连接,而不是将值从一个事物复制到另一个事物的操作。现在也许应该澄清的一个潜在的混淆来源是:这里的绿色箭头代表电线之间的连接,但本身不是电线。模块本身已经声明了 7 条导线(命名为 a、b、c、w、x、y 和 z)。这是因为,除非另有说明,否则声明实际上声明了一条线。写 input wire a 写 input a 是一样的.。因此,这些语句不是在创建导线,而是在已经存在的 7 根导线之间创建连接。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第2张图片

  verilog代码 

module top_module( 
    input a,b,c,
    output w,x,y,z );
    assign w = a;
    assign x = b,y = b;
    assign z = c;
    //如果我们确定每个信号的宽度,使用
    //串联运算符等效且更短:
    //assign {w,x,y,z}={a,b,b,c};
endmodule

2.1.3 Inverter  (逆变器)

 问题描述

创建一个实现 NOT 门的模块。该电路类似于线,但略有不同。当从电线连接到电线时,我们将实现逆变器(或"非门")而不是普通电线。使用assign语句。assign语句将持续将in的非转换为out。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第3张图片

verilog代码

module top_module( input in, output out );
    assign out = ~in;
endmodule

2.1.4 AND gate  (和门)

 问题描述

创建实现 AND 门的模块。

该电路现在有三条导线(a、b和out)。导线a和b已经具有由输入端口驱动的值。但wire out目前并不是由任何因素驱动的。写一个assign语句,用a和b的AND信号输出。

请注意,该电路与NOT门非常相似,只是多了一个输入。如果听起来不一样,那是因为我已经开始描述信号是被驱动的(已知值由附加到它的某个东西决定)还是不是被某个东西驱动的。输入线由模块外部的东西驱动。assign语句将把一个逻辑电平驱动到一条线上。正如您所料,一条导线不能有多个驱动器(如果有,其逻辑级别是多少?),没有驱动程序的导线将有一个未定义的值(在合成硬件时通常被视为0)。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第4张图片

verilog代码

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = a & b;
endmodule

 2.1.5 NOR gate  (或非门)

 问题描述

创建一个实现或非门的模块。或非门是输出反转的或门。在Verilog中编写NOR函数时需要两个运算符。

assign语句用一个值驱动一条线(或者更正式地称为“网”)。该值可以是任意复杂的函数,只要它是组合函数(即无内存、无隐藏状态)。assign语句是一种连续赋值,因为每当其任何输入发生变化时,都会“重新计算”输出,就像一个简单的逻辑门一样。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第5张图片

verilog代码

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = ~(a | b);
endmodule

 2.1.6 XNOR gate  (异或非门)

 问题描述

创建一个实现 XNOR 门的模块。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第6张图片

 verilog代码

module top_module( 
    input a, 
    input b, 
    output out );
    //assign out = a ~^ b;a和b相同输出0,不同输出1
    //assign out = a ^~ b;
    assign out = ~(a ^ b);
endmodule

2.1.7 Declaring wires(声明导线)

问题描述 

执行以下电路。创建两条中间导线(可以任意命名)将与门连接在一起。请注意,为NOT gate馈电的导线实际上是wire out,因此不一定需要在此处声明第三条导线。请注意,导线是如何由一个源(门的输出)驱动的,但可以提供多个输入。

如果你遵循图表中的电路结构,你应该得到四个assign语句,因为有四个信号需要赋值。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第7张图片

verilog代码

module top_module (
	input a,
	input b,
	input c,
	input d,
	output out,
	output out_n );
	
	wire w1, w2;		// Declare two wires (named w1 and w2)
	assign w1 = a&b;	// First AND gate
	assign w2 = c&d;	// Second AND gate
	assign out = w1|w2;	// OR gate: Feeds both 'out' and the NOT gate

	assign out_n = ~out;	// NOT gate
	
endmodule

2.1.8 7458 chip( 7458芯片)  

问题描述 

7458是一款带有四个“与”门和两个“或”门的芯片。这个问题比7420稍微复杂一些。

创建一个功能与7458芯片相同的模块。它有10个输入和2个输出。您可以选择使用assign语句来驱动每条输出线,也可以选择声明(四)条线用作中间信号,其中每条内部线由一个AND门的输出驱动。如果想进行额外的练习,可以尝试两种方法。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第8张图片

verilog代码

module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    //第一种方法
    assign p2y = (p2a & p2b) | (p2c & p2d);
    assign p1y = (p1a & p1c & p1b) | (p1f & p1e & p1d);
    //第二种方法
    wire a,b,c,d;
    assign a = p2a & p2b;
    assign b = p2c & p2d;
    assign p2y = a | b;
    assign c = p1a & p1c & p1b;
    assign d = p1f & p1e & p1d;
    assign p1y = c | d;
endmodule

 2.2 Vectors(矢量)

 2.2.1 Vectors(矢量) 

 问题描述

向量用于使用一个名称对相关信号进行分组,以便于操作。例如,导线[7:0]w;声明一个名为w的8位向量,该向量在功能上相当于有8条独立的导线。

请注意,向量的声明将维度放在向量名称之前,这与C语法相比是不寻常的。但是,零件选择的尺寸标注位于向量名称之后,正如您所期望的那样。

构建一个具有一个3位输入的电路,然后输出相同的矢量,并将其拆分为三个单独的1位输出。将输出o0连接到输入向量的位置0,将o1连接到位置1,等等。

在图表中,旁边带有数字的记号表示向量(或“总线”)的宽度,而不是为向量中的每一位画一条单独的线。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第9张图片

 verilog代码

module top_module(
	input [2:0] vec, 
	output [2:0] outv,
	output o2,
	output o1,
	output o0
);
	
	assign outv = vec;

	// This is ok too: assign {o2, o1, o0} = vec;
	assign o0 = vec[0];
	assign o1 = vec[1];
	assign o2 = vec[2];
	
endmodule

2.2.2 Vectors in more detail(更详细的矢量) 

 问题描述

构建一个组合电路,将输入半字(16位[15:0])拆分为低位[7:0]和高位[15:8]字节。

verilog代码

module top_module (
	input [15:0] in,
	output [7:0] out_hi,
	output [7:0] out_lo
);
	
	assign out_hi = in[15:8];
	assign out_lo = in[7:0];
	
	// Concatenation operator also works: assign {out_hi, out_lo} = in;
	
endmodule

2.2.3 Vector part select(矢量部分选择) 

 问题描述

32 位矢量可以被视为包含 4 个字节(位 [31:24]、[23:16] 等)。构建一个电路,该电路将反转 4 字节字的字节顺序。

AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa

当需要交换一段数据的字节序时,例如在小端 x86 系统和许多 Internet 协议中使用的大端格式之间,通常使用此操作。

verilog代码

module top_module (
	input [31:0] in,
	output [31:0] out
);

	assign out[31:24] = in[ 7: 0];	
	assign out[23:16] = in[15: 8];	
	assign out[15: 8] = in[23:16];	
	assign out[ 7: 0] = in[31:24];	
	
endmodule

2.2.4 Bitwise operators(按位运算符) 

 问题描述

构建一个具有两个3位输入的电路,用于计算两个向量的位或、两个向量的逻辑或,以及两个向量的逆(非)。将b的非数放在out_not的上半部分(即位[5:3]),将a的非放在下半部分。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第10张图片

 verilog代码

module top_module(
	input [2:0] a, 
	input [2:0] b, 
	output [2:0] out_or_bitwise,
	output out_or_logical,
	output [5:0] out_not
);
	
	assign out_or_bitwise = a | b;
	assign out_or_logical = a || b;

	assign out_not[2:0] = ~a;	// Part-select on left side is o.
	assign out_not[5:3] = ~b;	//Assigning to [5:3] does not conflict with [2:0]
	
endmodule

2.2.5 Four-input gates(四输入门) 

 问题描述

在[3:0]中构建一个具有四个输入的组合电路。

有3个输出:

out_和:4输入与门的输出。

out_或:4输入或门的输出。

输出异或:4输入异或门的输出。

要查看AND、OR和XOR运算符,请参阅andgate,norgate,xnorgate

verilog代码

module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);
   assign out_and = & in;
   assign out_or = | in;
   assign out_xor = ^in;
endmodule

2.2.6 Vector concatenation operator(矢量串联运算符) 

 问题描述

给定多个输入向量,将它们连接在一起,然后将它们拆分为多个输出向量。有六个 5 位输入向量:a、b、c、d、e 和 f,总共 30 位输入。有四个 8 位输出向量:w、x、y 和 z,用于 32 位输出。输出应是输入向量的串联,后跟两个 1 位:

verilog代码

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );//

    // assign { ... } = { ... };
    assign {w,x,y,z} = {a,b,c,d,e,f,2'b11};
endmodule

2.2.7 Vector reversal1(矢量反转) 

 问题描述

给定一个 8 位输入向量 [7:0],反转其位顺序。

verilog代码

module top_module (
	input [7:0] in,
	output [7:0] out
);
//第一种方法
	assign {out[0],out[1],out[2],out[3],out[4],out[5],out[6],out[7]} = in;
	
/*第二种方法

//我知道你非常想知道如何使用循环来实现这一点:

//创建一个组合始终块。这就产生了计算相同结果的组合逻辑

//作为顺序代码。for循环描述的是电路*行为*,而不是*结构*,因此只能使用它们

//程序块内部(例如,始终块)。

//创建的电路(导线和门)不进行任何迭代:它只产生相同的结果

//好像迭代发生了。实际上,逻辑合成器会在编译时进行迭代,以

//找出要生产的电路。(相比之下,Verilog模拟器将按顺序执行循环。)

//在模拟过程中。)
	always @(*) begin	
		for (int i=0; i<8; i++)	// int is a SystemVerilog type. Use integer for pure Verilog.
			out[i] = in[8-i-1];
	end

//第三种方法

//也可以使用generate for循环来实现这一点。生成循环看起来像循环的过程,

//但在概念上是完全不同的,不容易理解。生成循环用于进行实例化

//关于“事物”(与程序循环不同,它不描述动作)。这些“东西”是赋值语句,

//模块实例化、网络/变量声明和过程块(不在内部时可以创建的东西)

//程序)。生成循环(和genvars)完全在编译时计算。你可以想到

//块作为预处理的一种形式,生成更多代码,然后通过逻辑合成器运行。

//在下面的示例中,generate for循环首先在编译时创建8条assign语句,然后合成的。

//请注意,由于其预期用途(在编译时生成代码),因此有一些限制

//关于你如何使用它们。例子:1。Quartus需要一个generate for循环才能有一个命名的开始-结束块

//附件(在本例中,名为“my_block_name”)。2.在循环体内部,genvars是只读的。
	generate
		genvar i;
		for (i=0; i<8; i = i+1) begin: my_block_name
			assign out[i] = in[8-i-1];
		end
	endgenerate
	*/
	
endmodule

2.2.8 Repliction operator(复制操作员) 

 问题描述

复制操作员常见的一个地方是,将一个较小的数字扩展为一个较大的数字,同时保留其有符号值。这是通过复制左边较小数字的符号位(最高有效位)来实现的。例如,将4'b0101扩展到8位的符号导致8'b00000101,而将4'b1101扩展到8位的符号导致8'b11111101。

构建一个将8位数字扩展到32位的电路。这需要将符号位的24个副本(即复制位[7]24次)与8位数字本身串联起来。

verilog代码

module top_module (
	input [7:0] in,
	output [31:0] out
);

	// Concatenate two things together:
	// 1: {in[7]} repeated 24 times (24 bits)
	// 2: in[7:0] (8 bits)
	assign out = { {24{in[7]}}, in };
	
endmodule

2.2.9 More replication(更多复制) 

 问题描述

给定五个 1 位信号(a、b、c、d 和 e),计算 25 位输出矢量中的所有 25 个成对单位比较。如果要比较的两位相等,则输出应为 1。

out[24] = ~a ^ a;   // a == a, so out[24] is always 1.
out[23] = ~a ^ b;
out[22] = ~a ^ c;
...
out[ 1] = ~e ^ d;
out[ 0] = ~e ^ e;

verilog代码

module top_module (
	input a, b, c, d, e,
	output [24:0] out
);

	wire [24:0] top, bottom;
	assign top    = { {5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}} };
	assign bottom = {5{a,b,c,d,e}};
	assign out = ~top ^ bottom;	// Bitwise XNOR

	// This could be done on one line:
	// assign out = ~{ {5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}} } ^ {5{a,b,c,d,e}};
	
endmodule

​​​2.3  Modules: Hierarchy(模块:层次结构

 2.3.1 Modules(模块

问题描述

将信号连接到模块端口

有两种常用的方法将电线连接到端口:按位置或按名称。

按职位

按位置将电线连接到端口的语法应该很熟悉,因为它使用类似C的语法。实例化模块时,端口根据模块的声明从左到右连接。例如:mod_a instance1 ( wa, wb, wc );

这将实例化类型的模块并为其提供实例名称"instance1",然后将信号(新模块外部)连接到新模块的第一个端口 ()、第二个端口 () 和第个端口 ()。此语法的一个缺点是,如果模块的端口列表发生更改,则还需要查找和更改模块的所有实例化以匹配新模块。

按名称

通过名称将信号连接到模块的端口,即使端口列表发生变化,电线也能保持正确连接。但是,此语法更为冗长。例如:mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );

上面的行实例化了一个名为"instance2"的模块类型,然后将信号(模块外部)连接到名为wc 的端口 ,连接到名为wa 的端口,以及名为 wb的端口。请注意,端口的排序在这里是如何无关紧要的,因为无论其在子模块的端口列表中的位置如何,都将与正确的名称建立连接。另请注意此语法中紧挨着端口名称前面的句点。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第11张图片

 verilog代码 

module top_module (
	input a,
	input b,
	output out
);

	// Create an instance of "mod_a" named "inst1", and connect ports by name:
	mod_a inst1 ( 
		.in1(a), 	// Port"in1"connects to wire "a"
		.in2(b),	// Port "in2" connects to wire "b"
		.out(out)	// Port "out" connects to wire "out" 
				// (Note: mod_a's port "out" is not related to top_module's wire "out". 
				// It is simply coincidence that they have the same name)
	);

/*
	// Create an instance of "mod_a" named "inst2", and connect ports by position:
	mod_a inst2 ( a, b, out );	// The three wires are connected to ports in1, in2, and out, respectively.
*/
	
endmodule

2.3.2 Connecting ports by position(按位置连接端口)

问题描述

此问题与上一个问题类似 (模块).您将获得一个名为该模块的模块,该模块具有 2 个输出和 4 个输入(按该顺序排列)。必须按位置将 6 个端口按该顺序连接到顶级模块的端口

您将获得以下模块:

module mod_a ( output, output, input, input, input, input );

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第12张图片

verilog代码

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a u_mod_a(out1,out2,a,b,c,d);
endmodule

2.3.3 Connecting ports by name(按名称连接端口)

问题描述

此问题类似于模块.您将获得一个名为该模块的模块,该模块按某种顺序具有 2 个输出和 4 个输入。您必须按名称将 6 个端口连接到顶级模块的端口

此问题类似于模块.您将获得一个名为该模块的模块,该模块按某种顺序具有 2 个输出和 4 个输入。您必须按名称将 6 个端口连接到顶级模块的端口

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第13张图片

verilog代码

module top_module ( 
    input a, 
    input b, 
    input c,
    input d,
    output out1,
    output out2
);
    mod_a u_mod_a (  
        .out1(out1),
        .out2(out2),
        .in1 (a   ),
        .in2 (b   ),
        .in3 (c   ),
        .in4 (d   )
    );
endmodule

2.3.4 Three modules(三个模块)

问题描述

您将获得一个具有两个输入和一个输出的模块(实现D触发器)。实例化其中三个,然后将它们链接在一起以形成长度为 3 的移位寄存器。端口需要连接到所有实例。my_dffclk

提供给您的模块是:module my_dff ( input clk, input d, output q );

请注意,要进行内部连接,您需要声明一些电线。在命名电线和模块实例时要小心:名称必须是唯一的。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第14张图片

verilog代码

module top_module ( input clk, input d, output q );
    wire q1,q2;
    my_dff u1_my_dff(
        .clk(clk),
        .d(d),
        .q(q1)
    );
    my_dff u2_my_dff(
        .clk(clk),
        .d(q1),
        .q(q2)
    );
    my_dff u3_my_dff(
        .clk(clk),
        .d(q2),
        .q(q)
    );
endmodule

2.3.5 Module and vectors(模块和矢量)

问题描述

本练习是 module_shift 的扩展。模块端口不再只是单个引脚,我们现在有带有向量作为端口的模块,您将连接线向量而不是普通线。与 Verilog 中的其他任何地方一样,端口的向量长度不必与连接到它的导线相匹配,但这会导致向量的零填充或截断。本练习不使用向量长度不匹配的连接。

您将获得一个带有两个输入和一个输出的模块 my_dff8(实现一组 8 个 D 触发器)。实例化其中的三个,然后将它们链接在一起以形成一个长度为 3 的 8 位宽移位寄存器。此外,创建一个 4 对 1 多路复用器(未提供),它根据 sel[1:0] 选择输出什么:输入 d 处的值,在第一个、第二个或第三个 D 触发器之后。 (本质上,sel 选择延迟输入的周期数,从零到三个时钟周期。)

提供给你的模块是:module my_dff8(input clk, input [7:0] d, output [7:0] q);

未提供多路复用器。一种可能的编写方法是在一个带有 case 语句的 always 块中。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第15张图片

verilog代码

module top_module (
	input clk,
	input [7:0] d,
	input [1:0] sel,
	output reg [7:0] q
);

	wire [7:0] o1, o2, o3;		// output of each my_dff8
	
	// Instantiate three my_dff8s
	my_dff8 d1 ( clk, d, o1 );
	my_dff8 d2 ( clk, o1, o2 );
	my_dff8 d3 ( clk, o2, o3 );

	// This is one way to make a 4-to-1 multiplexer
	always @(*)		// Combinational always block
		case(sel)
			2'h0: q = d;
			2'h1: q = o1;
			2'h2: q = o2;
			2'h3: q = o3;
		endcase

endmodule

2.3.6 Adder1(加法器 1)

问题描述

您将获得一个执行 16 位加法的模块 add16。 实例化其中两个以创建一个 32 位加法器。 一个 add16 模块计算加法结果的低 16 位,而第二个 add16 模块在接收到第一个加法器的进位后计算结果的高 16 位。 您的 32 位加法器不需要处理进位(假设为 0)或进位(忽略),但内部模块需要才能正常工作。 (换句话说,add16 模块执行 16 位 a + b + cin,而您的模块执行 32 位 a + b)。

如下图所示将模块连接在一起。 提供的模块 add16 具有以下声明:

module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第16张图片

  verilog代码

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cout,cout1;
    add16 u1_add16(
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(1'b0),
        .sum(sum[15:0]),
        .cout(cout)
    );
   add16 u2_add16(
       .a(a[31:16]),
       .b(b[31:16]),
       .cin(cout),
       .sum(sum[31:16]),
       .cout(cout1)
    );
endmodule

2.3.7 Adder2(加法器 2)

问题描述

在本练习中,您将创建具有两个层次结构的电路。您的 top_module 将实例化 add16 的两个副本(已提供),每个副本将实例化 add1 的 16 个副本(您必须编写)。因此,您必须编写两个模块:top_module 和 add1。

与 module_add 一样,您将获得一个执行 16 位加法的模块 add16。您必须实例化其中的两个以创建 32 位加法器。一个 add16 模块计算加法结果的低 16 位,而第二个 add16 模块计算结果的高 16 位。您的 32 位加法器不需要处理进位(假设为 0)或进位(忽略)。

如下图所示将 add16 模块连接在一起。提供的模块 add16 具有以下声明:

模块add16(输入[15:0] a,输入[15:0] b,输入cin,输出[15:0] sum,输出cout);

在每个 add16 中,实例化了 16 个全加器(模块 add1,未提供)以实际执行加法。您必须编写具有以下声明的完整加法器模块:

模块add1(输入a,输入b,输入cin,输出总和,输出cout);

回想一下,全加器计算 a+b+cin 的和和进位。

综上所述,本设计共有三个模块:

top_module — 您的顶级模块,其中包含两个...
add16, provided — 一个 16 位加法器模块,由 16 个...
add1 — 1 位全加器模块。

如果您的提交缺少模块 add1,您将收到一条错误消息,显示错误 (12006):节点实例“user_fadd[0].a1”实例化未定义实体“add1”。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第17张图片

 verilog代码

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);//
    wire cout1,cout2;
    add16 u1_add16(
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(1'b0),
        .sum(sum[15:0]),
        .cout(cout1)
    );
    add16 u2_add16(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(cout1),
        .sum(sum[31:16]),
        .cout(cout2)
    );
endmodule

module add1 ( input a, input b, input cin,   output sum, output cout );

// Full adder module here
    assign {cout,sum} = a+b+cin;
endmodule

2.3.8 Carry-select adder(携带选择加法器)

问题描述

纹波进位加法器的一个缺点(参见前面的练习)是加法器计算进位的延迟(从进位,在最坏的情况下)相当慢,并且第二级加法器无法开始计算其执行直到第一级加法器完成。这使加法器变慢。一种改进是进位选择加法器,如下所示。第一级加法器和以前一样,但是我们复制第二级加法器,一个假设进位=0,一个假设进位=1,然后使用快速2对1多路复用器选择哪个结果碰巧是正确的。 在本练习中,为您提供与前一练习相同的模块 add16,它将两个 16 位数字与进位相加,并产生一个进位和 16 位和。您必须使用您自己的 16 位 2 对 1 多路复用器来实例化其中的三个以构建进位选择加法器。 如下图所示将模块连接在一起。提供的模块 add16 具有以下声明:

module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第18张图片

verilog代码

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire cout1,cout2,cout3;
    wire [15:0] sum0;
    wire [15:0] sum1;
    add16 u1_add16(
        .a(a[15:0]),
        .b(b[15:0]),
        .cin(1'b0),
        .sum(sum[15:0]),
        .cout(cout1)
    );
    add16 u2_add16(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(1'b0),
        .sum(sum0[15:0]),
        .cout(cout2)
    );
    add16 u3_add16(
        .a(a[31:16]),
        .b(b[31:16]),
        .cin(1'b1),
        .sum(sum1[15:0]),
        .cout(cout3)
    );
    assign sum[31:16]=cout1 ? sum1 : sum0;
endmodule

2.3.9 Adder-subtractor(加法器减法器)

​​问题描述

加法器-减法器可以通过选择性地取反一个输入来从加法器构建,这相当于将输入反相然后加 1。最终结果是一个可以执行两种操作的电路:(a + b + 0) 和 ( a + ~b + 1)。 如果您想更详细地了解该电路的工作原理,请参阅 Wikipedia。 构建下面的加减法器。 为您提供了一个 16 位加法器模块,您需要对其进行两次实例化: module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

每当 sub 为 1 时,使用 32 位宽的 XOR 门来反转 b 输入。(这也可以被视为 b[31:0] 与 sub 复制 32 次进行异或。请参阅复制运算符。)。 还将子输入连接到加法器的进位。

HDLbits刷题中文完整版,按照刷题网站顺序每日更新一道_第19张图片

verilog代码 

module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire[31:0]	b_com;
    wire		cout;
    
    assign b_com = sub ?~b:b;
    //assign b_com = {32{sub}} ^ b;
    add16 u1_add16(
        .a      (a[15:0]        ),
        .b      (b_com[15:0]	),
        .cin    (sub            ),
        .sum    (sum[15:0]   ),
        .cout   (cout           )
    );
    
    add16 u2_add16(
        .a      (a[31:16]       ),
        .b      (b_com[31:16]	),
        .cin    (cout	        ),
        .sum    (sum[31:16]	),
        .cout   (               )
    );
endmodule

你可能感兴趣的:(笔记,开发语言)