Verilog Full Adder Example


Full Adder

We will continue to learn more examples with Combinational Circuit - this time a full adder. A combinational circuit is one in which the present output is a function of only the present inputs - there is no memory. This is different from the sequential circuits that we will learn later where the present output is a function of not only the present input but also of past inputs/outputs as well.

Table: A one bit comparator



  Carry in     Input y     Input x     Carry out     Output A  
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 1 0
1 1 1 1 1


Let us look at the source code for the implemmentation of a full adder

fulladder.v
  1. /*
  2. Full Adder Module for bit Addition
  3. Written by referencedesigner.com
  4. */
  5. module fulladder
  6. (
  7. input x,
  8. input y,
  9. input cin,
  10.  
  11. output A,
  12. output cout
  13. );
  14.  
  15. assign {cout,A} = cin + y + x;
  16.  
  17. endmodule
  18.  
  19.  


The important statement to note is the assignment statement

assign {cout,A} = cin + y + x;

An left side of the assignemnt statement can contain a concatenation of scalar or vector. In this way it is possible in this case to assign the result of the adder to two bit vector. Notice how the vector array is formed using the curly bracket {cout,A}. The rightmost part of the vector {cout,A} , which is A in this case forms the LSB.

We will now add a test bench to confirm that the result is as expected. So here goes the test bench.
fulladdertb.v
  1. /*
  2. Full Adder Module for bit Addition
  3. Written by referencedesigner.com
  4. */
  5. `timescale 1ns / 100ps
  6.  
  7. module fulladdertb;
  8.  
  9. reg input1;
  10. reg input2;
  11. reg carryin;
  12.  
  13. wire out;
  14. wire carryout;
  15.  
  16.  
  17. fulladder uut (
  18. .x(input1),
  19. .y(input2),
  20. .cin(carryin),
  21. .A(out),
  22. .cout(carryout)
  23. );
  24.  
  25. initial
  26. begin
  27. input1 =0;
  28. input2 =0;
  29. carryin =0;
  30. #20; input1 =1;
  31. #20; input2 =1;
  32. #20; input1 =0;
  33. #20; carryin =1;
  34. #20; input2=0;
  35. #20; input1=1;
  36. #20; input2=1;
  37. #40;
  38. end
  39.  
  40.  
  41. initial
  42. begin
  43. $monitor("time = %2d, CIN =%1b, IN1=%1b, IN2=%1b, COUT=%1b, OUT=%1b", $time,carryin,input2, input1,carryout,out);
  44. end
  45.  
  46. endmodule


As usual we will compile the program with following commands
 

C:\iverilog -o output fulladder.v fulladdertb.v
C:\vvp output

 

time =  0, CIN =0, IN1=0, IN2=0, COUT=0, OUT=0
time = 20, CIN =0, IN1=0, IN2=1, COUT=0, OUT=1
time = 40, CIN =0, IN1=1, IN2=1, COUT=1, OUT=0
time = 60, CIN =0, IN1=1, IN2=0, COUT=0, OUT=1
time = 80, CIN =1, IN1=1, IN2=0, COUT=1, OUT=0
time = 100, CIN =1, IN1=0, IN2=0, COUT=0, OUT=1
time = 120, CIN =1, IN1=0, IN2=1, COUT=1, OUT=0
tme = 140, CIN =1, IN1=1, IN2=1, COUT=1, OUT=1


Notice that we have introduced a system variable $time as one of the parameters in the $monitor statement. This comes handy when looking at the data ( if that is not in graph). The system variable $time returns the current simulation time as a 64-bit integer.

Looking back at the code - the vector concatenation thing on the left hand side in the assignment statement
 

assign {cout,A} =  cin + y + x; 



Could be replaced by two assignment statements ( looking at the table in the top of the page and writing sum of products.
 

assign A =  ((~cin) & x &(~y)) | ((~cin) &(~x)&y ) | (cin &(~x) &(~y)) | (cin & x & y)     ;
assign cout = ((~cin) & x &y) | ((cin) &(~x)&y ) | (cin &(x) &(~y)) | (cin & x & y)  ;

If you look more closely, the full adder circuit can be simplified quite a bit, but will require intelligent mix of Exclusive OR gates when writing term for sum.



This will form the basis of one of the exercises below.
Exercise

1. Redo the full adder with Gate Level modeling. Run the test bench to make sure that you get the correct result.

2. Draw a truth table for full adder and implement the full adder using UDP.

3. Use the waveform viewer so see the result graphically.

Solution

Before looking at the solution, make sure you have given your efforts to solve it. Here are the solution codes.
  1. /*
  2. Full Adder Module for bit Addition
  3. Written by referencedesigner.com
  4. */
  5. module fulladder
  6. (
  7. input x,
  8. input y,
  9. input cin,
  10.  
  11. output A,
  12. output cout
  13. );
  14.  
  15. wire p,r,s;
  16. xor (p,x,y);
  17. xor (A,p,cin);
  18.  
  19. and(r,p,cin);
  20. and(s,x,y);
  21. or(cout,r,s);
  22.  
  23. endmodule
  24.  


  1. /*
  2. Full Adder Module for bit Addition
  3. Written by referencedesigner.com
  4. */
  5. module fulladder
  6. (
  7. input x,
  8. input y,
  9. input cin,
  10.  
  11. output A,
  12. output cout
  13. );
  14. addtable(A,cin,x,y);
  15. addcarry(cout,cin,x,y);
  16. endmodule
  17.  
  18. primitive addtable(out, cin, in1, in2);
  19. output out;
  20. input cin,in1,in2;
  21.  
  22. table
  23. // cin in1 in2 : out
  24. 0 0 0 : 0 ;
  25. 0 0 1 : 1;
  26. 0 1 0 : 1;
  27. 0 1 1 : 0;
  28. 1 0 0 : 1 ;
  29. 1 0 1 : 0;
  30. 1 1 0 : 0;
  31. 1 1 1 : 1;
  32.  
  33.  
  34.  
  35. endtable
  36. endprimitive
  37.  
  38.  
  39. primitive addcarry(cout,cin, in1, in2);
  40. output cout;
  41. input cin,in1,in2;
  42.  
  43. table
  44. // cin in1 in2 : cout
  45. 0 0 0 : 0 ;
  46. 0 0 1 : 0;
  47. 0 1 0 : 0;
  48. 0 1 1 : 1;
  49. 1 0 0 : 0 ;
  50. 1 0 1 : 1;
  51. 1 1 0 : 1;
  52. 1 1 1 : 1;
  53. endtable
  54. endprimitive
  55.  


Exercise

1. Extend the full bit adder so that it can add two 2 bit inputs in place of two 1 bit inputs. It will also have a carry in and a carry out.