//
//
// This is just a little demo of DDS.  It doesn't have any cool features
// or anything..
//
module dds (
   clk,
   reset,
   
   din,
   
   dout
);

parameter	W = 12;

input		clk;	// Primary clock.
input		reset;	// Synchronous reset.
input [W-1:0]	din;	// The "phase step".
output [W-1:0]	dout;	// Output of the phase accumulator register.

reg [W-1:0]	dout;

reg [W-1:0]	accum;	// Phas Accumulator

// Just output the accumulator...
always @(accum)
   dout <= accum;

// Specify the accumulator..   
always @(posedge clk) begin
   if (reset) accum <= 0;
   else begin
      accum <= accum + din;
   end
end

endmodule

// synopsys translate_off
module ddstest;

reg		clk;
reg		reset;
reg [11:0]	din;
wire [11:0]	dout;	
reg [7:0]	cosout;	

// Instantiate the DDS with 12-bits.
//
dds #(12) dds1 (.clk(clk),  .reset(reset),  .din(din),  .dout(dout));

// Here's our Cosine lookup table.
//
reg [7:0]	costable[0:4095];  // 4KBytes.

// DDS Phase Accumulator output simply indexes into the Cos lookup table.
//
always @(dout)
   cosout <= costable[dout];

// Main test thread.
//   
initial begin
   $readmemh ("cos.hex", costable); // See the PERL program 'generate_cos_table.pl'

   din = 12'h020; // Start at 16
   #500000;
   
   din = 12'h0D0; // A little faster.. 
   #500000;
   
   din = 12'h200; // Fairly fast.
   #500000;
   
   $finish;
end

// Let's clock it at 1 MHz
initial begin
   clk = 0;
   forever begin
      #500 clk = 1;
      #500 clk = 0;
   end
end

// Reset
initial begin
   reset = 1;
   #3500 reset = 0;
end

// Generate VCD file for viewing.
initial begin
   $dumpfile ("dds.vcd");
   $dumpvars (0,ddstest);   
end
endmodule

/*
//***  Here's the Perl program for your reference...
`ifdef WHEN_PERL_IS_A_SUBSET_OF_VERILOG
      #!/tools2/perl/bin/perl
      #
      #  Generate a file of cos data for use by a DDS simulation.
      #

      $n      = 4096;	# Number of data points
      $minval = 0;	# Smallest cos value.
      $maxval = 255;	# Largest cos value.

      $pi = 3.1415927;
      $t = 0;
      for ($i = 1; $i < $n; $i = $i + 1) {
         $value = ($maxval - $minval)/2 + (($maxval - $minval)/2)*cos($t);
         $value = int($value);
         printf "%x\n", $value;
         $t = $t + 2*$pi / $n;
      }
`endif
*/

[ [ ['module', 'dds', '(', [['clk'], ['reset'], ['din'], ['dout']], ')', ';'],
    [ ['parameter', ['W', '=', '12'], ';'],
      ['input', 'clk', ';'],
      ['input', 'reset', ';'],
      ['input', '[', ['W'], '-', '1', ':', '0', ']', 'din', ';'],
      ['output', '[', ['W'], '-', '1', ':', '0', ']', 'dout', ';'],
      ['reg', '[', ['W'], '-', '1', ':', '0', ']', ['dout'], ';'],
      ['reg', '[', ['W'], '-', '1', ':', '0', ']', ['accum'], ';'],
      [ 'always',
        ['@', '(', [['accum']], ')'],
        [[['dout'], '<=', ['accum']], ';']],
      [ 'always',
        ['@', '(', ['posedge', ['clk']], ')'],
        [ 'begin',
          [ [ 'if',
              ['(', ['reset'], ')'],
              [[['accum'], '<=', '0'], ';'],
              'else',
              [ 'begin',
                [[[['accum'], '<=', ['accum'], '+', ['din']], ';']],
                'end']]],
          'end']]],
    'endmodule'],
  [ ['module', 'ddstest', ';'],
    [ ['reg', ['clk'], ';'],
      ['reg', ['reset'], ';'],
      ['reg', '[', '11', ':', '0', ']', ['din'], ';'],
      ['wire', '[', '11', ':', '0', ']', ['dout'], ';'],
      ['reg', '[', '7', ':', '0', ']', ['cosout'], ';'],
      [ 'dds',
        ['#', '(', ['12'], ')'],
        [ ['dds1'],
          [ '(',
            ['.clk', '(', ['clk'], ')'],
            ['.reset', '(', ['reset'], ')'],
            ['.din', '(', ['din'], ')'],
            ['.dout', '(', ['dout'], ')'],
            ')']],
        ';'],
      [ 'reg',
        '[',
        '7',
        ':',
        '0',
        ']',
        ['costable', '[', '0', ':', '4095', ']'],
        ';'],
      [ 'always',
        ['@', '(', [['dout']], ')'],
        [[['cosout'], '<=', ['costable', '[', ['dout'], ']']], ';']],
      [ 'initial',
        [ 'begin',
          [ ['$readmemh', '(', '"cos.hex"', ['costable'], ')', ';'],
            [[['din'], '=', "12 'h 020"], ';'],
            [['#', '500000'], ';'],
            [[['din'], '=', "12 'h 0D0"], ';'],
            [['#', '500000'], ';'],
            [[['din'], '=', "12 'h 200"], ';'],
            [['#', '500000'], ';'],
            ['$finish', ';']],
          'end']],
      [ 'initial',
        [ 'begin',
          [ [[['clk'], '=', '0'], ';'],
            [ 'forever',
              [ 'begin',
                [ [['#', '500'], [[['clk'], '=', '1'], ';']],
                  [['#', '500'], [[['clk'], '=', '0'], ';']]],
                'end']]],
          'end']],
      [ 'initial',
        [ 'begin',
          [ [[['reset'], '=', '1'], ';'],
            [['#', '3500'], [[['reset'], '=', '0'], ';']]],
          'end']],
      [ 'initial',
        [ 'begin',
          [ ['$dumpfile', '(', '"dds.vcd"', ')', ';'],
            ['$dumpvars', '(', '0', ['ddstest'], ')', ';']],
          'end']]],
    'endmodule']]
