/////////////////////////////////////////////////////////////////////////////        
//  top_sin_wave.v       : DDS 电路实验参考代码                                         
//  author               : 杜伟韬                                                   
//  date                 : 2011-10-11                                               
/////////////////////////////////////////////////////////////////////////////        
//        中国传媒大学 广播电视数字化教育部工程研究中心（ECDAV）                    
//                     http://ecdav.cuc.edu.cn                                      
//  本设计功能                                        
//    生成不同频率的正弦波
//    输入：用户按键UP，DOWN
//    输出：2补码格式的波形
//    行为：以1MHz为步进，用户通过UP/DOWN按键生成1MHz～10MHz不同频率的正弦波
//
//  本设计用途                                                                      
//    1、 中国传媒大学 电子设计竞赛辅导培训教学参考设计                             
//    2、 数字工程中心 研究生电路设计课程教学参考设计                               
/////////////////////////////////////////////////////////////////////////////        
// 
//              实验作业：掌握DDS的原理，并且能够回答以下问题                                    
//
//   1、如何根据CLK频率和输入频率字来设定输出波形的频率                             
//   2、补码格式能够直接送给DAC么？为什么仿真工具里观察数据有多种选项，         
//      比如unsigned/hex/binary/signed decimal 等等                                 
//   3、如何自动生成波表ROM的verilog代码？                                          
//   4、如何调节ROM的地址空间容量和数据字长？调节这些参数有什么意义和代价？         
//   5、如何评价DDS输出波形的质量？                                                 
//
/////////////////////////////////////////////////////////////////////////////        
//              
//              中国传媒大学数字化工程中心 本科生创新实验项目
//
//  长期招募热爱电子设计的同学，欢迎本科生同学参与到数字化工程中心的科研项目       
//      
//      详情咨询：diansai@cuc.edu.cn 或 中国传媒大学综合楼6层 卢起斌老师            
//
/////////////////////////////////////////////////////////////////////////////        
// module top_sin_wave(), top level entity
/////////////////////////////////////////////////////////////////////////////        
module top_sin_wave(
  CLK       ,   // clock, posedge valid
  BUTUP     ,   // input button freq upward setting
  BUTDOWN   ,   // input button freq downward setting 
  BUTRST    ,   // reset button
  CLKOUT    ,   // clock output
  SINOUT    );  // DDS sine wave out, to DAC
input CLK;
input BUTUP, BUTDOWN, BUTRST;
output CLKOUT;
output[12-1:0]  SINOUT;

wire butup_W, butdown_W, butrst_W;
wire butup_no_jitter_W, butdown_no_jitter_W, butrst_no_jitter_W, rst_W;
wire [32-1:0] fqwd_W;
wire fwen_W;
wire dds_clkout_W;
wire [12-1:0]  dds_out_2c_W; // dds output in 2's complement format
// fpga board button is pull-up to VCC
assign butup_W     = ~BUTUP    ; 
assign butdown_W   = ~BUTDOWN  ;
assign butrst_W    = ~BUTRST   ;
assign rst_W = butrst_no_jitter_W | pu_rst_W;

powerup_reset U_PURST(
  .CLK       (CLK       ),   // clock   
  .RSTOUT    (pu_rst_W  ));  // power up reset

button_in_out U_BUTUP(
  .CLK      (CLK                ),   // clock
  .IN       (butup_W            ),   // input button signal
  .OUT      (butup_no_jitter_W  ));  // output button signal

button_in_out U_BUTDOWN(
  .CLK      (CLK                ),   // clock
  .IN       (butdown_W          ),   // input button signal
  .OUT      (butdown_no_jitter_W));  // output button signal

button_in_out U_BUTRST(
  .CLK      (CLK                ),   // clock
  .IN       (butrst_W           ),   // input button signal
  .OUT      (butrst_no_jitter_W ));  // output button signal

generate_freq_word U_GFQWD(
  .CLK       (CLK                   ),   // input clock
  .RST       (rst_W                 ),   // input reset 
  .BUTUP     (butup_no_jitter_W     ),   // input button upward
  .BUTDOWN   (butdown_no_jitter_W   ),   // input button downward
  .FQWD      (fqwd_W                ),   // output frequency word
  .FWEN      (fwen_W                ));  // output frequency word update enable

dds_core_sin U_DDS(
  .CLK      (CLK            ),   // clock, posedge valid
  .RST      (rst_W          ),   // reset, high level reset
  .FWEN     (fwen_W         ),   // frequency word update enable, high level enable
  .FWIN     (fqwd_W         ),   // input frequency word
  .CLKOUT   (dds_clkout_W   ),   // output clock
  .SINOUT   (dds_out_2c_W   ));  // sine signal output, 2's complement format

assign SINOUT = dds_out_2c_W;
assign CLKOUT = ~dds_clkout_W;

endmodule // module dds_core

/////////////////////////////////////////////////////////////////////////////        
// module generate_freq_word()
// read input button signal
// generate frequency word value and update enable signal  
/////////////////////////////////////////////////////////////////////////////        
module generate_freq_word(
  CLK       ,   // input clock
  RST       ,   // input reset 
  BUTUP     ,   // input button upward
  BUTDOWN   ,   // input button downward
  FQWD      ,   // output frequency word
  FWEN      );  // output frequency word update enable

parameter VAL_FREQ_BASE = 32'h051E_B851;  // 50MHz clock, 1MHz out wave freqword value
parameter VAL_FREQ_MAX  = (VAL_FREQ_BASE * 10);  // 50MHz clock, MAX 10MHz out wave freqword value

input CLK,RST;       
input BUTUP, BUTDOWN;
output [31:0] FQWD;      
output FWEN;      
// when push button will cause these DFFs 1 clock cycle high level  
reg butup_enR, butdown_enR; 
reg butup_d1R, butdown_d1R; 
reg [31:0] FQWD;      
reg FWEN;      
/////////////////////////////////////////////////////////////////////////////        
// pipeline align
// BUTUP        | butup_d1R    |    butup_enR   | FWEN
// BUTDOW       | butdown_d1R  |    butdown_enR | FQWD
/////////////////////////////////////////////////////////////////////////////        
always @ (posedge CLK or posedge RST) begin
  if(RST) begin
    butup_d1R   <= 1'b0; 
    butdown_d1R <= 1'b0; 
    butup_enR   <= 1'b0;    
    butdown_enR <= 1'b0; 
  end
  else begin
    butup_d1R   <= BUTUP    ; 
    butdown_d1R <= BUTDOWN  ;
    if((~butdown_d1R) && (BUTDOWN))
      butdown_enR <= 1'b1;
    else
      butdown_enR <= 1'b0;
    if((~butup_d1R) && (BUTUP))
      butup_enR <= 1'b1;
    else
      butup_enR <= 1'b0;
  end
end
always @ (posedge CLK or posedge RST) begin
  if(RST) begin
    FQWD <= VAL_FREQ_BASE;
    FWEN <= 1'b1;
  end
  else begin
    // BUTTON UP
    if(butup_enR &&(~butdown_enR)) begin
      if(FQWD == VAL_FREQ_MAX)
        FQWD <= VAL_FREQ_BASE;
      else
        FQWD <= FQWD + VAL_FREQ_BASE;
    end
    // BUTTON DOWN
    else if((~butup_enR) &&butdown_enR) begin
      if(FQWD == VAL_FREQ_BASE)
        FQWD <= VAL_FREQ_MAX;
      else
        FQWD <= FQWD - VAL_FREQ_BASE;
    end
    // no valid button push
    else begin
      FQWD <= FQWD;   // hold old value
    end
    FWEN <= (butup_enR || butdown_enR);
  end
end


endmodule
