Circuits - Combinational Logic
文章目录
basic gates
1 wire
Implement the following circuit:
module top_module (
input in,
output out);
assign out = in;
endmodule
2 GND
module top_module (
output out);
assign out = 0;
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);
wire in1_in2_nor;
assign in1_in2_nor = ~ (in1 ^ in2 );
assign out = in3 ^ in1_in2_nor;
endmodule
6 more logic gates
There are 7 outputs, each with a logic gate driving it:
- 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
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
Create a module with the same functionality as the 7420 chip. It has 8 inputs and 2 outputs.
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 table
For a boolean function of N inputs, there are 2N possible input combinations. Each row of the truth table lists one input combination, so there are always 2N rows. The output column shows what the output should be for each input value.
number | x3 | x2 | x1 | f |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 0 |
2 | 0 | 1 | 0 | 1 |
3 | 0 | 1 | 1 | 1 |
4 | 1 | 0 | 0 | 0 |
5 | 1 | 0 | 1 | 1 |
6 | 1 | 1 | 0 | 0 |
7 | 1 | 1 | 1 | 1 |
The above truth table is for a three-input, one-output function. It has 8 rows for each of the 8 possible input combinations, and one output column. There are four inputs combinations where the output is 1, and four where the output is 0.
Create a combinational circuit that implements the above truth table.
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
wire [2:0] judge;
always @(*) begin
case ({x3,x2,x1})
3'b000: f = 0;
3'b001: f = 0;
3'b010: f = 1;
3'b011: f = 1;
3'b100: f = 0;
3'b101: f = 1;
3'b110: f = 0;
3'b111: f = 1;
default: f = 0;
endcase
end
endmodule
9 two-bit equality
Create a circuit that has two 2-bit inputs A[1:0]
and B[1:0]
, and produces an output z
. The value of z
should be 1 if A = B
, otherwise z
should be 0.
module top_module ( input [1:0] A, input [1:0] B, output z );
assign z = (A == B)? 1 : 0 ;
endmodule
10 simple circuit A
Module A is supposed to implement the function z = (x^y) & x
. Implement this module.
module top_module (input x, input y, output z);
assign z = ( x ^ y ) & x;
endmodule
11 simple circuit B
module top_module ( input x, input y, output z );
always @(*) begin
case ({x,y})
2'b00: z = 1;
2'b01: z = 0;
2'b10: z = 0;
2'b11: z = 1;
default: z = 0;
endcase
end
endmodule
12 combine circuits A and B
See mt2015_q4a and mt2015_q4b for the submodules used here. The top-level design consists of two instantiations each of subcircuits A and B, as shown below.
module top_module ( input x, input y, output z );
wire z1,z2,z3,z4;
wire z12or,z34and;
circuitA IA1 (x,y,z1);
circuitB IB1 (x,y,z2);
circuitA IA2 (x,y,z3);
circuitB IB2 (x,y,z4);
assign z12or = z1 | z2;
assign z34and = z3 & z4;
assign z = z12or ^ z34and;
endmodule
module circuitA ( input x, input y, output z );
assign z = ( x ^ y ) & x;
endmodule
module circuitB ( input x, input y, output z );
always @(*) begin
case ({x,y})
2'b00: z = 1;
2'b01: z = 0;
2'b10: z = 0;
2'b11: z = 1;
default: z = 0;
endcase
end
endmodule
13 Ringer
Suppose you are designing a circuit to control a cellphone’s ringer and vibration motor. Whenever the phone needs to ring from an incoming call (input ring), your circuit must either turn on the ringer (output ringer = 1) or the motor (output motor = 1), but not both. If the phone is in vibrate mode (input vibrate_mode = 1), turn on the motor. Otherwise, turn on the ringer.
Try to use only assign statements, to see whether you can translate a problem description into a collection of logic gates.
单纯用assign语句的方法:
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
assign motor = ring & vibrate_mode;
assign ringer = ring & ~vibrate_mode;
endmodule
使用always block的方法:
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
always @(*) begin
if (ring) begin
if (vibrate_mode) begin
motor = 1;
end
else
ringer = 1;
end
else begin
motor = 0;
ringer = 0;
end
end
endmodule
14 thermostat
A heating/cooling thermostat controls both a heater (during winter) and an air conditioner (during summer). Implement a circuit that will turn on and off the heater, air conditioning, and blower fan as appropriate.
The thermostat can be in one of two modes: heating (mode = 1
) and cooling (mode = 0
). In heating mode, turn the heater on when it is too cold (too_cold = 1
) but do not use the air conditioner. In cooling mode, turn the air conditioner on when it is too hot (too_hot = 1
), but do not turn on the heater. When the heater or air conditioner are on, also turn on the fan to circulate the air. In addition, the user can also request the fan to turn on (fan_on = 1
), even if the heater and air conditioner are off.
Try to use only assign
statements, to see whether you can translate a problem description into a collection of logic gates.
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 = heater | aircon | fan_on;
endmodule
15 Popcount3
A “population count” circuit counts the number of '1’s in an input vector. Build a population count circuit for a 3-bit input vector.
module top_module(
input [2:0] in,
output [1:0] out );
integer i;
always @(*) begin
out = 0;
for ( i = 0 ; i < 3 ; i++ ) begin
out = out + in[i];
end
end
endmodule
简化的写法:
module top_module(
input [2:0] in,
output [1:0] out );
assign out = in[0] + in[1] + in[2];
endmodule
16 Gates and Vectors
You are given a four-bit input vector in[3:0]. We want to know some relationships between each bit and its neighbour:
- out_both: Each bit of this output vector should indicate whether both the corresponding input bit and its neighbour to the left (higher index) are ‘1’. For example,
out_both[2]
should indicate ifin[2]
andin[3]
are both 1. Sincein[3]
has no neighbour to the left, the answer is obvious so we don’t need to knowout_both[3]
. - out_any: Each bit of this output vector should indicate whether any of the corresponding input bit and its neighbour to the right are ‘1’. For example,
out_any[2]
should indicate if eitherin[2]
orin[1]
are 1. Sincein[0]
has no neighbour to the right, the answer is obvious so we don’t need to knowout_any[0]
. - out_different: Each bit of this output vector should indicate whether the corresponding input bit is different from its neighbour to the left. For example,
out_different[2]
should indicate ifin[2]
is different fromin[3]
. For this part, treat the vector as wrapping around, soin[3]
's neighbour to the left isin[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[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
17 even longer vectors
You are given a 100-bit input vector in[99:0]. We want to know some relationships between each bit and its neighbour:
- out_both: Each bit of this output vector should indicate whether both the corresponding input bit and its neighbour to the left are ‘1’. For example,
out_both[98]
should indicate ifin[98]
andin[99]
are both 1. Sincein[99]
has no neighbour to the left, the answer is obvious so we don’t need to knowout_both[99]
. - out_any: Each bit of this output vector should indicate whether any of the corresponding input bit and its neighbour to the right are ‘1’. For example,
out_any[2]
should indicate if eitherin[2]
orin[1]
are 1. Sincein[0]
has no neighbour to the right, the answer is obvious so we don’t need to knowout_any[0]
. - out_different: Each bit of this output vector should indicate whether the corresponding input bit is different from its neighbour to the left. For example,
out_different[98]
should indicate ifin[98]
is different fromin[99]
. For this part, treat the vector as wrapping around, soin[99]
's neighbour to the left isin[0]
.
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
Multiplexers
1 Mux 2 to 1
Create a one-bit wide, 2-to-1 multiplexer. When sel=0, choose a. When sel=1, choose b.
module top_module(
input a, b, sel,
output out );
assign out = sel ? b : a ;
endmodule
2 Mux2to1v
Create a 100-bit wide, 2-to-1 multiplexer. When sel=0, choose a. When sel=1, choose b.
module top_module(
input [99:0] a, b,
input sel,
output [99:0] out );
assign out = sel ? b : a ;
endmodule
3 Mux9to1v
Create a 16-bit wide, 9-to-1 multiplexer. sel=0 chooses a, sel=1 chooses b, etc. For the unused cases (sel=9 to 15), set all output bits to ‘1’.
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)
4'b 0000: out = a;
4'b 0001: out = b;
4'b 0010: out = c;
4'b 0011: out = d;
4'b 0100: out = e;
4'b 0101: out = f;
4'b 0110: out = g;
4'b 0111: out = h;
4'b 1000: out = i;
default: out = '1;
//'1表示全部置1, '0 'x 'z同理
endcase
end
endmodule
4 Mux256to1
Create a 1-bit wide, 256-to-1 multiplexer. The 256 inputs are all packed into a single 256-bit input vector. sel=0 should select in[0]
, sel=1 selects bits in[1]
, sel=2 selects bits in[2]
, etc.
module top_module(
input [255:0] in,
input [7:0] sel,
output out );
assign out = in[sel];
endmodule
5 Mux256to1v
Create a 4-bit wide, 256-to-1 multiplexer. The 256 4-bit inputs are all packed into a single 1024-bit input vector. sel=0 should select bits in[3:0]
, sel=1 selects bits in[7:4]
, sel=2 selects bits in[11:8]
, etc.
module top_module(
input [1023:0] in,
input [7:0] sel,
output [3:0] out );
assign out = {in[4*sel+3],in[4*sel+2],in[4*sel+1],in[4*sel]};
endmodule
Arithmetic Circuits
1 Hadd
Create a half adder. A half adder adds two bits (with no carry-in) and produces a sum and carry-out.
module top_module(
input a, b,
output cout, sum );
assign {cout,sum} = a + b;
endmodule
2 Fadd
Create a full adder. A full adder adds three bits (including carry-in) and produces a sum and carry-out.
module top_module(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a + b + cin;
endmodule
3 Adder3
Now that you know how to build a full adder, make 3 instances of it to create a 3-bit binary ripple-carry adder. The adder adds two 3-bit numbers and a carry-in to produce a 3-bit sum and carry out. To encourage you to actually instantiate full adders, also output the carry-out from each full adder in the ripple-carry adder. cout[2] is the final carry-out from the last full adder, and is the carry-out you usually see.
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
Fadd fadd0 ( a[0], b[0], cin, cout[0], sum[0]);
Fadd fadd1 ( a[1], b[1], cout[0], cout[1], sum[1]);
Fadd fadd2 ( a[2], b[2], cout[1], cout[2], sum[2]);
endmodule
module Fadd(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a + b + cin;
endmodule
4 Adder
Implement the following circuit:
(“FA” is a full adder)
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
wire [3:0] cout;
Fadd fadd0 ( x[0], y[0], 0, cout[0], sum[0]);
Fadd fadd1 ( x[1], y[1], cout[0], cout[1], sum[1]);
Fadd fadd2 ( x[2], y[2], cout[1], cout[2], sum[2]);
Fadd fadd3 ( x[3], y[3], cout[2], cout[3], sum[3]);
assign sum[4] = cout[3];
endmodule
module Fadd(
input a, b, cin,
output cout, sum );
assign {cout,sum} = a + b + cin;
endmodule
一种简便的写法:
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum
);
// This circuit is a 4-bit ripple-carry adder with carry-out.
assign sum = x+y; // Verilog addition automatically produces the carry-out bit.
// Verilog quirk: Even though the value of (x+y) includes the carry-out, (x+y) is still considered to be a 4-bit number (The max width of the two operands).
// This is correct:
// assign sum = (x+y);
// But this is incorrect:
// assign sum = {x+y}; // Concatenation operator: This discards the carry-out
endmodule
5 Signed addition overflow
Assume that you have two 8-bit 2’s complement numbers, a[7:0] and b[7:0]. These numbers are added to produce s[7:0]. Also compute whether a (signed) overflow has occurred.
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
补码的溢出规律
补码的溢出可以视为两种情况:正溢出和负溢出
正溢出
两个正数相加,产生的进位1覆盖了结果的符号位,导致运算结果为负数
0100 + 0100 = 1000
负溢出
两个负数相加,导致符号位的1变为0。
1001+1010=(1)0011
6 Adder100
Create a 100-bit binary adder. The adder adds two 100-bit numbers and a carry-in to produce a 100-bit sum and carry out.
module top_module(
input [99:0] a, b,
input cin,
output cout,
output [99:0] sum );
assign {cout,sum} = a + b + cin;
endmodule
7 BCDadd4
You are provided with a BCD (binary-coded decimal) one-digit adder named bcd_fadd that adds two BCD digits and carry-in, and produces a sum and carry-out.
module bcd_fadd (
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
Instantiate 4 copies of bcd_fadd to create a 4-digit BCD ripple-carry adder. Your adder should add two 4-digit BCD numbers (packed into 16-bit vectors) and a carry-in to produce a 4-digit sum and carry out.
module top_module (
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire [3:0] c;
bcd_fadd fadd0( a[3:0], b[3:0], cin, c[0], sum[3:0] );
bcd_fadd fadd1( a[7:4], b[7:4], c[0], c[1], sum[7:4]);
bcd_fadd fadd2( a[11:8], b[11:8], c[1], c[2], sum[11:8]);
bcd_fadd fadd3( a[15:12], b[15:12], c[2], c[3], sum[15:12]);
assign cout = c[3];
endmodule
Karnaugh map to circuit
1 Kmap1
Implement the circuit described by the Karnaugh map below.
module top_module(
input a,
input b,
input c,
output out );
assign out = (a | b | c);
endmodule
2 Kmap2
Implement the circuit described by the Karnaugh map below.
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = ~a & ~d | ~b & ~c | ~a & b & c & d | a & c & d;
endmodule
3 Kmap3
Implement the circuit described by the Karnaugh map below.
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = a | ~a & ~b & c;
endmodule
4 Kmap4
Implement the circuit described by the Karnaugh map below.
module top_module(
input a,
input b,
input c,
input d,
output out );
always @(*) begin
case ({a,b,c,d})
4'b0100,4'b1000,4'b0001,4'b1101,4'b0111,4'b1011,4'b0010,4'b1110: out = 1;
default: out = 0;
endcase
end
endmodule
对逻辑式进行化简,可得:
out=a’bc’d’+ab’c’d’+a’b’c’d+abc’d+a’bcd+ab’cd+a’b’cd’+abcd’
=a’b(c⊙d)+ab’(c⊙d)+a’b’(c⊕d)+ab(c⊕d)
=(a⊕d)(c⊙d)+(a⊙d)(c⊕d)
=(a⊕d)⊕(c⊕d)
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = (a^b)^(c^d);
endmodule
5 Minimum SOP and POS
A single-output digital system with four inputs (a,b,c,d) generates a logic-1 when 2, 7, or 15 appears on the inputs, and a logic-0 when 0, 1, 4, 5, 6, 9, 10, 13, or 14 appears. The input conditions for the numbers 3, 8, 11, and 12 never occur in this system. For example, 7 corresponds to a,b,c,d being set to 0,1,1,1, respectively.
Determine the output out_sop in minimum SOP form, and the output out_pos in minimum POS form.
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 | d ) & ( ~b | d );
endmodule
6 Karnaugh Map
Consider the function f shown in the Karnaugh map below.
Implement this function. d is don’t-care, which means you may choose to output whatever value is convenient.
module top_module (
input [4:1] x,
output f );
assign f = ~x[1] & x[3] | x[1] & x[2] & ~x[3] & x[4];
endmodule
7 Karnaugh Map
Consider the function f shown in the Karnaugh map below. Implement this function.
(The original exam question asked for simplified SOP and POS forms of the function.)
module top_module (
input [4:1] x,
output f
);
assign f = ~x[2] & ~x[4] | ~x[1] & x[3] | x[1]& x[2] & x[3] & x[4];
endmodule
8 K-map implemented with a multiplexer
For the following Karnaugh map, give the circuit implementation using one 4-to-1 multiplexer and as many 2-to-1 multiplexers as required, but using as few as possible. You are not allowed to use any other logic gate and you must use a and b as the multiplexer selector inputs, as shown on the 4-to-1 multiplexer below.
You are implementing just the portion labelled top_module, such that the entire circuit (including the 4-to-1 mux) implements the K-map.
(The requirement to use only 2-to-1 multiplexers exists because the original exam question also wanted to test logic function simplification using K-maps and how to synthesize logic functions using only multiplexers. If you wish to treat this as purely a Verilog exercise, you may ignore this constraint and write the module any way you wish.)
module top_module (
input c,
input d,
output [3:0] mux_in
);
always @(*) begin
mux_in = '0;
case ({c,d})
2'b 00: mux_in[2] = 1;
2'b 01: mux_in[0] = 1;
2'b 11: begin
mux_in[0] = 1;
mux_in[3] = 1;
end
2'b 10: begin
mux_in[0] = 1;
mux_in[2] = 1;
end
endcase
end
endmodule