/// Sample Code for LSU EE 4702-1 Spring 2001
///
/// Synthesizable Population Modules and Testbench
///
 /// Input:       a,  an 8-bit vector.
 /// Output:    pop, the number of 1's in a.

// All population modules are synthesizable.

// The pop_sequential modules are done in several ways (at least one
// Form 1, Form 2, and Form 3).  The comments next to the module
// describe the form and the characteristics of the module.


// Form 1, Combinational Logic.
//
`define xCOMB
`ifdef COMB
module pop_combinational(pop,a);
   input a;
   output pop;

   //  Number of gates :                     266
   //  data arrival time                                    3.59

   wire [7:0] a;
   reg [3:0]  pop;
   reg [7:0]  a_work;
   reg [3:0]  pop_work;
   integer    i;

   always @( a ) begin

      pop_work = 0;
      a_work   = a;

      for(i=0; i<8; i=i+1) 
        begin 
           pop_work = pop_work + a_work[0];
           a_work   = a_work >> 1;
        end

      pop = pop_work;

   end

endmodule
`endif

// Form 3, Implicit State Machine.  Performs one iteration per cycle,
// with additional cycles needed before and after the population count.
//
`define SEQ
`ifdef SEQ
// exemplar encoding gray
module pop_sequential(pop,rdy,a,clk);
   // Specify pin number (on chip) for clk.  (Not tested.)
   // exemplar attribute clk pin_number 1
   input a, clk;
   output pop, rdy;

   //  Number of gates :                     739
   //  clk                    : 294.7 MHz

   reg    rdy;
   wire [7:0] a;
   reg [3:0]  pop;
   reg [7:0]  a_work, a_copy;

   always @( posedge clk ) if( a_copy !== a ) @( posedge clk ) begin

      rdy    = 0;
      pop    = 0;
      a_work = a;
      a_copy = a;

      @( posedge clk );

      while( a_work ) begin
         @( posedge clk );
         pop = pop + a_work[0];
         a_work = a_work >> 1;

      end

      @( posedge clk );

      rdy = a_copy == a;

   end

endmodule
`endif

// Form 2.  Code uses an (explicit) state machine, one iteration per
// clock cycle.  This is the version written during the lecture.
//
`define xSEQ3
`ifdef SEQ3
module pop_sequential(pop,rdy,a,clk);
   input a, clk;
   output pop, rdy;


   reg    rdy;
   wire [7:0] a;
   reg [3:0]  pop;
   reg [7:0]  a_work, a_copy;

   reg        state;
   parameter  st_idle = 0;
   parameter  st_count = 1;

   always @( posedge clk )
     case( state )
       st_idle: 
         if( a_copy !== a ) begin
            rdy    = 0;
            pop    = 0;
            a_work = a;
            a_copy = a;
            state  = st_count;
         end

       st_count:
         begin
            pop = pop + a_work[0];
            a_work = a_work >> 1;

            if( !a_work ) begin
               rdy = a_copy == a;
               state = st_idle;
            end
         end
   endcase

endmodule
`endif

// Form 2.  Code does entire population count in one cycle.
//
`define xSEQ2
`ifdef SEQ2
module pop_sequential(pop,rdy,a,clk);
   input a, clk;
   output pop, rdy;

   reg    rdy;
   wire [7:0] a;
   reg [3:0]  pop;
   reg [7:0]  a_work, a_copy;

   always @( posedge clk ) if( a_copy !== a ) begin

      rdy = 0;
      pop = 0;
      a_work   = a;
      a_copy   = a;

      repeat( 8 ) begin
         pop = pop + a_work[0];
         a_work = a_work >> 1;
      end

      rdy = a_copy == a;

   end

endmodule
`endif

// Form 2.  Code uses an (explicit) state machine, one iteration per
// clock cycle.  This was prepared before the lecture.
//
`define xSEQE
`ifdef SEQE
module pop_sequential_expl(pop,rdy,a,clk);
   input a, clk;
   output pop, rdy;

   reg    rdy;
   wire [7:0] a;
   reg [3:0]  pop;
   reg [7:0]  a_work, a_copy;

   parameter  st_ready  = 0;
   parameter  st_loop   = 1;
   parameter  st_finish = 2;

   reg [1:0]  state, next_state;

   always @( posedge clk ) begin
      case( state )

        st_ready:
          if( a_copy !== a ) begin
             rdy    = 0;
             pop    = 0;
             a_work = a;
             a_copy = a;
             next_state = st_loop;
          end

        st_loop:
          if( a_work ) begin
             pop = pop + a_work[0];
             a_work = a_work >> 1;
          end else
            next_state = st_finish;

        st_finish:
          begin
             rdy = a_copy == a;
             next_state = st_ready;
          end

        default:
          begin
             next_state = st_ready;
             a_copy = 0;
             pop = 0;
          end

      endcase

      state = next_state;
   end

endmodule
`endif




// exemplar translate_off

module test_pop();

   wire [3:0] pc, psi, pse;
   integer    i;
   wire [7:0] a = i[7:0];
   integer    check;
   integer    popf;

   wire       rdy, rdye;
   reg        clk;

   function integer pop;
      input [7:0] a;
      begin
         pop = 0;
         while( a ) begin pop = pop + a[0]; a = a >> 1; end
      end
   endfunction

   initial clk = 0;
   always #2 clk = !clk;

   pop_combinational p_c(pc,a);
   pop_sequential p_si(psi,rdy,a,clk);
   pop_sequential_expl p_se(pse,rdye,a,clk);

   task checkp;
      input [3:0] p;
      input [159:0] name;

      if( p !== popf ) $display("%s has wrong value for %d, %h",name,a,p);
      
   endtask

   initial begin
      
      check = 0;
      i = 5;
      wait(!rdy);wait(rdy);
      wait(!rdye);wait(rdye);

      for(i=0; i<256; i=i+1)
        begin
           wait(!rdy); wait(!rdye);wait(rdy);wait(rdye);
           popf = pop(a);

           checkp(pc,"Combinational");
           checkp(psi,"Sequential Impl.");
           checkp(pse,"Sequential Expl.");

           check = check + popf;

        end // for (i=0; i<255; i=i+1)

      if( check != 256 * 4 ) begin
         $display("Incorrect check.");
         $stop;
      end

      $display("Done with tests.");
      $stop;
      
   end
   
endmodule
              
   
// exemplar translate_on