关注 望森FPGA 查看更多FPGA资讯
这是望森的第 8 期分享
作者 | 望森
来源 | 望森FPGA
目录
1 Wire | 连线
2 GND | 地线
3 NOR | 或非门
4 Another gate | 另外的门电路
5 Two gates | 两个门电路
6 More logic gates | 更多逻辑门电路
7 7420 chip | 7420 芯片
8 Truth tables | 真值表
9 Two-bit equality | 两位相等
10 Simple circuit A | 简单电路A
11 Simple circuit B | 简单电路B
12 Combine circuits A and B | 合并电路 A 和 B
13 Ring or vibrate? | 响铃还是振动?
14 Thermostat | 恒温器
15 bit population count | 比特计数电路
16 Gates and vectors | 门电路与向量
17 Even longer vectors | 更长的向量
本文中的代码都能够正常运行,请放心食用😋~
练习的官方网站是:https://hdlbits.01xz.net/
注:作者将每个练习的知识点都放在了题目和答案之后
1 Wire | 连线
题目:
实现以下电路:
答案:
module top_module (
input in,
output out);
assign out = in;
endmodule
2 GND | 地线
题目:
实现以下电路:
答案:
module top_module (
output out);
assign out = 1'b0;
endmodule
3 NOR | 或非门
题目:
实现以下电路:
答案:
module top_module (
input in1,
input in2,
output out);
assign out = ~(in1 | in2);
endmodule
4 Another gate | 另外的门电路
题目:
实现以下电路:
答案:
module top_module (
input in1,
input in2,
output out);
assign out = in1 & ~in2;
endmodule
5 Two gates | 两个门电路
题目:
实现以下电路:
答案:
module top_module (
input in1,
input in2,
input in3,
output out);
assign out = ~(in1 ^ in2) ^ in3;
endmodule
6 More logic gates | 更多逻辑门电路
题目:
好的,让我们尝试同时构建多个逻辑门。构建一个具有两个输入 a 和 b 的组合电路。
有 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
预期解决方案长度:大约 7 行。
答案:
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
知识点:
错解分析:【注意运算符之间的优先级】
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 7420 chip | 7420 芯片
题目:
7400 系列集成电路是一系列数字芯片,每个芯片都有几个门。7420 是一款带有两个 4 输入 NAND 门的芯片。
创建一个具有与 7420 芯片相同功能的模块。它有 8 个输入和 2 个输出。
答案:
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
8 Truth tables | 真值表
题目:
在前面的练习中,我们使用了简单的逻辑门和多个逻辑门的组合。这些电路是组合电路的例子。组合意味着电路的输出是其输入的函数(在数学意义上)。这意味着对于任何给定的输入值,只有一个可能的输出值。因此,描述组合函数行为的一种方法是明确列出输入的每个可能值的输出应该是什么。这是一个真值表。
对于 N 个输入的布尔函数,有 2(N) 个可能的输入组合。真值表的每一行都列出一个输入组合,因此总是有 2(N) 行。输出列显示每个输入值的输出应该是什么。
上面的真值表适用于三输入单输出函数。它有 8 行,分别表示 8 种可能的输入组合,以及一个输出列。有 4 种输入组合的输出为 1,还有 4 种输入组合的输出为 0。
创建一个实现上述真值表的组合电路。
答案:
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
always@(*)begin
case({x3,x2,x1})
3'b000 : f = 1'b0;
3'b001 : f = 1'b0;
3'b010 : f = 1'b1;
3'b011 : f = 1'b1;
3'b100 : f = 1'b0;
3'b101 : f = 1'b1;
3'b110 : f = 1'b0;
3'b111 : f = 1'b1;
default f = 1'b0;
endcase
end
endmodule
知识点:
从真值表合成电路
假设我们想构建上述电路,但只能使用一组标准逻辑门。如何构建任意逻辑函数(以真值表表示)?
创建实现真值表功能的电路的一种简单方法是:以乘积和的形式来表达该功能。乘积(即“与”)之和(即“或”)意味着真值表的每一行使用一个 N 输入与门(以检测输入何时与每一行匹配),后跟一个“或”门,该“或”门仅选择导致 '1' 输出。
对于上述示例,如果输入与第 2 行或第 3 行或第 5 行或第 7 行匹配,则输出为“1”(这是一个 4 输入或门)。如果 x3=0 且 x2=1 且 x1=0,则输入与第 2 行匹配(这是一个 3 输入与门)。因此,可以使用 4 个相互“或”的与门以规范形式实现此真值表。
9 Two-bit equality | 两位相等
题目:
创建一个具有两个 2 位输入 A[1:0] 和 B[1:0] 的电路,并产生输出 z。如果 A = B,则 z 的值应为 1,否则 z 应为 0。
答案:
module top_module ( input [1:0] A, input [1:0] B, output z );
assign z = (A == B) ? 1'b1 : 1'b0;
endmodule
10 Simple circuit A | 简单电路A
题目:
模块 A 应该实现函数 z = (x^y) & x。实现此模块。
答案:
module top_module (input x, input y, output z);
assign z = (x^y) & x;
endmodule
11 Simple circuit B | 简单电路B
题目:
电路 B 可以用以下模拟波形描述:
实现该电路。
答案:
真值表:
x | y | z |
0 | 0 | 1 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
表达式:
z = ~ (x ^ y)
代码:
module top_module ( input x, input y, output z );
assign z = ~ (x ^ y);
endmodule
12 Combine circuits A and B | 合并电路 A 和 B
题目:
请参阅 mt2015_q4a 和 mt2015_q4b 了解此处使用的子模块。顶层设计由子电路 A 和 B 各两个实例组成,如下所示。
实现该电路。
答案:
module top_module (input x, input y, output z);
wire z_t1;
module_a inst1(
.z(z_t1),
.x(x),
.y(y)
);
wire z_t2;
module_b inst2(
.z(z_t2),
.x(x),
.y(y)
);
wire z_t3;
module_a inst3(
.z(z_t3),
.x(x),
.y(y)
);
wire z_t4;
module_b inst4(
.z(z_t4),
.x(x),
.y(y)
);
wire z_t12,z_t34;
assign z_t12 = z_t1 | z_t2;
assign z_t34 = z_t3 & z_t4;
assign z = z_t12 ^ z_t34;
endmodule
module module_a (input x, input y, output z);
assign z = (x^y) & x;
endmodule
module module_b ( input x, input y, output z );
assign z = ~ (x ^ y);
endmodule
13 Ring or vibrate? | 响铃还是振动?
题目:
假设您正在设计一个电路来控制手机的铃声和振动马达。每当手机需要因来电而响铃时(输入铃声),您的电路必须打开铃声(输出铃声 = 1)或马达(输出马达 = 1),但不能同时打开两者。如果手机处于振动模式(输入振动模式 = 1),则打开马达。否则,打开铃声。
尝试仅使用赋值语句,看看是否可以将问题描述转换为逻辑门的集合。
答案:
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
always@(*) begin
if(ring)begin
if(vibrate_mode) begin
ringer = 1'b0;
motor = 1'b1;
end
else begin
ringer = 1'b1;
motor = 1'b0;
end
end
else begin
ringer = 1'b0;
motor = 1'b0;
end
end
endmodule
知识点:
设计提示:在设计电路时,人们通常必须“反向”思考问题,从输出开始,然后反向处理输入。
这通常与人们思考(顺序、命令式)编程问题的方式相反,在顺序编程中,人们会先查看输入,然后决定操作(或输出)。对于顺序程序,人们通常会认为“如果(输入是 ___ )那么(输出应该是 ___ )”。另一方面,硬件设计师经常认为“当(输入为___)时,(输出应为___)。
上述问题描述以适合软件编程的命令式形式编写(如果响铃,则执行此操作),因此您必须将其转换为更适合硬件实现的声明式形式(assign ringer = ___)。能够以两种风格思考并在两者之间进行转换是硬件设计所需的最重要技能之一。
14 Thermostat | 恒温器
题目:
加热/冷却恒温器控制加热器(冬季)和空调(夏季)。实现一个电路,根据需要打开和关闭加热器、空调和鼓风机。
恒温器可以处于两种模式之一:加热(模式 = 1)和冷却(模式 = 0)。
在加热模式下,当太冷时打开加热器(too_cold = 1),但不使用空调。
在冷却模式下,当太热时打开空调(too_hot = 1),但不打开加热器。
当加热器或空调打开时,也打开风扇以循环空气。
此外,即使加热器和空调都关闭,用户也可以请求风扇打开(fan_on = 1)。
尝试仅使用赋值语句,看看是否可以将问题描述转化为逻辑门的集合。
答案:
module top_module (
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
parameter OPEN = 1'b1;
parameter CLOSE = 1'b0;
always@(*)begin
if(mode) begin //heating
if(too_cold) begin
heater = OPEN;
aircon = CLOSE;
fan = OPEN;
end
else if(fan_on) begin
heater = CLOSE;
aircon = CLOSE;
fan = OPEN;
end
else begin
heater = CLOSE;
aircon = CLOSE;
fan = CLOSE;
end
end
else begin //cooling
if(too_hot) begin
heater = CLOSE;
aircon = OPEN;
fan = OPEN;
end
else if(fan_on) begin
heater = CLOSE;
aircon = CLOSE;
fan = OPEN;
end
else begin
heater = CLOSE;
aircon = CLOSE;
fan = CLOSE;
end
end
end
endmodule
15 bit population count | 比特计数电路
题目:
“人口计数”电路计算输入向量中“1”的数量。为 3 位输入向量构建人口计数电路。
答案:
我的答案:
真值表:
in[2] | in[1] | in[0] | out[1] | out[0] |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 0 | 1 |
0 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 0 | 1 |
1 | 0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 | 0 |
1 | 1 | 1 | 1 | 1 |
卡诺图:
out[1]
in[2]/in[1] in[0] | 00 | 01 | 11 | 10 |
0 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 1 | 1 |
out[0]
in[2]/in[1] in[0] | 00 | 01 | 11 | 10 |
0 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 1 | 0 |
逻辑表达式:
out[1] = in[2] in[0] + in[2] in[1] + in[1] in[0]
out[0] = in[2] in[1]' in[0]' + in[2] in[1] in[0] + in[2]' in[1]' in[0] + in[2]' in[1] in[0]'
代码:
我的答案:
module top_module(
input [2:0] in,
output [1:0] out );
always@(*) begin
out[1] = in[2]&in[0] | in[2]&in[1] | in[1]&in[0];
out[0] = in[2]&~in[1]&~in[0] | in[2]&in[1]&in[0] | ~in[2]&~in[1]&in[0] | ~in[2]&in[1]&~in[0];
end
endmodule
参考答案:
module top_module (
input [2:0] in,
output [1:0] out
);
// This is a function of 3 inputs. One method is to use a 8-entry truth table:
// in[2:0] out[1:0]
// 000 00
// 001 01
// 010 01
// 011 10
// 100 01
// 101 10
// 110 10
// 111 11
assign out[0] = (~in[2] & ~in[1] & in[0]) | (~in[2] & in[1] & ~in[0]) | (in[2] & ~in[1] & ~in[0]) | (in[2] & in[1] & in[0]);
assign out[1] = (in[1] & in[0]) | (in[2] & in[0]) | (in[2] & in[1]);
// Using the addition operator works too:
// assign out = in[0]+in[1]+in[2];
// Yet another method uses behavioural code inside a procedure (combinational always block)
// to directly implement the truth table:
/*
always @(*) begin
case (in)
3'd0: out = 2'd0;
3'd1: out = 2'd1;
3'd2: out = 2'd1;
3'd3: out = 2'd2;
3'd4: out = 2'd1;
3'd5: out = 2'd2;
3'd6: out = 2'd2;
3'd7: out = 2'd3;
endcase
end
*/
endmodule
16 Gates and vectors | 门电路与向量
题目:
给定一个四位输入向量 in[3:0]。我们想知道每个位与其相邻位之间的一些关系:
-
out_both:此输出向量的每个位应指示相应的输入位及其左侧的相邻位(较高索引)是否均为“1”。例如,out_both[2] 应指示 in[2] 和 in[3] 是否均为 1。由于 in[3] 左侧没有相邻位,因此答案显而易见,因此我们不需要知道 out_both[3]。
-
out_any:此输出向量的每个位应指示相应的输入位及其右侧的相邻位是否为“1”。例如,out_any[2] 应指示 in[2] 或 in[1] 是否为 1。由于 in[0] 右侧没有相邻位,因此答案显而易见,因此我们不需要知道 out_any[0]。
-
out_different:此输出向量的每个位应指示相应的输入位是否与其左侧的相邻位不同。例如,out_different[2] 应指示 in[2] 是否与 in[3] 不同。对于这部分,将向量视为环绕,因此 in[3] 左侧的相邻位是 in[0]。
答案:
我的答案:
module top_module(
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );
always@(*) begin
out_both = in[3:1] & in[2:0];
out_any = in[3:1] | in[2:0];
out_different = in ^ {in[0],in[3:1]};
end
endmodule
参考答案:
module top_module (
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different
);
// Use bitwise operators and part-select to do the entire calculation in one line of code
// in[3:1] is this vector: in[3] in[2] in[1]
// in[2:0] is this vector: in[2] in[1] in[0]
// Bitwise-OR produces a 3 bit vector. | | |
// Assign this 3-bit result to out_any[3:1]: o_a[3] o_a[2] o_a[1]
// Thus, each output bit is the OR of the input bit and its neighbour to the right:
// e.g., out_any[1] = in[1] | in[0];
// Notice how this works even for long vectors.
assign out_any = in[3:1] | in[2:0];
assign out_both = in[2:0] & in[3:1];
// XOR 'in' with a vector that is 'in' rotated to the right by 1 position: {in[0], in[3:1]}
// The rotation is accomplished by using part selects[] and the concatenation operator{}.
assign out_different = in ^ {in[0], in[3:1]};
endmodule
知识点:
学会找到题目中的规律并用代码表示!
17 Even longer vectors | 更长的向量
题目:
给定一个 100 位输入向量 in[99:0]。我们想知道每个位与其相邻位之间的一些关系:
-
out_both:此输出向量的每个位应指示相应的输入位及其左侧相邻位是否均为“1”。例如,out_both[98] 应指示 in[98] 和 in[99] 是否均为 1。由于 in[99] 左侧没有相邻位,因此答案显而易见,因此我们不需要知道 out_both[99]。
-
out_any:此输出向量的每个位应指示相应的输入位及其右侧相邻位是否均为“1”。例如,out_any[2] 应指示 in[2] 或 in[1] 是否为 1。由于 in[0] 右侧没有相邻位,因此答案显而易见,因此我们不需要知道 out_any[0]。
-
out_different:此输出向量的每一位应指示相应的输入位是否与其左侧的相邻位不同。例如,out_different[98] 应指示 in[98] 是否与 in[99] 不同。对于这部分,将向量视为环绕,因此 in[99] 左侧的相邻位是 in[0]。
答案:
module top_module(
input [99:0] in,
output [98:0] out_both,
output [99:1] out_any,
output [99:0] out_different );
always@(*) begin
out_both = in[99:1] & in[98:0];
out_any = in[99:1] | in[98:0];
out_different = in ^ {in[0],in[99:1]};
end
endmodule
- END -
公z号/CSDN/EETOP搜索【望森FPGA】,查看更多FPGA资讯~
相关推荐文章,点击跳转:
望森FPGA的HDLBits专栏