Circuits_Combinational Logic
1.Multiplexers 总结
2-to1 multiplexer & 1.2 2-to1 bus multiplexer
2路选择器比较简单,可以直接用 ?:进行选择。
9-to1 multiplexer
9选1的直接用case语句即可,值得注意的有两点
-
case语句中为了简便,可以用十六进制表示,相比二进制可以少写很多数字
-
对于case语句中没有提到的情况,一般用default写明,不过也可通过在always块中先赋初值来解决,如下所示:
always @(*)
begin
out = 'hFFFF;
case (sel)
...
endcase
end
module top_module(
input [15:0] a, b, c, d, e, f, g, h, i,
input [3:0] sel,
output [15:0] out );
always@(*)
begin
case(sel)
/* both is ok
4'b0000:out = a;
4'b0001:out = b;
4'b0010:out = c;
4'b0011:out = d;
4'b0100:out = e;
4'b0101:out = f;
4'b0110:out = g;
4'b0111:out = h;
4'b1000:out = i;
default:out = 'hFFFF;
*/
'h0:out = a;
'h1:out = b;
'h2:out = c;
'h3:out = d;
'h4:out = e;
'h5:out = f;
'h6:out = g;
'h7:out = h;
'h8:out = i;
default:out = 'hFFFF;
endcase
end
endmodule
Mux256to1
答案:
module top_module(
input [255:0] in,
input [7:0] sel,
output out );
assign out = in[sel];
endmodule
- 当case语句有很多的情况时,全部列出来就显得很不明智。这里就提供了一种讨巧的方法。直接sel和索引的一一对应关系,直接将sel当做索引。
Mux256to1v
然而,当你从上一题学到了这一讨巧的方法,想要依样画葫芦,写下
assign out = in [sel * 4 + 3:sel * 4];
编辑器会残酷的告诉你:NO!
这种讨巧的方法并不经常可行,原因是:
- 使用变量索引从向量中选择一位是可行的,因为综合器可以确定所选位的宽度是恒定的。
- 使用变量索引从向量中选择多位时不可行,因为综合器无法证明所选位的宽度是常数。
针对这个问题,有两种解决方法,一种是上一题讨巧方法的变种。不让我一起写,那我就分开写,再拼起来呗!
assign out = {in[sel*4+3], in[sel*4+2], in[sel*4+1], in[sel*4+0]};
另外一种是采用有些不习惯的表达,也就是Verilog-2001的更新提供的位切片(索引矢量部分选择)的语法,具体如下
assign out = in[4*sel+3 -: 4]; //起始:4*sel+3, “-:” 指往负方向,4表示4位,相当于[sel*4+3:sel*4]
assign out = in[4*sel +: 4]; //起始:4*sel-3, “+:” 指往正方向,4表示4位,相当于[sel*4+3:sel*4]
2.Arithmetic Circuits 总结
3-bit binary adder & 4-digit BCD adder
这两题有以下共同点:
1.a和b的位数均大于1,因此在实例化的时候要注意输入和输出的位宽,比如
bcd_fadd u1_fadd(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[3:0])
);
2.要进行循环例化。注意不能直接用for,而要用generate语句搭配for循环。注意写的时候注意别漏了begin-end块的名字
generate
genvar i;
for(i=4;i<16;i=i+4)
begin:fadder
bcd_fadd u1_fadd(
.a(a[i+3:i]),
.b(b[i+3:i]),
.cin(cout_temp[i-4]),
.cout(cout_temp[i+3:i]),
.sum(sum[i+3:i]));
end
endgenerate
最后附上代码
//3-bit binary adder
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
fadd u1_fadd(
.a(a[0]),
.b(b[0]),
.cin(cin),
.cout(cout[0]),
.sum(sum[0])
);
generate //多个例化不可只用for,要用generate
genvar i;
for(i=1;i<3;i=i+1)
begin:adder //注意别漏了模块名
fadd u2_fadd(
.a(a[i]),
.b(b[i]),
.cin(cout[i-1]),
.cout(cout[i]),
.sum(sum[i])
);
end
endgenerate
endmodule
module fadd(input a,b,cin,
output cout,sum);
assign {cout,sum}=a+b+cin;
endmodule
//4-digit BCD adder
module top_module(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire [15:0] cout_temp;
bcd_fadd u1_fadd(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[3:0])
);
generate
genvar i;
for(i=4;i<16;i=i+4)
begin:fadder
bcd_fadd u1_fadd(
.a(a[i+3:i]),
.b(b[i+3:i]),
.cin(cout_temp[i-4]),
.cout(cout_temp[i+3:i]),
.sum(sum[i+3:i]));
end
endgenerate
assign cout = cout_temp[12];
endmodule
Karnaugh Map to Circuit
Minimum SOP & POS
一个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.
module top_module (
input a,
input b,
input c,
input d,
output out_sop,
output out_pos
);
assign out_sop = (c & d) | (~a & ~b & c);
assign out_pos = c & (~a | ~c | d)&( ~b | ~c | d);
endmodule
解析:
- SOP,按照卡诺图的原则,把1和x圈起来(如上图红圈),写出即可得出答案;
- POS,把0圈起来(看黑圈),写出表达式。注意,此时是Y’,写成Y形式即可
关于什么是SOP和POS,也就是最小项之和,最大项之积,大家可以参考下面这篇。
https://blog.51cto.com/physic/1305570