////////////////////////////////////////////////////////////////////////////////
///
/// Solution to LSU EE 3755 Spring 2002 Homework 3
///

// Assignment:http://www.ee.lsu.edu/ee3755/2002/hw03.html

////////////////////////////////////////////////////////////////////////////////
/// Problem 1
///

module adder8(sum,a,b);
   input [7:0] a, b;
   output [8:0] sum;

   wire         p0, g0, p1, g1;

   adder4 a0(sum[3:0],p0,g0,a[3:0],b[3:0],1'b0);
   adder4 a1(sum[7:4],p1,g1,a[7:4],b[7:4],g0);

   assign       sum[8] = g0 & p1 | g1;

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Problem 2
///

 // Common problem:  Signals omitted from event control in always.
 //  For example, in the second always in the module below the
 //  following is an easy mistake to make (g0 missing):
 //      always @( p0 or p1 or g1 ) 

module adder4(sum,P,G,a,b,cin);
   input [3:0] a, b;
   input       cin;
   output [3:0] sum;
   output       P, G;
   reg          P, G;

   wire         p0, g0, p1, g1;

   adder2 a0(sum[1:0],p0,g0,a[1:0],b[1:0],cin);

   reg          c0;
   
   always @( cin or p0 or g0 ) c0 = cin & p0 | g0;
   
   adder2 a1(sum[3:2],p1,g1,a[3:2],b[3:2],c0);

   always @( p0 or p1 or g0 or g1 ) 
     begin
        P = p0 & p1;
        G = g0 & p1 | g1;
     end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Problem 3
///

 // Common mistake: P and G must not be computed using a carry out.

module adder2(sum,P,G,a,b,cin);
   input [1:0] a, b;
   input       cin;
   output [1:0] sum;
   output       P, G;

   wire         c0, c1;

   bfa bfa0(sum[0],c0,a[0],b[0],cin);
   bfa bfa1(sum[1],c1,a[1],b[1],c0);

   wire       p0 = a[0] | b[0];
   wire       p1 = a[1] | b[1];
   wire       g0 = a[0] & b[0];
   wire       g1 = a[1] & b[1];

   assign     P = p0 & p1;
   assign     G = g0 & p1 | g1;

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Module used in the solution.
///

module bfa(sum,cout,a,b,cin);
   input a,b,cin;
   output sum,cout;

   assign sum = a ^ b ^ cin;
   assign cout = a & b | b & cin | a & cin;

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Testbench
///

module test_add8();

   parameter stop_on_error = 1;
   parameter max_errs = 10;

   wire [8:0] sum;
   reg [7:0]  a, b;
   
   adder8 a8(sum,a,b);

   integer    i, err;
   reg [8:0]  shadow_sum;
   
   initial begin

      err = 0;

      for(i=0; i<='hffff; i=i+1) begin
         {a,b} = i;
         #1;

         shadow_sum = a + b;

         if( shadow_sum !== sum ) begin

            err = err + 1;

            if( err < max_errs ) 
              $display("FAIL: Wrong sum: 0x%h + 0x%h = 0x%h (correct) != 0x%h",
                       a, b, shadow_sum, sum);

            if( err == max_errs )
              $display("Maximum error message count reached.");

            if( stop_on_error ) $stop;
            
         end
                          
      end

      $display("Tests completed.");
      if( err == 0 )
        $display("PASS: No errors detected.");
      else
        $display("FAIL: %d errors.\n",err);

   end
   

endmodule