文章目录
- 一、基础门电路(Basic Gate)
- 1.gate
- 2.真值表
- 3.关于电路设计思路
- 4.门电路与向量
- 二、多路选择器(multiplexer)
- 1. 2-to-1 multiplexer (Mux2to1)
- 2. 9-to-1 multiplexer (Mux9to1v)
- 3. 256-to-1 multiplexer (Mux256to1)
- 4. 256-to-1 4-bit multiplexer (Mux256to1v)
- 三、运算电路(Arithmatic Circuits)
- 1.半加器 Half adder (Hadd)
- 2.全加器 Full adder (Fadd)
- 3.三位二进制加法器 3-bit binary adder(Adder3 )
- 4.有符号数相加溢出 Signed addition overflow
- 5.100bit的二进制的加法器
- 5.4-digit BCD adder
- 四、卡诺图转化电路(Karnaugh Map to Circuits)
- 1.卡诺图基础(Karnaugh Map)
- 最小项
- 卡诺图
- 化简卡诺图
- 2.卡诺图电路(Karnaugh Map Circuits)
- 1) 3-variable
- 2) 4-variable
- 3) 4-variable2
- 4) Minimum SOP and POS
- 5) K-map implemented with a multiplexer
- 总结
一、基础门电路(Basic Gate)
1.gate
out = ~(in1 | in2) //或非门
out = in1 & (~in2); //一个与门,但输入in2需要取反。
wire temp;
assign temp = in1 ^~ in2;
assign out = temp ^ in3; // 一个异或门,一个同或门
- 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
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);
2.真值表
从真值表合成电路,且仅限使用一组标准逻辑门,将如何构建电路呢?
本解析采用最小项之和的方法来构建电路图,最小项表达式为真值表中每一个对应函数值为1的输入变量,将上图真值表中函数值为1的最小项取出相加,便是函数最小项表达式。上图最小项表达式为:
assign f = (!x3 & x2) | (x3 & x1);
3.关于电路设计思路
硬件电路的编程与软件的变成是存在差异的,一般进行软件编程时,我们是先关注输入( if (input are _)),再关注输出( then (output are ))。而在硬件编程时,我们需要转变思维方式,在确保输出是正确的情况下,再思考输入。( The (output should be _) when (inputs are __))。
能够思考和转换两种风格是硬件设计所需的最重要技能之一。例:Ring or vibrate本题所述的要求十分适合以软件编程的命令形式来编写程序( if ring then do this ),所以我们需要试着来转变思维,用硬件的设计思路来编写该程序( assign ringer = )。
assign motor = ring & vibrate_mode;
assign ringer = ring & (!vibrate_mode);
4.门电路与向量
例:problem 58 有一个4bit输入的电路,我们需要了解4bit输入数据之间的关系。
- out_both: 输入的每一个bit均需要检测该bit位与其左侧(即高比特位)是否全为 ‘ 1 ’ 。 示例:
out_both[2]
应检测in[2]
与in[3]
是否均为 ‘ 1 ’ 。因为in[3]
为输入的最高位,故我们无需检测out_both[3]
- out_any: 输入的每一个bit均需要检测该bit位与其右侧(即低比特位)两者其中一个为 ‘ 1 ’ 。 示例:
out_any[2]
应检测in[2]
与in[1]
两者其中一个为 ‘ 1 ’ 。因为in[0]
为输入的最低位,故我们无需检测out_any[0]
- out_different: 输入的每一个bit均需要检测该bit位与其左侧(即高比特位)两者是否不同。 示例:
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);
assign out_both = {{in[3] & in[2]}, {in[2] & in[1]}, {in[1] & in[0]}};
assign out_any = {{in[3] | in[2]} , {in[2] | in[1]} , {in[1] | in[0]}};
assign out_different = {{in[0] ^ in[3]}, {in[3] ^ in[2]}, {in[2] ^ in[1]}, {in[1] ^ in[0]}};
endmodule
例:problem 59 有一个100bit( input [99:0] )输入的电路,我们需要了解4bit输入数据之间的关系。
- out_both输出是判断现有bit位与其左侧bit位是否均为 ‘1’,可以采用移位运算(片选)来实现
- out_any输出是判断现有bit位与右侧bit位两者间是否有一个为‘1’,也采用移位运算
- out_different输出同理,判断现有bit位与左侧bit位是否不同,唯一需要注意的是在此输出中题目要求将输入变为一个环,将in[0]与 in[99] 链接在一起了,此处可采用链接符 { in[0], in[99:1] }。该输出同样采用移位运算。
assign out_both = in[98:0] & in[99:1];
assign out_any = in[99:1] | in[98:0];
assign out_different = in ^ {in[0],in[99:1]};
二、多路选择器(multiplexer)
1. 2-to-1 multiplexer (Mux2to1)
module top_module(
input in1, in2, sel,
output out );
assign out = (sel) ? in1 : in2;
endmodule
2. 9-to-1 multiplexer (Mux9to1v)
always @(*)begin
case(sel)
4'd0:out = a;
4'd1:out = b;
4'd2:out = c;
4'd3:out = d;
4'd4:out = e;
4'd5:out = f;
4'd6:out = g;
4'd7:out = h;
4'd8:out = i;
default:out=16'hffff;
endcase
end
3. 256-to-1 multiplexer (Mux256to1)
这里我们可以根据题目的要求,结合选择运算符的特性实现。根据提示:选择运算符的 index 可以为变量,只要变量的位宽和向量的长度匹配即可。
所以我们直接将 sel ,这个变量,作为片选向量 in 的 index。
module top_module (
input [255:0] in,
input [7:0] sel,
output out
);
// Select one bit from vector in[]. The bit being selected can be variable.
assign out = in[sel];
//assign out = in >> sel;
endmodule
4. 256-to-1 4-bit multiplexer (Mux256to1v)
同上一题的区别在于,位宽从 1 位变到了 4 位。
module top_module (
input [1023:0] in,
input [7:0] sel,
output [3:0] out
);
// We can't part-select multiple bits without an error, but we can select one bit at a time,
// four times, then concatenate them together.
assign out = {in[sel*4+:3], in[sel*4+:2], in[sel*4+:1], in[sel*4+:0]};
// Alternatively, "indexed vector part select" works better, but has an unfamiliar syntax:
// assign out = in[sel*4 +: 4]; // Select starting at index "sel*4", then select a total width of 4 bits with increasing (+:) index number.
// assign out = in[sel*4+3 -: 4]; // Select starting at index "sel*4+3", then select a total width of 4 bits with decreasing (-:) index number.
// Note: The width (4 in this case) must be constant.
endmodule
本题如果延续上一题的思考方式: assign out = in[ sel*4+3 : sel*4 ]
; 但这个表达式不符合 Verilog 片选操作符的语法。片选多个比特的正确语法有两种:
assign out = in[sel*4 +: 4];
// 从sel*4
开始,选择比特序号大于sel*4
的 4 位比特,相当于[sel*4+3:sel*4]
assign out = in[sel*4+3 -: 4];
// 从 sel4+3 开始,选择比特序号小于 sel4+3 的 4位比特,相当于[sel*4+3:sel*4]
- 当然本身
in[ sel*4+3 : sel*4 ]
这样的语法是不能使用。
三、运算电路(Arithmatic Circuits)
1.半加器 Half adder (Hadd)
实现一个 2 进制 1bit 加法器,加法器将输入的两个 1bit 数相加,产生两数相加之和以及进位。
module top_module(
input a, b,
output cout, sum );
assign {cout,sum} = a + b;
endmodule
使用位连接符语法,省去显示的变量信号声明。
本题也可以先声明一个 2bit 宽度的变量用于接收相加的结果以及可能的进位,2 个 1bit 数相加可能产生一个 2bit 宽度的结果。将高位赋予 cout,低位赋予 sum。
2.全加器 Full adder (Fadd)
全加器与半加器的区别在于,除了将输入的两个 1bit 数相加之外,还累加来自前级的进位,产生相加之和以及进位。
module top_module(
input a, b, cin,
output cout, sum );
assign{cout,sum} = a + b + cin;
endmodule
一般全加器才是数字系统中广泛使用的加法器。这里的 1bit 全加器往往会并行构成更宽的全加器。
3.三位二进制加法器 3-bit binary adder(Adder3 )
本题中需要通过实例化 3 个全加器,并将它们级联起来实现一个位宽为 3 bit 的二进制加法器,加法器将输入的两个 3bit 数相加,产生相加之和以及进位。
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
adder U1(
.a(a[0])
,.b(b[0])
,.cin(cin)
,.cout(cout[0])
,.sum(sum[0])
);
adder U2(
.a(a[1])
,.b(b[1])
,.cin(cout[0])
,.cout(cout[1])
,.sum(sum[1])
);
adder U3(
.a(a[2])
,.b(b[2])
,.cin(cout[1])
,.cout(cout[2])
,.sum(sum[2])
);
endmodule
module adder(
input a, b, cin,
output cout, sum );
assign{cout,sum} = a + b + cin;
endmodule
4.有符号数相加溢出 Signed addition overflow
本题讨论的是有符号数相加的溢出问题中,需要实现一个 2 进制 8bit 有符号数加法器,加法器将输入的两个 8bit数补码相加,产生相加之和以及进位。
a[7] && b[7] && ~s[7]:
负数相减(补码相加)产生正数,判断溢出。
~a[7] && ~b[7] && s[7]:
正数相加产生一个负数,判断溢出。
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
); //
assign s = a + b;
assign overflow = ( a[7] && b[7] && ~s[7] ) || (~a[7] && ~b[7] && s[7]);
//正正相加,产生负数(正溢出
//负负相减,产生正数(负溢出
endmodule
5.100bit的二进制的加法器
题目要求我们创建一个100bit的二进制的加法器,该电路共包含两个100bit的输入和一个cin, 输出产生sum和cout。
本题和之前需要用generate
语句的题目很类似
module top_module(
input [99:0] a, b,
input cin,
output cout,
output [99:0] sum );
//直接相加赋值也可以
//assign {cout,sum} = a+b+cin;
wire [99:0] cout_temp;
//初始化第一个实例
full_adder fadd1(
.a(a[0]),
.b(b[0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[0])
);
genvar i ;
//循环生成99个实例
generate
for(i=1;i<100;i=i+1)
begin:genadder
full_adder fadd(
.a(a[i]),
.b(b[i]),
.cin(cout_temp[i-1]),
.cout(cout_temp[i]),
.sum(sum[i])
);
end
endgenerate
assign cout = cout_temp[99];
endmodule
module full_adder(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a+b+cin;
endmodule
5.4-digit BCD adder
题目给我们提供了一个BCD加法器名字为bcd_fadd, 输入为两个4bitBCD码,一个cin,产生输出为sum和cout。
且题目也说明需要我们例化4次bcd_fadd来得到一个4-digit的BCD加法器(共16bit), 同样产生sum和cout。
module bcd_fadd {
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
module top_module(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire [3:0] cout_temp;
//实例化4个bcd_fadd
bcd_fadd U1(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[3:0])
);
bcd_fadd U2(
.a(a[7:4]),
.b(b[7:4]),
.cin(cout_temp[0]),
.cout(cout_temp[1]),
.sum(sum[7:4])
);
bcd_fadd U3(
.a(a[11:8]),
.b(b[11:8]),
.cin(cout_temp[1]),
.cout(cout_temp[2]),
.sum(sum[11:8])
);
bcd_fadd U4(
.a(a[15:12]),
.b(b[15:12]),
.cin(cout_temp[2]),
.cout(cout_temp[3]),
.sum(sum[15:12])
);
assign cout = cout_temp[3];
endmodule
四、卡诺图转化电路(Karnaugh Map to Circuits)
1.卡诺图基础(Karnaugh Map)
最小项
最小项的定义:一个函数的某个乘积项包含了函数的全部变量,其中每个变量都以原变量或反变量的形式出现,且仅出现一次,则这个乘积项称为该函数的一个标准积项,通常称为最小项。
最小项的表示方法:通常mi用来表示最小项。
下标i的确定方式:把最小项中原变量记为1,反变量记为0,当变量顺序确定后,可以按顺序排列成一个二进制数,则与这个二进制数相对应的十进制数,就是这个最小项的下标i。
最小项的的相邻性:任何两个最小项如果他们只有一个因子不同,其余因子都相同,则称这两个最小项为相邻最小项。相邻的两个最小项之和可以合并一项,消去一个变量。 如:
卡诺图
- 一种描述逻辑函数特殊方格图。
- 每格代表一个最小项,上下左右相邻就具备相邻性。
- 有n个变量,最小项就有2^n 且卡诺图也由 2^n个格子构成。
例:画出逻辑函数的卡诺图(四变量)解:
化简卡诺图
卡诺图相邻性的特点保证了几何相邻两方格所代表的最小项只有一个变量不同。因此,若相邻的方格都为1(简称1格)时,则对应的最小项就可以合并。合并的结果是消去这个不同的变量,只保留相同的变量。这是图形化简法的依据。
综上所述,卡诺图具备以下特性:
卡诺图中两个相邻1格的最小项可以合并成一个与项,并消去一个变量。 卡诺图中四个相邻1格的最小项可以合并成一个与项,并消去两个变量。 卡诺图中八个相邻1格的最小项可以合并成一个与项,并消去三个变量。 ———————————————— 版权声明:本文为CSDN博主「Samplay」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:选择圈很重要
- 列出逻辑函数的最小项表达式,由最小项表达式确定变量的个数(如果最小项中缺少变量,应补齐)。
- 画出最小项表达式对应的卡诺图。
- 将卡诺图中的1格画圈,一个也不能漏圈,否则最后得到的表达式就会与所给函数不等;1格允许被一个以上的圈所包围。
- 圈的个数应尽可能得少。即在保证1格一个也不漏圈的前提下,圈的个数越少越好。因为一个圈和一个与项相对应,圈数越少,与或表达式的与项就越少。
- 按照2k个方格来组合(即圈内的1格数必须为1,2,4,8等),圈的面积越大越好。因为圈越大,可消去的变量就越多,与项中的变量就越少。
- 每个圈应至少包含一个新的1格,否则这个圈是多余的。 用卡诺图化简所得到的最简与或式不是唯一的。
————————————————
版权声明:本文为CSDN博主「Samplay」的原创文章,遵循CC 4.0BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
更多示例点击以上链接学习
2.卡诺图电路(Karnaugh Map Circuits)
1) 3-variable
assign out = a | b | c;
2) 4-variable
assign out = ~b&~c | ~a&~d | a&c&d | ~a&b&c;
3) 4-variable2
- 其中D为don’t care值。相当于X。可以一起圈。
assign out = a | (~b&c);
4) Minimum SOP and POS
- SOP(Sum of Product,最小项表达式(与或式):积之和) 最小项之和
- POS(Product of Sum,最大项表达式(或与式):和之积) 最大项之积
一个4输入a, b, c, d和一输出的逻辑电路,当输入为2, 7或15时,输出为1, 当输入为0, 1, 4, 5, 6, 9, 10,13, 或 14 时,输出为0,当输入为3,8,11或12时输出为任意值。举例来说,7对应输入abcd为0,1,1,1.
注意: 该电路的SOP和POS必须均为化简后的最小值
SOP圈法如下:
assign out_sop = c&d | ~a&~b&c ;
SOP圈法如下:
pos:最大项之积选择0或者d圈,圈法规则与最小项之和一致。圈完后进行取反求和,最后不同的圈进行求积操作
assign out_pos = c & (~a | b) & (~b | d);
5) K-map implemented with a multiplexer
根据题目给出的卡诺图,用一个4-1的多路选择器和尽可能多的2-1多路选择器来实现电路,不允许使用其他逻辑门,必须使用ab作为选择器的输入。
从图中所示,在ab为某一固定值的情况下,根据cd的输入不同,来选择输出。
例如当ab == 2’b00时, mux_in[0] 根据卡诺图所示应为 c | d,
当ab == 2’b01时, mux_in[1] 根据卡诺图所示为1’b0 ,
此处需注意mux_in[3:0], 一个高位低位的问题,不要搞反了。
module top_module (
input c,
input d,
output [3:0] mux_in
);
assign mux_in = {(c&d),(~d),1'b0, (c|d)};
endmodule
总结
学习了基础门电路,掌握了基础门电路的用法。
学习了多路选择器,在位宽较小的多路选择器中,我们可以使用 assign 语句,三元表达式,case 语句等。在位宽较宽的多路选择器中,需要根据需求灵活地使用位选择符,如in[sel*4+3 -: 4]
或者位连接符。
学习了运算电路,全加器是数字系统中广泛使用的加法器, 1bit 全加器往往会并行构成更宽的全加器。进一步掌握实例化模块和generate
语句的使用。
学习了卡诺图,掌握了卡诺图的原理和化简卡诺图的方法(SOP和POS),但是运用不是很熟练,在今后使用中会加深学习。