目录
3.1.1.4Another gate(Exams/m2014 q4f)
3.1.1.5Two gates(Exams/m2014 q4g)
3.1.1.6 More logic gates(Gates)
3.1.1.8 Truth tables(Truthtable1)
3.1.1.9 Two-bit equality(Mt2015 eq2)
3.1.1.10 Simple circuit A(Mt2015 q4a)
3.1.1.11 Simple circuit B(Mt2015 q4b)
3.1.1.12 Combine circuits A and B(Mt2015 q4)
3.1.1.13 Ring or vibrate?(Ringer)
3.1.1.14 Thermostat(Thermostat)
3.1.1.15 3-bit population count(Popcount3)
3.1.1.16 Gates and vectors(Gatesv)
3.1.1.17 Even longer vectors(Gatesv100)
前言
HDLbits网站如下
Problem sets - HDLBits (01xz.net)
从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是3.1.1Basic gates
3.1.1.1Wire(Exams/m2014 q4h)
实现以下电路:
Solution:
module top_module (
input in,
output out);
assign out = in ;
endmodule
简简单单的wire信号
3.1.1.2GND(Exams/m2014 q4i)
实现以下电路:
Solution:
module top_module (
output out);
assign out = 1'b0;
endmodule
3.1.1.3NOR(Exams/m2014 q4e)
实现以下电路:
Solution:
module top_module (
input in1,
input in2,
output out);
assign out = ~(in1 | in2) ;
endmodule
3.1.1.4Another gate(Exams/m2014 q4f)
实现以下电路:
Solution:
module top_module (
input in1,
input in2,
output out);
assign out = in1 & ~in2 ;
endmodule
3.1.1.5Two gates(Exams/m2014 q4g)
实现以下电路:
Solution:
module top_module (
input in1,
input in2,
input in3,
output out);
assign out = ~(in1^in2)^in3;
endmodule
3.1.1.6 More logic gates(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行
Solution:
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
3.1.1.7 7420 chip(7420)
7400 系列集成电路是一系列数字芯片,每个芯片都有几个门。7420是具有2个4输入与非门的芯片。创建一个与 7420 芯片功能相同的模块。它有8个输入和2个输出。
Solution:
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
3.1.1.8 Truth tables(Truthtable1)
在之前的练习里,我们使用了简单的逻辑门和几个逻辑门的组合。这些电路是组合电路的例子。组合意味着电路的输出只是其输入的函数(在数学意义上)。这意味着对于任何给定的输入值,只有一个可能的输出值。因此,描述组合函数行为的一种方法是明确列出输入的每个可能的输出应该是什么。这就是真值表。
对于 N 个输入的布尔函数,有 个可能的输入组合。真值表的每一行列出一个输入组合,所以总是有 行。输出列显示每个输入值的输出应该是什么。
上面的真值表是针对三输入一输出的函数。对于 8 种可能的输入组合中的每一种,它都有 8 行,以及一个输出列。有四种输入组合,输出为 1,四种输入组合,输出为 0。
从真值表综合电路
假设我们要构建上述电路,但我们仅限于使用标准逻辑门的集合。您将如何构建任意逻辑函数(表示为真值表)?
创建实现真值表功能的电路的一种简单方法是以积(最小项)之和的形式表达该功能。积(意味着与)之和(意味着和)是指真值表的每一行使用一个N输入与门(以检测输入何时与每一行匹配),后跟一个 OR 门,只选择那些输出"1”的行。
乘积的总和(意为 OR)(意为 AND)是指真值表的每一行使用一个 N 输入 AND 门(以检测输入何时与每一行匹配),然后是一个 OR 门,只选择那些导致结果的行“1”输出。
对于上面的示例,如果输入匹配第 2 行或第 3 行或第 5 行或第 7 行(这是一个 4 输入或门),则输出为“1”。如果 x3=0 且 x2=1 且 x1=0(这是一个 3 输入与门),则输入匹配第 2 行。因此,该真值表可以通过使用 4 个进行 OR 运算的 AND 门以规范形式实现。
A Bit of Practice
创建一个实现上述真值表的组合电路。
Solution:
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
assign f = x3&x1 | (~x3)&x2;
endmodule
最小项化简不再赘述。
3.1.1.9 Two-bit equality(Mt2015 eq2)
创建一个具有两个 2 位输入 A[1:0] 和 B[1:0] 的电路,并产生一个输出 z。如果 A = B,则 z 的值应为 1,否则 z 应为 0。
Solution:
module top_module ( input [1:0] A, input [1:0] B, output z );
assign z = (A==B)?1:0;
endmodule
Warning (10230): Verilog HDL assignment warning at top_module.v(2): truncated value with size 32 to match size of target (1) File: /home/h/work/hdlbits.2733779/top_module.v Line: 2
这里出现了一个Warning:当赋值的右侧比左侧宽并且高位被截断时,就会发生截断值。如果出现您没想到的截断,这可能表明存在错误,因此请仔细检查这些内容。最常见情况是当您使用没有宽度的文字时(隐含 32 位),例如,使用assign a[1:0] = 1;而不是assign a[1:0] = 2'd1;
3.1.1.10 Simple circuit A(Mt2015 q4a)
模块A用来实现函数z = (x^y) & x。实现这个模块。
Solution:
module top_module (input x, input y, output z);
assign z = (x^y) & x ;
endmodule
3.1.1.11 Simple circuit B(Mt2015 q4b)
电路B可以用下面的仿真波形来描述:
Solution:
module top_module ( input x, input y, output z );
assign z = ~(x^y) ;
endmodule
容易发现,z是x和y的同或,而Verilog中只有异或(^),故同或用(~^)表示
3.1.1.12 Combine circuits A and B(Mt2015 q4)
本题用的子电路可以参考3.1.1.10和3.1.1.11.顶层设计包括子电路 A 和 B 的两个实例,如下所示。
Solution:
module top_module(
input x,
input y,
output z);
wire o1, o2, o3, o4;
A ia1 (x, y, o1);
B ib1 (x, y, o2);
A ia2 (x, y, o3);
B ib2 (x, y, o4);
assign z = (o1 | o2) ^ (o3 & o4);
// 或者你可以简化
// assign z = x|~y;
endmodule
module A (
input x,
input y,
output z);
assign z = (x^y) & x;
endmodule
module B (
input x,
input y,
output z);
assign z = ~(x^y);
endmodule
3.1.1.13 Ring or vibrate?(Ringer)
假设您正在设计一个电路来控制手机的响铃模式和震动模式。每当电话需要在来电时振铃(input ring),您的电路必须把响铃(output ringer = 1)和振动(output motor = 1)打开,但不能同时打开两者。如果手机处于震动模式(input vibrate_mode = 1),打开震动。否则打开响铃。
尝试只使用assign语句,看看是否可以将问题描述转化为逻辑门的集合。
设计提示:在设计电路时,人们经常不得不“向后”思考问题,从输出开始,然后反向到输入。这通常与人们对(顺序的、命令式的)编程问题的看法相反,在这种问题中,人们会先查看输入,然后再决定操作(或输出)。对于顺序程序,人们经常会想“如果(输入是 ___ )那么(输出应该是 ___ )”。另一方面,硬件设计人员通常认为“当(输入为 ___ )时(输出应为 ___ )”。
上面的问题描述是用适合软件编程的命令式形式写的(if ring then do this),所以你必须把它转换成更适合硬件实现的声明形式(assign ringer = ___)。能够思考并在两种风格之间进行转换是硬件设计所需的最重要技能之一。
期望的答案长度:2行
Hint:对于这个特殊问题,应该考虑“The motor is on when ___”,而不是“If (vibrate mode) then ___”。
Solution:
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
assign ringer = ~vibrate_mode & ring ;
assign motor = vibrate_mode & ring;
endmodule
3.1.1.14 Thermostat(Thermostat)
加热/冷却恒温器同时控制加热器(冬季)和空调(夏季)。实施一个电路,根据需要打开和关闭加热器、空调和鼓风机。
恒温器可以处于两种模式之一:加热(mode = 1)和冷却(mode = 0)。在制热模式下,太冷(too_cold = 1)时打开加热器,但不要使用空调。在制冷模式下,太热(too_hot = 1)时打开空调,但不要打开加热器。当加热器或空调打开时,还要打开风扇使空气流通。此外,用户还可以请求风扇开启(fan_on = 1),即使加热器和空调关闭。
尝试只使用assign语句,看看是否可以将问题描述转化为逻辑门的集合。
期望的答案长度:3行
Hint:在设计电路时,人们经常不得不“向后”思考问题,从输出开始,然后向后到输入
Solution:
module top_module(
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
// 提示:assign语句的顺序不影响实际综合的电路
// 风扇在heater或者aircon打开的时候打开,以及fan_on = 1 时打开
assign fan = heater | aircon | fan_on;
assign heater = (mode & too_cold);
assign aircon = (~mode & too_hot);
// * 不像实际的恒温器,这里没有“off”模式
endmodule
3.1.1.15 3-bit population count(Popcount3)
“人口计数”电路计算输入向量中“1”的数量。为 3 位输入向量构建人口计数电路。
Solution:
module top_module (
input [2:0] in,
output [1:0] out
);
// 这是3个输入的函数,一种方法是使用8项真值表
// 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]);
// 第二种方法:
// assign out = in[0]+in[1]+in[2];
// 第三种方法是在程序块(组合always块)中使用行为级描述,来直接实现真值表
/*
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
3.1.1.16 Gates and vectors(Gatesv)
你有一个4位输入向量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]。
Hint:both、any 和 different 输出分别使用双输入 AND、OR 和 XOR 运算。使用向量,这可以在 3 个assign语句中完成。
Solution:
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[3:1]&in[2:0];
assign out_any = in[3:1]|in[2:0];
assign out_different = in ^ {in[0],in[3:1]};
endmodule
3.1.1.17 Even longer vectors(Gatesv100)
另见较短的版本:3.1.1.17。
你有一个100位输入向量in[99:0],我们想知道每位与其邻位之间的关系:
- out_both:此输出向量的每一位都应指示相应的输入位及其左侧的邻居(较高索引)是否为“1”。例如,out_both[98] 应该表明 in[98] 和 in[99] 是否都为 1。由于 in[100] 左边没有邻居,所以答案很明显,所以我们不需要知道 out_both[100]。
- 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]。
Hint:使用assign语句,同样能在3个assign语句中完成
Solution:
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[98:0] | in [99:1];
assign out_different = in ^ {in[0],in[99:1]};
endmodule
本小节终于结束了,因为上周发生了很多事情,所以拖了很久qaq兜兜转转还是Verilog有意思