View Course Path

# Verilog code for Full Adder using Behavioral Modeling

After reading this post, you’ll be able to

1. Understand the full adder circuit.
2. Get familiar with behavioral style modeling in Verilog HDL.
3. Design a Full Adder circuit in Verilog using behavioral modeling.
4. Simulate the circuit using testbench and generate RTL schematics.

Contents

## What is a full adder?

The full adder is a digital circuit that performs the addition of three numbers. It is implemented using logic gates. A one-bit full adder adds three one-bit binary numbers (two input bits, mostly `A` and `B`, and one carry bit `Cin` being carried forward from previous addition) and outputs a sum and a carry bit.

A full adder can also be formed by using two half-adders and ORing their final outputs. A half adder adds two binary numbers. Since full adder is a combinational circuit, therefore it can be modeled in Verilog language.

Now, Verilog code for full adder circuit with the behavioral style of modeling first demands the concept and working of a full adder.

The logical expression for the two outputs sum and carry are given below. `A` `B` and `Cin` are the input variables for two-bit binary numbers and carry input and `S` and `Cout` are the output variables for Sum and Carry.

### Logical diagram with the expression:

S = A ⊕ B ⊕ Cin

Cout = A.B + B.C + C.A

OR

Cout = A & B | (A^B) & Cin

### Truth Table for Full Adder:

 A B Cin SUM (S) CARRY (Cout) 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1

## Methods of encoding a Full Adder using Behavioral Modeling

We’re modeling in behavioral style. We first need to analyze the truth table for the full adder. There are three inputs and two outputs to the full adder circuit.

Input: A, B, Cin

Output: S, Cout

The construct of Verilog behavioral modeling consists of three main parts:

1. Module declaration
2. Port list
3. Procedural statements
• The first and foremost task in Verilog coding is the declaration of the module. A `module`, being the functional block, describes a particular block in the digital system. Now module in Verilog is just like the function concept in C. It shows the input and output ports to a block.
`module module_name(port_list)`
• The port list contains the `input`, `output` and `inout` variables.
• Then comes the procedural statements; these statements are the assignment statements and are used to express the logical formulae.
• The end of a module is followed by `endmodule` keyword. These keywords are defined in Verilog IEEE 1134 standard.

The behavioral style mainly has two prominent statements. One is an `initial` statement which is executed only once and the other is `always` statement which gets executed once the sensitivity list gets enabled.

Well, if you’d look at the output of full adder, you’ll notice that the output changes whenever the input variable changes; there is no don’t care value in the input. To implement this, we’ll be using `always` statement. The syntax for `always` statement is:

```always

[timing_control]  procedural_statement```

Here the timing_control can be a delay control, wait for a certain time, or can be an event control, wait for an event to occur.

Procedural_statement consists of sequential block statements. The most commonly used are `begin``end`.

There are three different ways we can proceed with Verilog coding for full adder:

1. Using an always statement
2. Case statements
3. If-else statements

## Verilog code for full adder – Using always statement

This is the most general way of coding in behavioral style. What we do over here is; select the sensitivity list first, the change in which your output depends in almost every case, the input ports comprise the sensitivity list.

```always @(A or B or Cin)
begin
S = A ^ B ^ Cin;
Cout = A&B | (A^B) & Cin;
end```

Procedural statements inside this `always` block gets executed once there’s any change in event A, B OR Cin. Then comes the logical expression which will be assigned to the output registers S and Cout. Remember that the left-hand side entities must always be a reg (register) since registers are data storing elements.

So the final code is:

````timescale 1ns / 1ps module
full_adder( A, B, Cin, S, Cout);

input wire A, B, Cin;
output reg S, Cout;

always @(A or B or Cin)
begin
S = A ^ B ^ Cin;
Cout = A&B | (A^B) & Cin;
end
endmodule
```

## Verilog code for full adder – Using case statement

The `case` statement in Verilog is much similar to switch- case statement in C language. It is one of the procedural statements in Verilog. The expressions are executed once it fulfills the `case_expression` to its `case_item` value. If the `case_expression` doesn’t meet any of the `case_item` values, the default option is chosen at last.

```case (case_expression)

case_item1: procedural_expression;
case_item2: begin procedural_statements;
end
....
default: expression;

endcase```

The case_expression is evaluated first. Next, the case_item expressions are evaluated and compared in the given order. The set of statements that match the first true condition is executed.

For the full adder, we just try to write the statements according to the truth table; each row considering to be a case.

For instance, considering input 000 (A=0 B=0 Cin=0), the output is 00 (S=0 Cout=0)

`3'b000: `begin` S = 0; Cout = 0; `end``

After repeating this step for the rest of the inputs, we get the final code is:

````timescale 1ns / 1ps module
full_adder(input wire A, B, Cin, output reg S, output reg Cout);

always @(A or B or Cin)
begin

case (A | B | Cin)
3'b000: begin S = 0; Cout = 0; end
3'b001: begin S = 1; Cout = 0; end
3'b010: begin S = 1; Cout = 0; end
3'b011: begin S = 0; Cout = 1; end
3'b100: begin S = 1; Cout = 0; end
3'b101: begin S = 0; Cout = 1; end
3'b110: begin S = 0; Cout = 1; end
3'b111: begin S = 1; Cout = 1; end
endcase

end

endmodule```

Here, we are trying to give a value to the sum `S` and carry `Cout` for a particular input. Note the three inputs are considered here as a vector net. We can also treat the inputs individually, but that would make the code a bit lengthy.

## Verilog code for full adder – Using if-else statement

It is a conditional branching statement in Verilog. The format is:

```if(condition_1)
procedural_statement_1;

else if(condition_2)
procedural_statement_2;

else
procedural_statement_3;```

`if` condition_1 evaluates to a non- zero value, then the procedural_statement_1 is executed. If condition_2 evaluates to a value 0, X or Z, the procedural_statement_1 will not be executed, and an else branch, if it exists, is executed.

Now in behavioral modeling, we will construct each if-else block for a particular set of input and output. For example, if we consider the second row of truth table i.e. A = 0 B = 0 Cin = 0 and S = 0 Cout = 1 then it’s respective if-else block will look like this:

```else if(A==0 && B==0 && Cin==1)
begin
S=1;
Cout=0;
end```

Likewise, combining for the rest of the rows, we get the final Verilog code for full adder circuit using if-else statement:

````timescale 1ns / 1ps
module full_adder( A, B, Cin, S, Cout);

input wire A, B, Cin;
output reg S, Cout;

always @(A or B or Cin)
begin
if(A==0 && B==0 && Cin==0)
begin
S=0;
Cout=0;
end

else if(A==0 && B==0 && Cin==1)
begin
S=1;
Cout=0;
end

else if(A==0 && B==1 && Cin==0)
begin
S=1;
Cout=0;
end

else if(A==0 && B==1 && Cin==1)
begin
S=0;
Cout=1;
end

else if(A==1 && B==0 && Cin==0)
begin
S=1;
Cout=0;
end

else if(A==1 && B==0 && Cin==1)
begin
S=0;
Cout=1;
end

else if(A==1 && B==1 && Cin==0)
begin
S=0;
Cout=1;
end

else if(A==1 && B==1 && Cin==1)
begin
S=1;
Cout=1;
end

end

endmodule```

## Hardware Schematic for full adder

This is the hardware schematic for the design code that has been executed.

## Testbench for full adder in Verilog

For writing the testbench:

• We’ll first add the timescale directive. It starts with a grave accent ``` and does not end with a semicolon. Timescale directive is used for specifying the unit of time used in further modules and the time resolution (here one picosecond). The time resolution is the precision factor that determines the degree of accuracy of the time unit in the modules.
``timescale 1ns / 1ps`

Next is the `module` and variable declaration.

• The register (`reg`) type holds the value until a next value is being driven by the clock pulse onto it and is always under `initial` or `always` block. It is used to apply a stimulus to the input. Hence `A_input` `B_input` and `C_input` are declared as registers.
• Wires(`wire`) are declared for the variables which are passive in nature. Their values don’t change, and they can’t be assigned inside `always` and `initial` block. Hence sum `Sum` and carry `C_Output` variables are declared as wires.
```module top;
reg  A_input, B_input, C_input;
wire Sum, C_output;```

Then comes the module instantiation.

• The test bench applies stimulus to the Device Under Test DUT. To do this, the DUT must be instantiated under the testbench. The syntax for instantiation is given below. Port mapping is the linking of testbench’s modules with that of the design modules.
`name_of_module name_of_instance(port_map)`
• Now we’ll give an initial stimulus to the input variables. This is done under the `initial` block.
• We can also stop the simulation in a pre-mentioned delay time using `\$finish`.
``` initial
begin
A_input=0;
B_input=0;
C_input=0;
#100 \$finish;
end```

The additional thing over here is the use of two system tasks:

• `\$dumpfile` is used to dump the changes in the values of net and registers in a VCD file (value change dump file).
• `\$dumpvars` is used to specify which variables should be dumped in the file name specified by argument in the filename.
```initial
begin
A_input=0;
B_input=0;
C_input=0;
#100 \$finish;
end```
• Now, it depends on the user whether he wants to display the simulation result on the TCL console or not. I have used `\$monitor` which displays the value of the signal whenever its value changes.
• It is executed inside `always` block, and the sensitivity list remains the same as explained in the above section.
• The format specifier `%t` gives us the current simulation time and `%d` is used to display the value of the variable in decimal.
```always @(A_input or B_input or C_input)
\$monitor("At TIME(in ns)=%t, A=%d B=%d C=%d Sum = %d Carry = %d", \$time, A_input, B_input, C_input, Sum, C_output);```

Summing up the testbench code:

```//timescale directive
`timescale 1ns / 1ps
module top;

//declare testbench variables
reg  A_input, B_input, C_input;
wire Sum, C_output;

//instantiate the design module and connect to the testbench variables
full_adder instantiation(.A(A_input), .B(B_input), .Cin(C_input), .S(Sum), .Cout(C_output));

initial
begin
\$dumpfile("xyz.vcd");
\$dumpvars;

//set stimulus to test the code
A_input=0;
B_input=0;
C_input=0;
#100 \$finish;
end

//provide the toggling input (just like truth table input)
//this acts as the clock input
always #40 A_input=~A_input;
always #20 B_input=~B_input;
always #10 C_input=~C_input;

//display output if there’s a change in the input event
always @(A_input or B_input or C_input)
\$monitor("At TIME(in ns)=%t, A=%d B=%d C=%d Sum = %d Carry = %d", \$time, A_input, B_input, C_input, Sum, C_output);

endmodule```

## Simulation of Full Adder Circuit

The image below is the screenshot for the simulated design with the testbench.

## TCL Console Output

This is the final output on the console for user interaction.

## One thought on “Verilog code for Full Adder using Behavioral Modeling”

1. manoj kumar says: