////////////////////////////////////////////////////////////////////////////////
///
/// Template for LSU EE 3755 Fall 2001 Homework 2
///

 /// Name:  


 /// Instructions:
  //
  // Copy this to a file named hw02sol.v to directory ~/hw in your
  // class account. (~ is your home directory.)  Use this
  // file for your solution.  Your entire solution should be in
  // this file, except for links to illustrations.
  //
  // Do not rename the modules in this file and be sure to use the
  // directory and filename given above.

  // Assignment: http://www.ece.lsu.edu/ee3755/2001f/hw02.pdf

////////////////////////////////////////////////////////////////////////////////


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

module uni_striped_c(us,v);
   input [31:0] v;
   output       us;

   // Solution goes here.
   
endmodule


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

module uni_striped_s(us,bit,clk,start);
   input bit, clk, start;
   output us;

   // Solution goes here.
   
endmodule

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

// Submit sketch of synthesized hardware on paper or put in
// a file named hw1.ps, hw1.pdf, hw1.gif, or hw1.png

module andyetanotherif(x,a);
   input [7:0] a;
   output      x;
   reg [7:0]   x;

   always @( a )
     begin
        
        x = a;

        if( a[0] ) 
          begin
             x = x + 2;
             if( a[1] & a[2] ) x = x + 1;
          end
        else
          begin
             if( a[3] ^ a[4] ) x = x + ( a >> 1 ); else x = x + ( a << 1 );
             x = 3 * x;
          end

        if( x[7] ) x = x - 1;

     end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Testbenches


module test_us_c();

   parameter stop_on_err = 1;

   reg [31:0] v;
   wire       us;
   reg        shadow_us;
   reg        last;
   reg [5:0]  upto;
   
   uni_striped_c uc(us,v);
   utility u();

   integer    errs;

   initial
     begin
        errs = 0;

        begin:LOOP forever begin

           u.iterator(v,upto,last);
           shadow_us = upto == 32;
           #1;

           if( us !== shadow_us ) begin

              $display("Vector %h us should = %d but output is = %d",
                       v,shadow_us,us);
              errs = errs + 1;
              if( stop_on_err ) $stop;

           end

           if( last ) disable LOOP;

        end end

        $display("Done with tests, %d errors found.",errs);
        
     end

endmodule

module test_us_s();

   parameter stop_on_err = 1;

   wire       us;
   reg        bit, clk, start;
   reg        shadow_us;
   reg        last;

   uni_striped_s uc(us,bit,clk,start);
   utility u();

   integer    errs;
   integer    pos;
   reg [5:0]  upto;
   reg [31:0] v;

   initial begin:C forever begin clk = 0; #5; clk = 1; #5; end end

   initial
     begin
        errs = 0;

        begin:LOOP forever begin

           u.iterator(v,upto,last);

           @( negedge clk );
           start = 1;

           for(pos=0; pos<32; pos=pos+1) begin

              bit = v[pos];
              shadow_us = pos < upto;

              @( negedge clk );
              start = 0;

              if( us !== shadow_us ) begin

                 $display("Vector %h us upto = %d but output is = %d at %d",
                          v,upto,us,pos);
                 errs = errs + 1;
                 if( stop_on_err ) $stop;
                 
              end

           end

           if( last ) disable LOOP;

        end end

        disable C;
        $display("Done with tests, %d errors found.",errs);
        
     end

endmodule


module utility();

   reg [31:0] v, vorig;
   reg        us, more;
   
   integer    width;
   integer    pos, b, bb, i;
   integer    errs;
   integer    still_us;

   function [31:0] make_us;
      input width;
      integer width;
      reg [31:0] v, m;
      integer we;

      if( width )
        begin
           v = ( 1 << width ) - 1;
           m = v | v << width;
           we = width;
           while( !m[31] )
             begin
                we = we * 2;
                v = v | v << we;
                m = m | m << we;
             end
           make_us = v;
        end
      else
        make_us = 0;

   endfunction

   function integer us_upto; // But not including.
      input [31:0] v;
      reg [31:0] true_v;
      integer width;
      integer upto;
      
      begin
         if( !v[0] ) 
           begin
              us_upto = 0;
           end
         else
           begin
              width = 0;
              while( v[width] )
                begin
                   width = width + 1;
                end
              true_v = make_us(width);
              for( upto = 0;
                   upto < 32 && v[upto] == true_v[upto];
                   upto = upto + 1 ) upto = upto;
              us_upto = upto;
           end
      end
      
   endfunction

   integer vi;
   parameter vs_size = 31 * ( 1 + 4 * 10 );
   reg [31:0] vs [0:vs_size];
   reg [5:0]  uptos [0:vs_size];
   integer    v_num;

   task iterator;
      output [31:0] v;
      output [5:0] upto;
      output last;

      begin
         v = vs[vi];
         upto = uptos[vi];
         vi = vi + 1;
         last = vi >= vs_size;
      end

   endtask
   
   initial
     begin
        still_us = 0;
        v_num = 0;
        vi = 0;
        
        for(width=1; width<32; width=width+1)
          begin
             
             vorig = make_us(width);
             v = vorig;

             if( us_upto(v) !== 32 )
               begin
                  $display("Testbench internal error: wrong upto for v %h",v);
                  $stop;
               end
             
             vs[v_num] = v;
             uptos[v_num] = 32;
             v_num = v_num + 1;

             for(bb=1; bb<5; bb=bb+1)
               begin
                  for(i=0; i<10; i=i+1)
                    begin
                       v = vorig;
                       for(b=0; b<bb; b=b+1)
                         begin
                            pos = $random & 31;
                            v[pos] = ~vorig[pos];
                         end
                       if( us_upto(v) == 32 ) begin 
                          v[0] = 0; still_us = still_us + 1; 
                       end

                       vs[v_num] = v;
                       uptos[v_num] = us_upto(v);
                       v_num = v_num + 1;
                       
                    end
               end
          end
        if( v_num !== vs_size )
          begin
             $display("Testbench internal error: wrong array size. %d %d",
                      v_num, vs_size);
          end
     end

endmodule