/*
 CIC decimator with adjustable decimation factor and parameterized input
 data width. Enable signal allows single-shot or CW operation. On a rising
 edge of enable, integration starts (from the next clock cycle). If enable
 is set when integration is completed (dec_trigger is issued), CIC continues
 running, providing a CW mode of operation.
 
 Decimation factor "decim" is 27-bit wide, actual decimation is "decim+2". 
 Useful range is up to 2^27 (set "decim" to 2^27-2). Minimum value depends
 on the clk/usbclk rates. For clk at 125 MHz and usbclk at 50 MHz, minimum
 decimation is 15 (set "decim" to 13). Since this module is intended for
 polled scalar data acquisition, typical decimation factors will be much
 longer.

 Copyright (c) 2008 Dimtel, Inc., All Rights Reserved

 $Id: cic.v,v 1.2 2012/11/11 06:03:30 dim Exp $
 $Date: 2012/11/11 06:03:30 $
 $Author: dim $
 $Revision: 1.2 $
 $Log: cic.v,v $
 Revision 1.2  2012/11/11 06:03:30  dim
 Updates and fixes in 2009-2012 timeframe

 Revision 1.1.1.1  2009/06/02 20:26:02  dim
 Initial import


*/

`timescale 1ns/100ps

module cic #(parameter iwidth=14) (
  input clk,			// Signal processing clock
  input [iwidth-1:0] in,	// Signal
  input [26:0] decim,		// Decimation factor (N_d-2)
  input enable,			// Enable
  
  input usbclk,			// Local bus clock
  output reg [iwidth+26:0] out,	// Decimated output
  output reg strobe		// Data update strobe
);

  parameter IDLE = 1'b1; parameter INTEGRATING = 1'b0;
  reg state = IDLE;
  reg [27:0] dec_cntr = 28'b0;
  reg [iwidth+26:0] integrator = 0, diff = 0;
  wire [iwidth+26:0] delta;
  reg [iwidth+26:0] out_acq = 0;
  reg [3:0] sft = 4'b0;
  wire dec_trigger;
  
  reg [2:0] sft_clk;

  initial begin
    strobe <= 1'b0;
    out <= 32'b0;
  end

  /*
    Integrator state machine. We start in the IDLE state. If enable
    arrives, start integrating. When decimation is finished, we
    go back to idle state, unless enable is set.
  */
  always @(posedge clk) begin
    // CIC integrator
    integrator <= integrator + {{28{in[iwidth-1]}}, in};
    case (state)
      IDLE: 
        if (enable) begin
          state      <= INTEGRATING;
          diff       <= integrator;	// Save the current value at start
          dec_cntr   <= decim;
        end
      INTEGRATING: begin
        if (dec_trigger) begin
          dec_cntr <= decim;
          if (~enable)
            state    <= IDLE;
        end
        else
          dec_cntr <= dec_cntr - 27'b1;
      end
    endcase
    // Differentiator pipeline
    if (dec_trigger) begin
      diff <= integrator;
      out_acq <= delta;
      sft <= 12'b1111;
    end
    else
      sft <= {sft[2:0], 1'b0};
  end
  
  // Decimation trigger signal
  assign dec_trigger = dec_cntr[27];
  
  // CIC differentiator
  assign delta = integrator - diff;
  
  // Transfer to the local bus clock domain
  always @(posedge usbclk) begin
    sft_clk <= {sft_clk[1:0], sft[3]};
    if (~sft_clk[2] & sft_clk[1]) begin // Rising edge
      out <= out_acq;
      strobe <= 1'b1;
    end
    if (strobe) strobe <= 1'b0;
  end
endmodule // cic
