【Verilog】HDLBits刷题 02 Verilog语言(1)

一、基础

1. wire

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

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

module top_module( input in, output out );
	
	assign out = in;
	// Note that wires are directional, so "assign in = out" is not equivalent.
    // 请注意,电线是有方向的,因此“分配输入 = 输出”并不等效。
	
endmodule

2. four wires

Create a module with 3 inputs and 4 outputs that behaves like wires that makes these connections:

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

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

module top_module (
	input a,
	input b,
	input c,
	output w,
	output x,
	output y,
	output z  );
	
	assign w = a;
	assign x = b;
	assign y = b;
	assign z = c;

	// If we're certain about the width of each signal, using 
	// the concatenation operator is equivalent and shorter:
	// assign {w,x,y,z} = {a,b,b,c};
	
endmodule

3. 非门(NOT gate)

Create a module that implements a NOT gate.

(创建一个实现非门的模块。)

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

4. 与门(AND gate)

Create a module that implements an AND gate.

(创建一个实现 AND 门的模块。)

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

[Hint] Verilog has separate bitwise-AND (&) and logical-AND (&&) operators, like C. Since we're working with a one-bit here, it doesn't matter which we choose.

([提示] Verilog 有单独的按位与 (&) 和逻辑与 (&&) 运算符,如 C。由于我们在这里使用的是一位,所以选择哪一个并不重要。)

4. 或非门(NOR gate)

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.

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

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

[Hint] Verilog has separate bitwise-OR (|) and logical-OR (||) operators, like C. Since we're working with a one-bit here, it doesn't matter which we choose.

([提示] Verilog 有单独的按位或 (|) 和逻辑或 (||) 运算符,如 C。由于我们在这里使用的是一位,所以选择哪一个并不重要。)

5. 异或非门(XNOR gate)

Create a module that implements an XNOR gate.

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

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

[Hint] The bitwise-XOR operator is ^. There is no logical-XOR operator.

([提示] 按位异或运算符是 ^。没有逻辑异或运算符。)

6. 声明 wires

Implement the following circuit. Create two intermediate wires (named anything you want) to connect the AND and OR gates together. Note that the wire that feeds the NOT gate is really wire out, so you do not necessarily need to declare a third wire here. Notice how wires are driven by exactly one source (output of a gate), but can feed multiple inputs.

(实现以下电路。创建两条中间线(任意命名)将“与”门和“或”门连接在一起。请注意,为非门供电的电线实际上是电线输出,因此您不一定需要在此处声明第三根电线。请注意电线如何仅由一个源(门的输出)驱动,但可以馈送多个输入。)

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

7. 7458芯片

The 7458 is a chip with four AND gates and two OR gates. This problem is slightly more complex than 7420.

Create a module with the same functionality as the 7458 chip. It has 10 inputs and 2 outputs. You may choose to use an assign statement to drive each of the output wires, or you may choose to declare (four) wires for use as intermediate signals, where each internal wire is driven by the output of one of the AND gates. For extra practice, try it both ways.

(7458是一个带有四个与门和两个或门的芯片。这个问题比7420稍微复杂一些。
创建一个与7458芯片具有相同功能的模块。它有 10 个输入和 2 个输出。您可以选择使用分配语句来驱动每条输出线,也可以选择声明(四根)线用作中间信号,其中每条内部线由其中一个 AND 门的输出驱动。如需额外练习,请尝试两种方法。)

[Hint] You need to drive two signals (p1y and p2y) with a value.

([提示] 您需要用一个值驱动两个信号(p1y 和 p2y)。)

module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
	wire w1, w2, w3, w4;
    assign w1 = p2a&p2b;
    assign w2 = p2c&p2d;
    assign p2y = w1|w2;
    assign w3 = p1a&p1c&p1b;
    assign w4 = p1f&p1e&p1d;
    assign p1y = w3|w4;

endmodule

二、向量(Vector)

Vectors are used to group related signals using one name to make it more convenient to manipulate. For example, wire [7:0] w; declares an 8-bit vector named w that is functionally equivalent to having 8 separate wires.

Notice that the declaration of a vector places the dimensions before the name of the vector, which is unusual compared to C syntax. However, the part select has the dimensions after the vector name as you would expect.

(向量用于使用一个名称对相关信号进行分组,以使其更方便操作。例如,连线[7:0] w;声明一个名为 w 的 8 位向量,其功能相当于具有 8 条独立的电线。
请注意,向量的声明将维度放在向量名称之前,这与 C 语法相比很不寻常。但是,零件选择的尺寸位于矢量名称后面,正如您所期望的那样。)

wire [99:0] my_vector; // Declare a 100-element vector assign out = my_vector[10]; // Part-select one bit out of the vector

1. 向量

Build a circuit that has one 3-bit input, then outputs the same vector, and also splits it into three separate 1-bit outputs. Connect output o0 to the input vector's position 0, o1 to position 1, etc.

In a diagram, a tick mark with a number next to it indicates the width of the vector (or "bus"), rather than drawing a separate line for each bit in the vector.

(构建一个具有一个 3 位输入的电路,然后输出相同的向量,并将其分成三个独立的 1 位输出。将输出 o0 连接到输入向量的位置 0,将 o1 连接到位置 1,依此类推。
在图中,旁边带有数字的刻度线表示向量(或“总线”)的宽度,而不是为向量中的每个位绘制单独的线。)

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. 向量:部分元素选择

Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.

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

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

3. 向量:调换元素顺序

A 32-bit vector can be viewed as containing 4 bytes (bits [31:24], [23:16], etc.). Build a circuit that will reverse the byte ordering of the 4-byte word.

AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa

This operation is often used when the endianness of a piece of data needs to be swapped, for example between little-endian x86 systems and the big-endian formats used in many Internet protocols.

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

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

[Hint] Part-select can be used on both the left side and right side of an assignment.

([提示] 部分选择可用于分配的左侧和右侧。)

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

4. 按位运算与逻辑运算

Build a circuit that has two 3-bit inputs that computes the bitwise-OR of the two vectors, the logical-OR of the two vectors, and the inverse (NOT) of both vectors. Place the inverse of b in the upper half of out_not (i.e., bits [5:3]), and the inverse of a in the lower half.

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

Bitwise vs. Logical Operators

Earlier, we mentioned that there are bitwise and logical versions of the various boolean operators (e.g., norgate). When using vectors, the distinction between the two operator types becomes important. A bitwise operation between two N-bit vectors replicates the operation for each bit of the vector and produces a N-bit output, while a logical operation treats the entire vector as a boolean value (true = non-zero, false = zero) and produces a 1-bit output.

Look at the simulation waveforms at how the bitwise-OR and logical-OR differ.

(按位运算符与逻辑运算符:
之前,我们提到过各种布尔运算符(例如,norgate)有按位和逻辑版本。使用向量时,两种运算符类型之间的区别变得很重要。两个 N 位向量之间的按位运算会复制向量的每一位的运算并产生 N 位输出,而逻辑运算则将整个向量视为布尔值(true = 非零,false = 零)并且产生 1 位输出。
查看仿真波形,了解按位“或”和逻辑“或”有何不同。)

[Hint] Even though you cannot assign to a wire more than once, you can use a part select on the left-hand-side of an assign. You don't need to assign to the entire vector all in one statement.

([提示] 即使您不能多次分配给一条连线,您也可以在分配的左侧使用部件选择。您不需要在一个语句中全部分配给整个向量。)

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

5. 四输入组合电路

Build a combinational circuit with four inputs, in[3:0].

There are 3 outputs:

  • out_and: output of a 4-input AND gate.
  • out_or: output of a 4-input OR gate.
  • out_xor: output of a 4-input XOR gate.

(在[3:0]中构建一个具有四个输入的组合电路。
有3个输出:
out_and:4 输入与门的输出。
out_or:4 输入或门的输出。
out_xor:4 输入异或门的输出。)

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

endmodule

6. 向量串联运算符

Given several input vectors, concatenate them together then split them up into several output vectors. There are six 5-bit input vectors: a, b, c, d, e, and f, for a total of 30 bits of input. There are four 8-bit output vectors: w, x, y, and z, for 32 bits of output. The output should be a concatenation of the input vectors followed by two 1 bits:

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

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );//
    assign {w, x, y, z} = {a, b, c, d, e, f, 2'b11};

endmodule

7. 向量反转

Given an 8-bit input vector [7:0], reverse its bit ordering.

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

[Hint]

  • assign out[7:0] = in[0:7]; does not work because Verilog does not allow vector bit ordering to be flipped.
  • The concatenation operator may save a bit of coding, allowing for 1 assign statement instead of 8.

(分配out[7:0] = in[0:7];不起作用,因为 Verilog 不允许翻转向量位顺序。
连接运算符可以节省一些编码,允许 1 个赋值语句而不是 8 个。)

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;
	
	/*
	// I know you're dying to know how to use a loop to do this:

	// Create a combinational always block. This creates combinational logic that computes the same result
	// as sequential code. for-loops describe circuit *behaviour*, not *structure*, so they can only be used 
	// inside procedural blocks (e.g., always block).
	// The circuit created (wires and gates) does NOT do any iteration: It only produces the same result
	// AS IF the iteration occurred. In reality, a logic synthesizer will do the iteration at compile time to
	// figure out what circuit to produce. (In contrast, a Verilog simulator will execute the loop sequentially
	// during simulation.)
	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


	// It is also possible to do this with a generate-for loop. Generate loops look like procedural for loops,
	// but are quite different in concept, and not easy to understand. Generate loops are used to make instantiations
	// of "things" (Unlike procedural loops, it doesn't describe actions). These "things" are assign statements,
	// module instantiations, net/variable declarations, and procedural blocks (things you can create when NOT inside 
	// a procedure). Generate loops (and genvars) are evaluated entirely at compile time. You can think of generate
	// blocks as a form of preprocessing to generate more code, which is then run though the logic synthesizer.
	// In the example below, the generate-for loop first creates 8 assign statements at compile time, which is then
	// synthesized.
	// Note that because of its intended usage (generating code at compile time), there are some restrictions
	// on how you use them. Examples: 1. Quartus requires a generate-for loop to have a named begin-end block
	// attached (in this example, named "my_block_name"). 2. Inside the loop body, genvars are read only.
	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

8. 复制运算

One common place to see a replication operator is when sign-extending a smaller number to a larger one, while preserving its signed value. This is done by replicating the sign bit (the most significant bit) of the smaller number to the left. For example, sign-extending 4'b0101 (5) to 8 bits results in 8'b00000101 (5), while sign-extending 4'b1101 (-3) to 8 bits results in 8'b11111101 (-3).

Build a circuit that sign-extends an 8-bit number to 32 bits. This requires a concatenation of 24 copies of the sign bit (i.e., replicate bit[7] 24 times) followed by the 8-bit number itself.

(看到复制运算符的一个常见情况是将较小的数字符号扩展为较大的数字,同时保留其有符号值。这是通过将较小数字的符号位(最高有效位)复制到左侧来完成的。例如,将 4'b0101 (5) 符号扩展至 8 位会产生 8'b00000101 (5),而将 4'b1101 (-3) 符号扩展至 8 位会产生 8'b11111101 (-3)。
构建一个将 8 位数字符号扩展为 32 位的电路。这需要串联 24 个符号位副本(即复制 bit[7] 24 次),后跟 8 位数字本身。)

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

9. 重复运算和串联运算

As the diagram shows, this can be done more easily using the replication and concatenation operators.

  • The top vector is a concatenation of 5 repeats of each input
  • The bottom vector is 5 repeats of a concatenation of the 5 inputs

(如图所示,使用复制和串联运算符可以更轻松地完成此操作。
顶部向量是每个输入 5 次重复的串联
底部向量是 5 个输入串联的 5 次重复)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值