硬件模块设计的思考方式

HDLBits链接


基本的逻辑门操作

题目描述1:将输入端口in和输出端口out连接。

Solution1

1
2
3
4
5
module top_module (
input in,
output out);
assign out = in;
endmodule

题目描述2:将输出out接地。

1

Solution2

1
2
3
4
module top_module (
output out);
assign out = 1'b0;
endmodule

题目描述3:实现或非门操作。

2

Solution3

1
2
3
4
5
6
module top_module (
input in1,
input in2,
output out);
assign out =~(in1 | in2);
endmodule

题目描述4:实现下图所示的逻辑操作。

3

Solution4

1
2
3
4
5
6
module top_module (
input in1,
input in2,
output out);
assign out = in1 & (~in2);
endmodule

题目描述5:实现下图所示的逻辑操作。

4

Solution5

1
2
3
4
5
6
7
8
9
module top_module (
input in1,
input in2,
input in3,
output out);
wire temp;
assign temp = ~(in1^in2);
assign out = temp ^ in3;
endmodule

题目描述6:尝试同时建立几个逻辑门,建立一个两输入的组合电路。

共7个输出如下:

  • out_and: a and b
  • out_or: a or b
  • out_xor: a xor b
  • out_nand: a nand b
  • out_nor: a nor b
  • out_xnor: a xnor b
  • out_anotb: a and-not b

Solution6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top_module( 
input a, b,
output out_and,
output out_or,
output out_xor,
output out_nand,
output out_nor,
output out_xnor,
output out_anotb
);
assign out_and = a&b;
assign out_or = a|b;
assign out_xor = a^b;
assign out_nand = ~(a&b);
assign out_nor = ~(a|b);
assign out_xnor = ~(a^b);
assign out_anotb = a&(~b);
endmodule

题目描述7

7400系列集成电路是一个数字芯片系列,每个都由几个基本的逻辑门构成。7420是一个带有两个4输入与非门的芯片。

实现一个具有与7420芯片相同功能的模块,共8个输入和2个输出。

5

Solution7

1
2
3
4
5
6
7
8
module top_module ( 
input p1a, p1b, p1c, p1d,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
assign p1y=~(p1a&p1b&p1c&p1d);
assign p2y=~(p2a&p2b&p2c&p2d);
endmodule

真值表

在前面的练习中,我们使用简单的逻辑门和几个逻辑门的组合,这些电路是组合电路的例子。

组合电路的意思是电路的输出仅取决于输入,这意味着对于任何给定的输入值,只有一个可能的输出值。因此,描述组合函数行为的一种方法是明确地列出所有可能的输入所对应的输出值,即真值表。

对一个有N个输入的布尔函数而言,有2^N种可能的输入组合。真值表的每一行都列出了一个输入组合,因此总有2^N行。output列显示了每个输入值对应的输出。

6

那么我们如何只用标准逻辑门来实现查找表的功能呢?

一种简单的方法是将真值表中所有的真值写为乘积求和项的形式。求和即为或操作,乘积即为与操作。先使用一个N-输入的与门来决定是否输入的向量与真值表匹配,然后再用一个或门来选择满足匹配条件的结果进行输出。

题目描述:构建一个模块实现上述真值表的功能。

7

Solution

1
2
3
4
5
6
7
8
module top_module( 
input x3,
input x2,
input x1, // three inputs
output f // one output
);
assign f = (x1&x3)|(x2&~x3);
endmodule

部分考题

题目描述1

创建一个有两个2位输入A[1:0]和B[1:0]的电路,产生一个输出z。若A=B,则z=1,否则z=0。

Solution1

1
2
3
module top_module ( input [1:0] A, input [1:0] B, output z ); 
assign z=(A==B)?1'b1:1'b0;
endmodule

题目描述2

构建模块实现函数z = (x^y) & x

Solution2:

1
2
3
module top_module (input x, input y, output z);
assign z=(x^y)&x;
endmodule

题目描述3

构建模块实现如下波形图的输入输出关系

8

Solution3

1
2
3
module top_module ( input x, input y, output z );
assign z=~(x^y);
endmodule

题目描述4

A模块实现的功能如上述题二所示,B模块实现的功能如题三所示。搭建模块实现下图所示功能:

9

Solution4

1
2
3
4
5
6
7
8
9
10
module top_module (input x, input y, output z);

wire za;
wire zb;

assign za = (x ^ y) & x;
assign zb = ~(x ^ y);
assign z = (za | zb) ^ (za & zb);

endmodule

硬件工程师的思考方式

tips:当进行模块设计时,我们最好反向思考问题,如何从输出到输入。这与我们平时顺序式地思考编程问题不同,在编程时我们一般首先看输入如何决定输出,即输入为XX时输出为XX;对硬件工程师而言,通常的思路为输出为XX时输入是XX

在硬件设计中,在两种思路间思考与切换是很重要的技能。

题目描述1:设计一种电路来控制手机的铃声和振动马达。当有来电输入信号时(input ring),电路必须打开铃声(output ringer= 1)或电机(output motor= 1),但不能同时打开。如果手机处于振动模式(input vibrate_mode = 1),打开电机。否则打开铃声。

10

Solution1

1
2
3
4
5
6
7
8
9
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
assign ringer = ring & (~vibrate_mode);
assign motor = ring & vibrate_mode;
endmodule

题目描述2:加热/冷却恒温器同时控制加热器(冬季)和空调(夏季)。设计一个电路,根据需要打开或关闭加热器、空调和鼓风机。

恒温器有两种模式:加热模式(mode= 1)和冷却模式(mode= 0)。在加热模式下,当温度过低时打开加热器(too_cold = 1)但是不要使用空调。在冷却模式下,当温度太高(too_hot= 1)时打开空调,但不要打开加热器。

当暖气或空调打开时。同时打开风扇让空气流通。此外。用户也可以仅要求风扇打开(fan_on = 1),即使加热器和空调关闭。

Solution2

1
2
3
4
5
6
7
8
9
10
11
12
13
module top_module (
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
assign heater = mode & too_cold;
assign aircon = (~mode) & too_hot;
assign fan = (mode & too_cold) | ((~mode) & too_hot) | fan_on;
endmodule

对单向量的各bit进行操作

题目描述1:为3位输入向量构造一个数1的计数电路。

Solution1

1
2
3
4
5
6
7
8
9
10
11
module top_module( 
input [2:0] in,
output [1:0] out );
integer i;
always @(*) begin
out = 2'b0;
for(i=0;i<3;i++) begin
out = out + in[i];
end
end
endmodule

题目描述2:输入一个4位的输入向量in[3:0],输出每个比特和它相邻比特之间的一些关系:

  • out_both:这个输出向量的每一位应该表示对应的输入位和它左边的比特位(左边比特具有更高的索引)是否均为“1”。举例说明,out_both[2]应该指示出in[2]和in[3]是否均为1。
  • out_any:这个输出向量的每一位都应该表示相应的输入位和它右边的比特位是否存在“1”
  • out_different:这个输出向量的每一位都应该表明相应的输入位是否与其左边的比特位不同

Solution2

思路一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top_module( 
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );

integer i;

always @(*) begin
for(i=0;i<3;i++) begin
out_both[i] = in[i] & in[i+1];
out_any[i+1] = in[i+1] | in[i];
out_different[i] = in[i] ^ in[i+1];
end
out_different[3] = in[0] ^ in[3];
end

endmodule

思路二:

1
2
3
4
5
6
7
8
9
10
11
module top_module( 
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );

assign out_both = in[2:0] & in[3:1];
assign out_any = in[3:1] | in[2:0];
assign out_different = in[3:0] ^ {in[0],in[3:1]};

endmodule

题目描述3:题目同上,但输入向量变为100位。

Solution3

思路一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top_module( 
input [99:0] in,
output [98:0] out_both,
output [99:1] out_any,
output [99:0] out_different );

integer i;

always @(*) begin
for(i=0;i<99;i++) begin
out_both[i] = in[i] & in[i+1];
out_any[i+1] = in[i+1] | in[i];
out_different[i] = in[i] ^ in[i+1];
end
out_different[99] = in[0] ^ in[99];
end

endmodule

思路二:

1
2
3
4
5
6
7
8
9
10
11
module top_module( 
input [99:0] in,
output [98:0] out_both,
output [99:1] out_any,
output [99:0] out_different );

assign out_both = in[98:0] & in[99:1];
assign out_any = in[99:1] | in[98:0];
assign out_different = in[99:0] ^ {in[0],in[99:1]};

endmodule

总结

  • 熟悉了基本的逻辑门操作。
  • 学习了硬件工程师的设计思维:由输出到输入。
  • 学习了用标准的逻辑门实现查找表的功能。
  • 合理使用assign或for循环对向量的各bit位进行操作。