////////////////////////////////////////////////////////////////////////////////
///
/// Solution to LSU EE 3755 Fall 2001 Practice Midterm
///

// Practice Exam: http://www.ece.lsu.edu/ee3755/2001f/mtp.pdf
// Practice Exam Text Solution: http://www.ece.lsu.edu/ee3755/2001f/mtpsol.pdf


/// Problem 1

module cla_3sol(sum,a,b);
   input [2:0] a, b;
   output [3:0] sum;

   wire [2:0]   g, p, carry;
   
   assign       carry[0] = 1'b0;
   assign       carry[1] = g[0];
   assign       carry[2] = g[0] & p[1] | g[1];
   assign       sum[3] = g[0] & p[1] & p[2] | g[1] & p[2] | g[2];

   cla_slice s0(sum[0],g[0],p[0],a[0],b[0],carry[0]);
   cla_slice s1(sum[1],g[1],p[1],a[1],b[1],carry[1]);
   cla_slice s2(sum[2],g[2],p[2],a[2],b[2],carry[2]);

endmodule


/// Problem 2

module fp_flags(pos,zero,neg,int,single);
   input [31:0] single;
   output       pos, zero, neg, int;

   reg          int;
   reg          sign;
   reg [7:0]    exp;
   reg [22:0]   frac;

   reg          zero, pos, neg;

   reg [5:0] loc;
   integer   i;
   reg       found;
   
   always @( single ) begin

      sign = single[31];
      exp = single[30:23];
      frac = single[22:0];

      zero = !single[30:0];
      pos = !sign && !zero;
      neg = sign && !zero;

      found = 0;
      for(i=0; i<23; i=i+1) if( !found && frac[i] ) begin loc = i; found = 1; end
      if( !found ) loc = 23;

      int = zero || loc + exp >= 150;

   end
   
endmodule

module test_fp_flags();

   wire p, z, n, i;
   reg [31:0] s;
   real       shadow_s;
   
   fp_flags f(p,z,n,i,s);

   reg [63:0] d;

   task apply;
      input [31:0] value;
      input ep,ez,en,ei;

      begin

         s = value;
         #1;
         if( {ep,ez,en,ei} !== {p,z,n,i} ) begin
            $display("Wrong flags: pzni %b != %b for %h",
                     {ep,ez,en,ei}, {p,z,n,i},s);
            $stop;
         end

      end

   endtask

   initial begin

      apply(32'h3f8ccccd,1,0,0,0); // 1.1
      apply(32'h3f800000,1,0,0,1);
      apply(32'h4a08631c,1,0,0,1);
      apply(32'h4a08631e,1,0,0,0);
      apply(32'h42f6000d,1,0,0,0);
      apply(32'd0,0,1,0,1);
      apply(32'hca08631e,0,0,1,0);
      apply(32'h56e0910c,1,0,0,1);
      
   end

endmodule


/// Problem 3

module iloop(z,a);
   input [31:0] a;
   output       z;

   reg [4:0] i;
   reg       s, z;
   
   initial begin
      s = 0;
      // Since i is five bits it's impossible to represent 32 and so
      // "i<32" will always be true.  The problem can easily be fixed
      // by making i one bit larger.
      for(i=0; i<32; i=i+1) s = s | a[i];
      z = !s;
   end

endmodule


/// Problem 4

module add_1(sum,a,b,clk);
   input [31:0] a,b;
   input        clk;
   output       sum;

   reg [31:0]   sum;
   integer      i;
   reg          carry;

   always @( posedge clk )
     begin
        
        carry = 0;

        for(i=0; i<31; i=i+1) begin
      
           sum[i] = ~a[i] & ~b[i] &  carry |
                    ~a[i] &  b[i] & ~carry |
                     a[i] & ~b[i] & ~carry |
                     a[i] &  b[i] &  carry;

           carry = a[i] & b[i] | b[i] & carry | a[i] & carry;

        end

   end

endmodule


// This is a slightly streamlined version of the module in the exam
// text.

module add_2(sum,a,b,clk);
   input [31:0] a,b;
   input        clk;
   output       sum;
   
   reg [31:0] sum;
   reg [4:0]    i;
   reg          carry;

   always @( posedge clk )
     begin

        i = i + 1;
        if( i == 0 ) carry = 0;

        sum[i] = ~a[i] & ~b[i] &  carry |
                 ~a[i] &  b[i] & ~carry |
                  a[i] & ~b[i] & ~carry |
                  a[i] &  b[i] &  carry;

        carry = a[i] & b[i] | b[i] & carry | a[i] & carry;

     end

endmodule


/// Problem 5

module prefix_xor_4(x,a);
   input [3:0] a;
   output [3:0] x;

   assign       x[0] = a[0];

   xor x1(x[1],a[0],a[1]);
   xor x2(x[2],x[1],a[2]);
   xor x3(x[3],x[2],a[3]);

endmodule


/// Problem 6

module sums();

   reg [3:0] a, b, c;
   reg [5:0] d;

   initial begin

      a = 4'b0101;  b = 4'b0001;  c = a + b;  

      // Unsigned decimal: c =             Overflow?

      // Signed decimal:   c =             Overflow?
      

      a = -6; b = 4'b0001;  c = a + b;  

      // Unsigned decimal: c =             Overflow?

      // Signed decimal:   c =             Overflow?


      a = -6; b = 4'b0001;  c = a + b;  

      // Unsigned decimal: c =             Overflow?

      // Signed decimal:   c =             Overflow?


      a = 4'b1101; b = 4'b1100;  c = a + b;  

      // Unsigned decimal: c =             Overflow?

      // Signed decimal:   c =             Overflow?


      // Suppose c and d are for signed quantities.
      // Fix the assignment below.
      d = c;

   end

endmodule

module sums_sol();

   reg [3:0] a, b, c;
   reg [5:0] d;

   initial begin

      a = 4'b0101;  b = 4'b0001;  c = a + b;  

      // Unsigned decimal: c = 6           Overflow? No

      // Signed decimal:   c = 6           Overflow? No
      

      a = -6; b = 4'b0001;  c = a + b;  

      // Unsigned decimal: c = 11          Overflow? No

      // Signed decimal:   c = -5          Overflow? No


      a = 4'b1101; b = 4'b1100;  c = a + b;  

      // Unsigned decimal: c =  9          Overflow? Yes (finally)

      // Signed decimal:   c =  -7         Overflow? No


      // Suppose c and d are used for signed quantities.
      // Fix the assignment below.
      // Original assignment: d = c;
      d = {c[3],c[3],c};  // Fixed assignment with sign extension.

   end

endmodule


/// Problem 7


module to_str(x,s,a,b);
   input [1:0] s;
   input       a, b;
   output      x;

   assign x = s == 2 ? a : b;

endmodule


module is_structural(x,s,a,b);
   input [1:0] s;
   input       a, b;
   output      x;

   wire        a_path, b_path;
   wire        s_eq_2, s_ne_2;
   wire        not_s_0;

   or o1(x,a_path,b_path);

   and a1(s_eq_2,s[1],not_s_0);
   not n2(s_ne_2,s_eq_2);

   not n1(not_s_0,s[0]);

   and a2(a_path,s_eq_2,a);
   and a3(b_path,s_ne_2,b);

endmodule