// -----------------------------------------------------------------------------
// Copyright (c) 2011, ON Semiconductor.
// -----------------------------------------------------------------------------
// FILE NAME     : dig_sar_adc.v
// TYPE          : RTL
// AUTHOR        : Stephanie Cambounet
// AUTHORS EMAIL : Stephanie.Cambounet@onsemi.com
// -----------------------------------------------------------------------------
// RELEASE HISTORY
// VERSION DATE        AUTHOR                DESCRIPTION
//  1.0    2011-11-21  Stephanie Cambounet   Initial version
// -----------------------------------------------------------------------------
// KEYWORDS : 
// -----------------------------------------------------------------------------
// PURPOSE : 
// -----------------------------------------------------------------------------

/// to be scanned??

module dig_sar_adc (
input                reset_b,            // Master reset
input                clk,                // Input clock posedge
input                enable_conversion,
input                comp,
input [2:0]          holdb_delay,        // holdb programable timer: i2c 
input                holdb_timer_byp,    // bypass holdb_timer, use holdb_trigger
input                holdb_trigger,      // control falling edge of adc_holdb if timer bypassed 
input                holdb_clken,        // control of holdb timer speed
input                biconv,

output reg           startb,
output               data_valid,
output reg           busy,
output reg           DSW1,
output reg           DSW2,
output reg           DSW3,
output reg           DSW4,
output reg           DSW5,
output reg           DSW6,
output reg           DSW7,
output reg           vref_cal,
output reg [10:0]    adc_data           
);

/// ****************************************************************************
/// Declarations
/// ****************************************************************************
// Parameters
parameter IDLE             = 6'b0000001;
parameter HOLD             = 6'b0000010;
parameter SAR_OPERATION    = 6'b0000100;
parameter VALID_DATA_ON    = 6'b0001000;
parameter VALID_DATA_OFF   = 6'b0010000;
parameter ADC_RESETB       = 6'b0100000;

`define s_IDLE             state[0]
`define s_HOLD             state[1]
`define s_SAR_OPERATION    state[2]
`define s_VALID_DATA_ON    state[3]
`define s_VALID_DATA_OFF   state[4]
`define s_ADC_RESETB       state[5]    

`define ns_IDLE             next_state[0]
`define ns_HOLD             next_state[1]
`define ns_SAR_OPERATION    next_state[2]
`define ns_VALID_DATA_ON    next_state[3]
`define ns_VALID_DATA_OFF   next_state[4]
`define ns_ADC_RESETB       next_state[5]

// internal regs
reg  [5:0]     state;
reg  [5:0]     next_state;
reg  [3:0]     bit_cntr;
reg  [7:0]     holdb_timer;   
reg            conv_cnt;

// Internal Wires
//wire  [7:0]     holdb_half_delay;
wire  [7:0]     holdb_cal_delay;
reg   [7:0]     holdb_delay_int;


// -------------------------------------------------------------------------- 
//assign holdb_delay_int = (holdb_delay <= 8'd1) ? 8'd2 : holdb_delay;    // min holdb_delay prog = 2 => 3 cycles duration
//assign holdb_half_delay = (holdb_delay_int >> 1) + 1'b1;                // min vref_cal duration = 2 cycles

assign data_valid = `s_VALID_DATA_OFF;  


/// ****************************************************************************
/// Processes
/// ****************************************************************************
// -----------------------------------------------------------------------------
// resynchro
// -----------------------------------------------------------------------------
//enable resynchro: not necessary because synchronous with adc_dig

// -----------------------------------------------------------------------------
// FSM
// -----------------------------------------------------------------------------
always @ (posedge clk or negedge reset_b) begin
   if (!reset_b)
      state <= IDLE;
   else
      state <= next_state;
end

always @ (*) begin   
   next_state = state;
   
   case (state)
   
// IDLE
// --------------------------------------------------------------------------
   IDLE : begin
      if ( enable_conversion  || (biconv && conv_cnt)) begin        
         next_state = HOLD;  
      end
      else 
         next_state = IDLE;    
   end

// HOLD
// --------------------------------------------------------------------------
   HOLD : begin 
      if (( holdb_timer == 8'd1 && holdb_clken && !holdb_timer_byp ) || (holdb_trigger && holdb_timer_byp)) begin
//      if ( holdb_timer == 4'd1 ) begin      
            next_state = SAR_OPERATION;     
      end
      else begin
            next_state = HOLD;
      end
   end
 
// SAR_OPERATION
// --------------------------------------------------------------------------
   SAR_OPERATION : begin
      if (!startb && !(|bit_cntr)) begin    
         next_state = VALID_DATA_ON;
      end
      else
         next_state = SAR_OPERATION;
   end

// VALID_DATA_ON
// -------------------------------------------------------------------------- 
   VALID_DATA_ON : begin
         next_state = VALID_DATA_OFF;
   end

// VALID_DATA_OFF
// -------------------------------------------------------------------------- 
   VALID_DATA_OFF : begin
         next_state = ADC_RESETB;
   end
      
// ADC_RESETB
// -------------------------------------------------------------------------- 
   ADC_RESETB : begin
         next_state = IDLE;
   end

   default : next_state = IDLE;
  
   endcase
end


// -----------------------------------------------------------------------------
// sequencing signals: 
// -----------------------------------------------------------------------------
  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW1  <= 1'b0;
     end 
     else begin
        DSW1  <= `ns_HOLD; 
    end         
  end

   always @ (posedge clk or negedge reset_b) begin
      if (!reset_b) begin   
         vref_cal  <= 1'b0;
      end 
      else begin
//         vref_cal  <= `ns_HOLD & ((holdb_timer > holdb_half_delay) | (holdb_timer == 8'd0)); 
         vref_cal  <= `ns_HOLD & ((holdb_timer > holdb_cal_delay) | (holdb_timer == 8'd0)); 
    end         
   end
 

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW2  <= 1'b0;
     end 
     else begin
        DSW2  <= biconv & conv_cnt & 
//                ((`s_HOLD & (holdb_timer <= holdb_half_delay) & ~(holdb_timer == 8'd0 )) | (~(`s_IDLE) & ~(`ns_IDLE) & ~(`s_HOLD))); 
                ((`s_HOLD & (holdb_timer <= holdb_cal_delay) & ~(holdb_timer == 8'd0 )) | (~(`s_IDLE) & ~(`ns_IDLE) & ~(`s_HOLD))); 
    end         
  end

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW3  <= 1'b0;
     end 
     else begin
        DSW3  <= biconv & ~conv_cnt & ~(`ns_IDLE) & ~(`ns_HOLD); 
    end         
  end

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW4  <= 1'b0;
     end 
     else begin
        DSW4  <= biconv & `ns_HOLD & ~conv_cnt;
    end         
  end

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW5  <= 1'b0;
     end 
     else begin
        DSW5  <= biconv & conv_cnt & ~(`ns_IDLE);
    end         
  end

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW6  <= 1'b0;
     end 
     else begin
        DSW6  <= ~biconv | conv_cnt &  ~(`ns_IDLE) & ~(`ns_HOLD);
    end         
  end

  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        DSW7  <= 1'b0;
     end 
     else begin
        DSW7  <= ~biconv | ~conv_cnt & ~(`ns_IDLE) ;
    end         
  end


// -----------------------------------------------------------------------------
// conv_cnt: double conversion management
// -----------------------------------------------------------------------------
 always @ (posedge clk or negedge reset_b) begin
    if (!reset_b) begin   
       conv_cnt <= 1'b0;
    end 
    else begin
         if ( `s_ADC_RESETB && biconv ) begin        
            conv_cnt <= ~conv_cnt;
          end
   end         
end

// -----------------------------------------------------------------------------
// holdb_ timer: ADC data acquisition and storage
// -----------------------------------------------------------------------------
assign holdb_cal_delay = (holdb_delay <= 3'd2) ? ( holdb_delay_int >> 1) + 1'b1 : (holdb_delay_int - 8'd10);                

 always @ (*) begin
    case (holdb_delay )
        3'b000:  holdb_delay_int = 8'd3;      //  4   clock periods
        3'b001:  holdb_delay_int = 8'd7;      //  8  
        3'b010:  holdb_delay_int = 8'd15;     //  16  
        3'b011:  holdb_delay_int = 8'd31;     //  32
        3'b100:  holdb_delay_int = 8'd63;     //  64
        3'b101:  holdb_delay_int = 8'd95;     //  96
        3'b110:  holdb_delay_int = 8'd127;    //  128  
        3'b111:  holdb_delay_int = 8'd255;    //  256      
      endcase  
  end

 always @ (posedge clk or negedge reset_b) begin
    if (!reset_b) begin   
       holdb_timer <= 8'd0;
    end 
    else begin
        if (state == HOLD && !holdb_timer_byp ) begin    
          if ( holdb_clken ) begin
            if (holdb_timer == 8'b0) begin
               holdb_timer <= holdb_delay_int;      
            end
            else begin
               holdb_timer <= holdb_timer - 8'd1;
            end
          end
        end        
        else 
         holdb_timer <= 8'd0;
    end   
end       

// -----------------------------------------------------------------------------
// bit_cntr
// -----------------------------------------------------------------------------
always @ (posedge clk or negedge reset_b) begin
   if (!reset_b) begin   
      bit_cntr <= 4'd0;
   end 
   else begin 
      if ( `ns_SAR_OPERATION && `s_HOLD ) begin
         bit_cntr <= 4'd11;               //init to max value, 10 -> 11 for sign support
      end    
      else if(state == SAR_OPERATION) begin  
         if (!startb) begin
            if (bit_cntr == 4'd0) begin
               bit_cntr <= 4'd15;
            end
 //           else if (!first_cycle) begin
 //              bit_cntr  <= bit_cntr - 4'd1;
 //           end
            else 
               bit_cntr  <= bit_cntr - 4'd1;              
         end
      end 
   end   
end   

// -----------------------------------------------------------------------------
// startb
// -----------------------------------------------------------------------------
always @ (posedge clk or negedge reset_b) begin
   if (!reset_b) begin   
      startb <= 1'b1;
   end 
   else if (state == SAR_OPERATION) begin
      startb <= !startb;
   end
   else begin
         startb <= 1'b1;
   end      
end

// -----------------------------------------------------------------------------
// data
// -----------------------------------------------------------------------------
always @ (posedge clk or negedge reset_b) begin
   if (!reset_b) begin   
      adc_data <= 11'b00000000000;     
   end 
   else if (state == ADC_RESETB) begin
      adc_data <= 11'b00000000000;     
   end
   else if (state == SAR_OPERATION) begin     
      if (!startb) begin
         adc_data[bit_cntr] <= comp;      
         adc_data[bit_cntr -1] <= 1'b1;
      end
   end
   else  
   adc_data  <= adc_data ;       
end


// -----------------------------------------------------------------------------
// busy
// -----------------------------------------------------------------------------
  always @ (posedge clk or negedge reset_b) begin
     if (!reset_b) begin   
        busy  <= 1'b0;
     end 
     else if ( enable_conversion )        
        busy  <= 1'b1;
     else if ( data_valid )
        busy  <= 1'b0;
  end


`undef s_IDLE           
`undef s_HOLD          
`undef s_SAR_OPERATION  
`undef s_VALID_DATA_ON  
`undef s_VALID_DATA_OFF 
`undef s_ADC_RESETB     

`undef ns_IDLE          
`undef ns_HOLD         
`undef ns_SAR_OPERATION 
`undef ns_VALID_DATA_ON 
`undef ns_VALID_DATA_OFF
`undef ns_ADC_RESETB    

endmodule
