/*
 DCM variable phase adjustment controller. Allows to control DCM phase
 from a local bus register.
 
 $Id: dcm_ctrl.v,v 1.4 2009/08/29 19:51:59 dim Exp $
 $Date: 2009/08/29 19:51:59 $
 $Author: dim $
 $Revision: 1.4 $
 $Log: dcm_ctrl.v,v $
 Revision 1.4  2009/08/29 19:51:59  dim
 Converted to signed phase representation (-128 to 127 vs. 128 to 383)

 Revision 1.3  2009/06/04 05:36:18  dim
 Added condition to ack right away if DCM is unlocked

 Revision 1.2  2009/06/04 04:35:54  dim
 Moved ack generation to the end of phase shifting

 Revision 1.1.1.1  2009/02/05 07:20:51  dim
 Initial import

 Revision 1.2  2007/03/14 08:37:48  dim
 Gateware revision 1.01: first release of full iGp functionality

 Revision 1.1.1.1  2006/11/27 07:48:46  dim
 Initial import

*/

module dcm_ctrl(
	clk,	// Bus clock
	strobe,	// Bus strobe
	ce,	// Module select
	rd,	// Read/write direction
	ack,	// Bus ack
	din,	// Input data bus
	dout,	// Output data bus

	rst,	// DCM reset
	locked,	// DCM locked flag
	psclk,	// Phase shifter clock
	psen,	// Phase shifter enable
	psincdec, // Direction input
	psval,
	psdone	// Done flag
);
  // Inputs
  input clk, strobe, ce, rd, rst, psdone, locked;
  input [8:0] din;

  // Outputs
  output ack, psclk, psen, psincdec;
  output [31:0] dout;
  output [8:0] psval;
  
  // Wires 
  wire clk, strobe, ce, rst, psclk, psincdec_local;
  wire [8:0] din;
  wire [31:0] dout;
  
  // Registers
  reg ack = 1'b0, ack0 = 1'b0, psen = 1'b0, psincdec = 1'b0;
  reg [8:0] new = 9'h100;

  reg in_shift = 1'b0;
  reg [8:0] psval = 9'h100;

  assign psclk = clk;
  assign dout = {23'h0, ~psval[8], psval[7:0]};
  assign psincdec_local = (new > psval);

  always @(posedge clk) begin
    // On reset DCM goes to default delay
    if (rst) begin
      psval <= 9'h100;
//      new   <= 9'h100;
      psen  <= 1'b0;
      in_shift <= 1'b0;
    end
    if (strobe & ce & ~ack)
      if (~rd) begin
        new <= {~din[8], din[7:0]};
        ack0 <= 1'b1;
      end
      else
        ack <= 1'b1;
    if (ack) ack <= 1'b0;

    psincdec <= psincdec_local;

    // Phase shift state machine
    if (psval != new) begin
      if (~locked & ack0) begin
        ack <= 1'b1;
        ack0 <= 1'b0;
      end
      if (~in_shift & locked) begin
        psen <= 1'b1;
        in_shift <= 1'b1;
        psval <= (psincdec_local) ? psval + 9'h1 : psval - 9'h1;
      end
    end
    else if (ack0) begin
      // Done shifting, ack the bus
      ack0 <= 1'b0;
      ack  <= 1'b1;
    end
  
    if (psen) psen <= 1'b0;
    if (psdone) in_shift <= 1'b0;
  end
endmodule /* dcm_ctrl */
