module comparator_sel_mask #
  (
   parameter         C_FAMILY                         = "virtex6", 
                       // FPGA Family. Current version: virtex6 or spartan6.
   parameter integer C_DATA_WIDTH                     = 4
                       // Data width for comparator.
   )
  (
   input  wire                    CIN,
   input  wire                    S,
   input  wire [C_DATA_WIDTH-1:0] A,
   input  wire [C_DATA_WIDTH-1:0] B,
   input  wire [C_DATA_WIDTH-1:0] M,
   input  wire [C_DATA_WIDTH-1:0] V,
   output wire                    COUT
   );
  
  
  /////////////////////////////////////////////////////////////////////////////
  // Variables for generating parameter controlled instances.
  /////////////////////////////////////////////////////////////////////////////
  
  // Generate variable for bit vector.
  genvar lut_cnt;
  
  
  /////////////////////////////////////////////////////////////////////////////
  // Local params
  /////////////////////////////////////////////////////////////////////////////
  
  // Bits per LUT for this architecture.
  localparam integer C_BITS_PER_LUT   = 1;
  
  // Constants for packing levels.
  localparam integer C_NUM_LUT        = ( C_DATA_WIDTH + C_BITS_PER_LUT - 1 ) / C_BITS_PER_LUT;
  
  // 
  localparam integer C_FIX_DATA_WIDTH = ( C_NUM_LUT * C_BITS_PER_LUT > C_DATA_WIDTH ) ? C_NUM_LUT * C_BITS_PER_LUT :
                                        C_DATA_WIDTH;
  
  
  /////////////////////////////////////////////////////////////////////////////
  // Functions
  /////////////////////////////////////////////////////////////////////////////
  
  
  /////////////////////////////////////////////////////////////////////////////
  // Internal signals
  /////////////////////////////////////////////////////////////////////////////
  
  wire [C_FIX_DATA_WIDTH-1:0] a_local;
  wire [C_FIX_DATA_WIDTH-1:0] b_local;
  wire [C_FIX_DATA_WIDTH-1:0] m_local;
  wire [C_FIX_DATA_WIDTH-1:0] v_local;
  wire [C_NUM_LUT-1:0]        sel;
  wire [C_NUM_LUT:0]          carry_local;
  
  
  /////////////////////////////////////////////////////////////////////////////
  // 
  /////////////////////////////////////////////////////////////////////////////
  
  generate
    // Assign input to local vectors.
    assign carry_local[0] = CIN;
    
    // Extend input data to fit.
    if ( C_NUM_LUT * C_BITS_PER_LUT > C_DATA_WIDTH ) begin : USE_EXTENDED_DATA
      assign a_local        = {A, {C_NUM_LUT * C_BITS_PER_LUT - C_DATA_WIDTH{1'b0}}};
      assign b_local        = {B, {C_NUM_LUT * C_BITS_PER_LUT - C_DATA_WIDTH{1'b0}}};
      assign m_local        = {M, {C_NUM_LUT * C_BITS_PER_LUT - C_DATA_WIDTH{1'b0}}};
      assign v_local        = {V, {C_NUM_LUT * C_BITS_PER_LUT - C_DATA_WIDTH{1'b0}}};
    end else begin : NO_EXTENDED_DATA
      assign a_local        = A;
      assign b_local        = B;
      assign m_local        = M;
      assign v_local        = V;
    end
    
    // Instantiate one carry and per level.
    for (lut_cnt = 0; lut_cnt < C_NUM_LUT ; lut_cnt = lut_cnt + 1) begin : LUT_LEVEL
      // Create the local select signal
      assign sel[lut_cnt] = ( ( ( a_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] &
                                  m_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] ) ==
                                ( v_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] &
                                  m_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] ) ) & ( S == 1'b0 ) ) |
                            ( ( ( b_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] &
                                  m_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] ) ==
                                ( v_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] &
                                  m_local[lut_cnt*C_BITS_PER_LUT +: C_BITS_PER_LUT] ) ) & ( S == 1'b1 ) );
    
      // Instantiate each LUT level.
      carry_and # 
      (
       .C_FAMILY(C_FAMILY)
      ) compare_inst 
      (
       .COUT  (carry_local[lut_cnt+1]),
       .CIN   (carry_local[lut_cnt]),
       .S     (sel[lut_cnt])
      ); 
      
    end // end for lut_cnt
    
    // Assign output from local vector.
    assign COUT = carry_local[C_NUM_LUT];
    
  endgenerate
  
  
endmodule