| 
    
       `timescale 1ns / 1ps
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // This module is a third order delta/sigma modulator
 
     | 
  
  
     | 
    
       // It uses no multiply only shifts by 1, 2 or 13
 
     | 
  
  
     | 
    
       // There are only 7 adders used, it takes around 110 LUTs
 
     | 
  
  
     | 
    
       module hq_dac
 
     | 
  
  
     | 
    
       (
 
     | 
  
  
     | 
    
         input         reset,
 
     | 
  
  
     | 
    
         input         clk,
 
     | 
  
  
     | 
    
         input         clk_ena,
 
     | 
  
  
     | 
    
         input  [19:0] pcm_in,
 
     | 
  
  
     | 
    
         output reg    dac_out
 
     | 
  
  
     | 
    
       );
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       // ============== Stage #1 ==============
 
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       wire [23:0] w_data_in_p0;
 
     | 
  
  
     | 
    
       wire [23:0] w_data_err_p0;
 
     | 
  
  
     | 
    
       wire [23:0] w_data_int_p0;
 
     | 
  
  
     | 
    
       reg  [23:0] r_data_fwd_p1;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // PCM input extended to 24 bits
 
     | 
  
  
     | 
    
       assign w_data_in_p0  = { {4{pcm_in[19]}}, pcm_in };
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Error between the input and the quantizer output
 
     | 
  
  
     | 
    
       assign w_data_err_p0 = w_data_in_p0 - w_data_qt_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // First integrator adder
 
     | 
  
  
     | 
    
       assign w_data_int_p0 = { {3{w_data_err_p0[23]}}, w_data_err_p0[22:2] } // Divide by 4
 
     | 
  
  
     | 
    
                            + r_data_fwd_p1;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // First integrator forward delay
 
     | 
  
  
     | 
    
       always @(posedge reset or posedge clk)
 
     | 
  
  
     | 
    
         if (reset)
 
     | 
  
  
     | 
    
           r_data_fwd_p1 <= 24'd0;
 
     | 
  
  
     | 
    
         else if (clk_ena)
 
     | 
  
  
     | 
    
           r_data_fwd_p1 <= w_data_int_p0;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       // ============== Stage #2 ==============
 
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       wire [23:0] w_data_fb1_p1;
 
     | 
  
  
     | 
    
       wire [23:0] w_data_fb2_p1;
 
     | 
  
  
     | 
    
       wire [23:0] w_data_lpf_p1;
 
     | 
  
  
     | 
    
       reg  [23:0] r_data_lpf_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Feedback from the quantizer output
 
     | 
  
  
     | 
    
       assign w_data_fb1_p1 = { {3{r_data_fwd_p1[23]}}, r_data_fwd_p1[22:2] } // Divide by 4
 
     | 
  
  
     | 
    
                            - { {3{w_data_qt_p2[23]}},  w_data_qt_p2[22:2] }; // Divide by 4
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Feedback from the third stage
 
     | 
  
  
     | 
    
       assign w_data_fb2_p1 = w_data_fb1_p1
 
     | 
  
  
     | 
    
                            - { {14{r_data_fwd_p2[23]}}, r_data_fwd_p2[22:13] }; // Divide by 8192
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Low pass filter
 
     | 
  
  
     | 
    
       assign w_data_lpf_p1 = w_data_fb2_p1 + r_data_lpf_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Low pass filter feedback delay
 
     | 
  
  
     | 
    
       always @(posedge reset or posedge clk)
 
     | 
  
  
     | 
    
         if (reset)
 
     | 
  
  
     | 
    
           r_data_lpf_p2 <= 24'd0;
 
     | 
  
  
     | 
    
         else if (clk_ena)
 
     | 
  
  
     | 
    
           r_data_lpf_p2 <= w_data_lpf_p1;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       // ============== Stage #3 ==============
 
     | 
  
  
     | 
    
       // ======================================
 
     | 
  
  
     | 
    
       wire [23:0] w_data_fb3_p1;
 
     | 
  
  
     | 
    
       wire [23:0] w_data_int_p1;
 
     | 
  
  
     | 
    
       reg  [23:0] r_data_fwd_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Feedback from the quantizer output
 
     | 
  
  
     | 
    
       assign w_data_fb3_p1 = { {2{w_data_lpf_p1[23]}}, w_data_lpf_p1[22:1] } // Divide by 2
 
     | 
  
  
     | 
    
                            - { {2{w_data_qt_p2[23]}},  w_data_qt_p2[22:1] }; // Divide by 2
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Second integrator adder
 
     | 
  
  
     | 
    
       assign w_data_int_p1 = w_data_fb3_p1 + r_data_fwd_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // Second integrator forward delay
 
     | 
  
  
     | 
    
       always @(posedge reset or posedge clk)
 
     | 
  
  
     | 
    
         if (reset)
 
     | 
  
  
     | 
    
           r_data_fwd_p2 <= 24'd0;
 
     | 
  
  
     | 
    
         else if (clk_ena)
 
     | 
  
  
     | 
    
           r_data_fwd_p2 <= w_data_int_p1;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       // =====================================
 
     | 
  
  
     | 
    
       // ========== 1-bit quantizer ==========
 
     | 
  
  
     | 
    
       // =====================================
 
     | 
  
  
     | 
    
       wire [23:0] w_data_qt_p2;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       assign w_data_qt_p2 = (r_data_fwd_p2[23]) ? 24'hF00000 : 24'h100000;
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       always @(posedge reset or posedge clk)
 
     | 
  
  
     | 
    
         if (reset)
 
     | 
  
  
     | 
    
           dac_out <= 1'b0;
 
     | 
  
  
     | 
    
         else if (clk_ena)
 
     | 
  
  
     | 
    
           dac_out <= ~r_data_fwd_p2[23];
 
     | 
  
  
     | 
    
       
     | 
  
  
     | 
    
       endmodule
 
     |