//-----------------------------------------------------------------------------
//  
//  Copyright (c) 2009 Xilinx Inc.
//
//  Project  : Programmable Wave Generator
//  Module   : dac_spi.v
//  Parent   : wave_gen
//  Children : None
//
//  Description: 
//     This module takes each sample generated by the sample generator and
//     sends it to the digital to analog converter (DAC) using the SPI
//     protocol. Each SPI cycle is 32 clocks long, consisting of an address,
//     command, and 16 bits of data (MSbit first). The DAC on the development
//     boards use only the most significant 12 out of the 16 bit samples, but
//     all 16 bits are transmitted.
//
//  Parameters:
//
//  Local Parameters:
//
//  Notes       : 
//
//  Multicycle and False Paths
//    None.
//
//

`timescale 1ns/1ps


module dac_spi (
  input             clk_tx,       // Clock input
  input             rst_clk_tx,   // Active HIGH reset - synchronous to clk_tx
  input             en_clk_samp,  // Last clk_tx phase of clk_samp
  input      [15:0] samp,         // Sample output
  input             samp_val,     // New sample is available
  // D to A converter outputs
  output            spi_clk_o,    // Clock for SPI - generated by DDR flop
  output reg        spi_mosi_o,   // SPI master-out-slave-in data bit
  output reg        dac_cs_n_o,   // Chip select for DAC
  output reg        dac_clr_n_o   // Active low clear
);


//***************************************************************************
// Parameter definitions
//***************************************************************************

//***************************************************************************
// Reg and Wire declarations
//***************************************************************************

  wire [31:0] data_to_send; // Data to serialize to the DAC

  reg         active;       // Indicates that this module is sending a seq

  reg         old_active;   // The value of active on the last clock

  reg  [4:0]  bit_cnt;      // Counts from 30 to 0
  
//***************************************************************************
// Code
//***************************************************************************

  // Generate dac_clr_n - asserted only when internal reset is asserted
  always @(posedge clk_tx)
  begin
    if (rst_clk_tx)
    begin
      dac_clr_n_o     <= 1'b0;
    end
    else
    begin
      dac_clr_n_o     <= 1'b1;
    end // if rst_clk_tx
  end // always 

  // We start a new sequence when samp_val is asserted, and this is the 
  // "active" phase (i.e. the last one) of clk_samp
  assign start_spi = samp_val && en_clk_samp;

  assign data_to_send   = {
    8'b0000_0000,      // Don't care
    4'b0011,           // Write to an Update (Power Up) ch, N
    4'b0000,           // Channel A
    samp               // The sample to send
  };

  // Generate the output
  always @(posedge clk_tx)
  begin
    if (rst_clk_tx)
    begin
      active       <= 1'b0;
      old_active   <= 1'b0;
      bit_cnt      <= 5'b00000;
      dac_cs_n_o   <= 1'b1;      // Active low
      spi_mosi_o   <= 1'b1;      // Idle at 1'b1
    end
    else
    begin
      old_active   <= active;
      if (!active)
      begin
        if (start_spi)
        begin
          active       <= 1'b1;             // Go active
          dac_cs_n_o   <= 1'b0;             // Set CS active
          spi_mosi_o   <= data_to_send[31]; // Send the first bit of the seq
          bit_cnt      <= 5'd30;            // We have already sent 31
        end // 
        else
        begin
          dac_cs_n_o   <= 1'b1;             // INACTIVE
          spi_mosi_o   <= 1'b1;
        end
      end
      else // we are currently active
      begin
        spi_mosi_o <= data_to_send[bit_cnt];
        if (bit_cnt == 5'b00000) // This is the last bit
        begin
          active  <= 1'b0;
        end
        else // Not the last bit
        begin
          bit_cnt <= bit_cnt - 1'b1;
        end
      end
    end // if rst
  end // always
  
  // Generate the SPI clock using the DDR flop
  
  out_ddr_flop out_ddr_flop_spi_clk_i0 (
    .clk     (clk_tx),
    .rst     (rst_clk_tx),
    .d_rise  (1'b0),
    .d_fall  (active || old_active),
    .q       (spi_clk_o)
  );


endmodule

