Combinational Logic
Updated 2019-04-03
Digital logic blocks consists of combinational logic and sequential logic.
Combinational logic blocks are based on combinational logic – where the output is a function of only current inputs. They have no memory or history of past operations or states. Thus combinational logic blocks are constructed using only boolean logic gates but not flip-flops (since FFs are used for storing memory).
Combination blocks are used for, but not limited to:
- 7-segment display
- Multiplexers
- Game logic
Basic Combinational Logic in Verilog
module MY_SYSTEM(A, B, C);
input A, B;
output C;
assign C = A ^ B;
endmodule
Use wire
if we want to connect intermediate signals:
module MY_SYSTEM_2(A, B, C);
input A, B;
output C;
wire S0, S1;
assign S0 = A & ~B;
assign S1 = ~A & B;
assign C = S1 | S0;
endmodule
Recipe to Create Combinational Components
- Determine the boolean equation for each output
- Write the boolena equation as concurrent signal/wire assignments.
Since all logic is stateless, the outputs change based on the changes in the inputs. We need to wrap these logic in an always
block along with the sensitivity list.
always @(/* sensitivity list */)
begin
/* combinational stements */
end
All input signals that are involved in the combinational logic are required to be in the sensitivity list.
module MY_AND(A, B, C);
input A, B;
output C;
reg C;
always @(A or B)
C = A & B;
endmodule
In this case, signal change events of A and B should cause C to be “re-evaluated” since we are essentially “reading” the signals A and B. Note that we used reg C
to declare a wire, not a register so that it could be used within the always
block.
In SystemVerilog we use logic
instead of reg
which is less confusing. In addition, we also use always_comb
block as it’s less ambiguous.
module MY_AND(A, B, C);
input logic A, B;
output logic C;
always_comb
C = A & B;
endmodule
Multiplexers
Multiplexers (MUX) are used to select one of the input bits to be carried over – or “decision making”. They are made of combinational logic.
Here is an example implemenation of a MUX in SystemVerilog:
Example
module mux(input [3:0] X, input [1:0] SW, output Y);
always_comb
case (SW)
2'b00: Y = X[0];
2'b01: Y = X[1];
2'b10: Y = X[2];
2'b11: Y = X[3];
endcase
endmodule
Here, we set the output based on the control input SW
.
Alternatively, we could also use if/else statements or other logic operators or conditional statements such as ?
.
Note that in this example provided, we covered all permutations/cases of the combinational logic in the always_comb
block. If we don’t want to write out all the cases either because it’s too much or too redundant, we could use default
:
module mux(input [3:0] X, input [1:0] SW, output Y);
always_comb
case (SW)
2'b01: Y = X[1];
2'b10: Y = X[2];
2'b11: Y = X[3];
default: Y = X[0];
endcase
endmodule
This means for any case not covered in the case statement, we will default Y = X[0]
.
Warning: failure to cover all cases could lead to the synthesizer interpreting the verilog code as logic with memory, and make inferred latches. This is not the desired hardware, which is not good.