/*
 DDS module with arbitrary integer ratio phase advance.

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

 $Id: dds.v,v 1.4 2012/09/25 21:02:39 dim Exp $
 $Date: 2012/09/25 21:02:39 $
 $Author: dim $
 $Revision: 1.4 $
 $Log: dds.v,v $
 Revision 1.4  2012/09/25 21:02:39  dim
 Fixed cos/sin swap, added phase output

 Revision 1.3  2010/10/05 16:13:49  dim
 Updates prior to iGp12 release

 Revision 1.2  2009/08/29 19:53:10  dim
 Added square wave mode

 Revision 1.1  2009/06/02 20:04:07  dim
 Initial import


*/

`timescale 1ns/100ps

module dds #(parameter width=14) (
  input clk,			// Signal processing clock
  
  input [width-1:0] amplitude,	// DDS amplitude
  input [16:0] advance,		// Phase advance (floor(M / N))
  input [11:0] mN,		// Period (-N)
  input [11:0] remainder,	// Phase remainder (M % N)
  
  output [width-1:0] sin,	// Sine output
  output [width-1:0] cos,	// Cosine output
  output reg [16:0] phase	// Phase output for PM/FM of other DDS
);
  reg [11:0] cnt   = 12'hfff;	// Modulo counter
  reg carry = 1'b0;		// Carry out from modulo

  initial
    phase <= 17'b0;

  always @(posedge clk) begin
    phase        <= phase + advance + carry;
    {carry, cnt} <= {1'b0, cnt} + {1'b0, (carry ? mN : 12'b0)} + {1'b0, remainder};
  end

  // Waveshape generation CORDIC (Z input is 1 wider than X/Y)
  cordic #(.width(width)) cordic(.clk(clk), .xin(amplitude), 
                .yin({width{1'b0}}), .zin(phase[16:16-width]),
                .xout(cos), .yout(sin), .zout());
endmodule // dds

// Take standard DDS and interpolate two phase steps per clock for 
// DDR output
module dds_ddr (
  input clk,			// Signal processing clock
  
  input square,			// Square wave mode
  input [13:0] amplitude,	// DDS amplitude
  input [16:0] advance,		// Phase advance (floor(M / N))
  input [11:0] mN,		// Period (-N)
  input [11:0] remainder,	// Phase remainder (M % N)
  input signed [15:0] vec_I,	// Interpolation I
  input signed [15:0] vec_Q,	// Interpolation Q
  
  output reg [13:0] ddr0,	// DDR phase 0
  output reg [13:0] ddr1	// DDR phase 1
);
  wire signed [13:0] sin, cos, ddr1_int;
  reg signed [29:0] prod_I = 30'b0, prod_Q = 30'b0;
  reg signed [30:0] sum = 31'b0;
  reg [13:0] pipe0 = 14'b0, pipe1 = 14'b0;

  wire [13:0] amp = square ? 14'd4900 : amplitude;

  dds #(.width(14)) dds(.clk(clk), .amplitude(amp), .advance(advance),
          .mN(mN), .remainder(remainder), .sin(sin), .cos(cos));
  
  always @(posedge clk) begin
    pipe0 <= cos;
    pipe1 <= pipe0;
    
    // Rotation products
    prod_I <= vec_I * cos;
    prod_Q <= vec_Q * sin;
    
    // Sum
    sum    <= prod_I + prod_Q;
  end
  
  sat #(.imsb(30), .omsb(28), .owidth(14)) sat(.ins(sum), .out(ddr1_int));
  
  always @(posedge clk) begin
    ddr0 <= square ? (pipe1[13] ? ~amplitude : amplitude) : pipe1;
    ddr1 <= square ? (ddr1_int[13] ? ~amplitude : amplitude) : ddr1_int;
  end

endmodule // dds_ddr

// Single-rate DDS with selectable sine/square wave output
module dds_sdr (
  input clk,			// Signal processing clock
  
  input square,			// Square wave mode
  input [13:0] amplitude,	// DDS amplitude
  input [16:0] advance,		// Phase advance (floor(M / N))
  input [11:0] mN,		// Period (-N)
  input [11:0] remainder,	// Phase remainder (M % N)
  
  output reg [13:0] dds_out		// DDS output
);
  wire signed [13:0] sin;

  wire [13:0] amp = square ? 14'd4900 : amplitude;

  dds #(.width(14)) dds(.clk(clk), .amplitude(amp), .advance(advance),
          .mN(mN), .remainder(remainder), .sin(sin));
  
  always @(posedge clk)
    dds_out <= square ? (sin[13] ? ~amplitude : amplitude) : sin;

endmodule // dds_sdr
