Verilog Full Adder

The full adder is a digital component that performs three numbers an implemented using the logic gates. It is the main component inside an ALU of a processor and is used to increment addresses, table indices, buffer pointers, and other places where addition is required.

A one-bit full adder adds three one-bit binary numbers, two input bits, one carry bit, and outputs a sum and a carry bit.

A full adder is formed by using two half adders and ORing their final outputs. A half adder adds two binary numbers. The full adder is a combinational circuit so that it can be modeled in Verilog language.

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

Verilog Full Adder

Truth Table

ABCinCoutSum
00000
00101
01001
01110
10001
10110
11010
11111

Example

An example of a 4-bit adder is shown below, which accepts two binary numbers through the signals a and b.

An adder is a combinational circuit. Therefore Verilog can model it using a continuous assignment with assign or an always block with a sensitivity list that comprises all inputs.

Below code shows the uses an always block which gets executed whenever any of its inputs change value.

Hardware Schematic

Verilog Full Adder

Testbench

First, add the timescale directive. It starts with a grave accent ` but does not end with a semicolon. Timescale directive is used for specifying the unit of time used in further modules and the time resolution (one picosecond). The time resolution is the precision factor that determines the degree of accuracy of the time unit in the modules.

Next are the module and variable declaration.

  • The register (reg) type holds the value until the next value is 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.
  • Wires (wire) are declared for the passive variables. Their values don't change and can't be assigned them inside, always an initial block.

Then comes the module instantiation.

  • The test bench applies stimulus to the Device Under Test (DUT). The DUT must be instantiated under the testbench. Port mapping is the linking of testbench's modules with that of the design modules.
  • 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.

The different thing is the use of two system tasks:

  • $dumpfile is used to dump the changes in net and registers' values in a VCD file (value change dump file).
  • $dumpvars is used to specify which variables should be dumped in the file name specified by the filename argument.
  • Now, it depends on the user whether they want to display the simulation result on the TCL console or not. We used a $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.

When a and b add up to give a number more than 4 bits wide, the sum rolls over to zero and c_out becomes 1. For example, the line highlighted in yellow adds up to give 0x11 and the lower 4 bits get assigned to sum and bit#4 to c_out.