module M65C02_ClkGen(
    input   nRst,                       // External Reset Input (active low)
    input   ClkIn,                      // Reference Input Clk
    
    output  Clk,                        // Internal Clk - (M/D) x ClkIn
    output  Clk_UART,                   // 2x ClkIn
    output  Buf_ClkIn,                  // Buffered ClkIn
    
    output  reg Rst                     // Internal Reset
);

////////////////////////////////////////////////////////////////////////////////
//
//  Declarations
//

wire    DCM_Locked;             // DCM Locked Status Signal

reg     [3:0] DCM_Rst;          // Stretched DCM Reset (see Table 3-6 UG331)
reg     nRst_IFD;               // Input FF for external Reset signal
reg     [3:0] xRst;             // Stretched external reset (BufClkIn)
wire    Rst_M65C02;             // Combination of DCM_Rst and xRst
reg     [3:0] Rst_Dly;          // Stretched internal reset (BufClkIn)
wire    FE_Rst_Dly;             // Falling edge of Rst_Dly (Clk)

////////////////////////////////////////////////////////////////////////////////
//
//  Implementation
//

//  Implement internal clock generator using DCM and DFS. DCM/DFS multiplies
//  external clock reference by 4.

ClkGen  ClkGen (
            .USER_RST_IN(DCM_Rst[0]),           // DCM Rst generated on FE Lock 

            .CLKIN_IN(ClkIn),                   // ClkIn          = 14.7456 MHz
            .CLKIN_IBUFG_OUT(Buf_ClkIn),        // Buffered ClkIn = 14.7456 MHz

            .CLKFX_OUT(Clk),                    // DCM ClkFX_Out  = 58.9824 MHz 

            .CLK0_OUT(),                        // Clk0_Out unused 
            .CLK2X_OUT(Clk_UART),               // Clk2x_Out (FB) = 29.4912 MHz 
            
            .LOCKED_OUT(DCM_Locked)             // When 1, DCM Locked 
        );
      
//  Detect falling edge of DCM_Locked, and generate DCM reset pulse at least 4
//  ClkIn periods wide if a falling edge is detected. (see Table 3-6 UG331)
        
fedet   FE1 (
            .rst(1'b0),             // No reset required for this circuit 
            .clk(Buf_ClkIn),        // Buffered DCM input Clock
            .din(DCM_Locked),       // DCM Locked signal
            .pls(FE_DCM_Locked)     // Falling Edge of DCM_Locked signal
        );
        
always @(posedge Buf_ClkIn or posedge FE_DCM_Locked)
begin
    if(FE_DCM_Locked)
        DCM_Rst <= #1 4'b1111;
    else
        DCM_Rst <= #1 {1'b0, DCM_Rst[3:1]};
end

//  Synchronize asynchronous external reset, nRst, to internal clock and
//      stretch (extend) by 16 clock cycles after external reset deasserted
//
//  With Spartan 3A(N) FPGA family use synchronous reset for reset operations
//  per synthesis recommendations. so only these FFs will use asynchronous
//  reset, and the remainder of the design will use synchronous reset.

always @(posedge Buf_ClkIn or negedge DCM_Locked)
begin
    if(~DCM_Locked)
        nRst_IFD <= #1 0;
    else
        nRst_IFD <= #1 nRst;
end

always @(posedge Buf_ClkIn or negedge DCM_Locked)
begin
    if(~DCM_Locked)
        xRst <= #1 ~0;
    else
        xRst <= #1 {~nRst_IFD, xRst[2:1]};
end        

assign Rst_M65C02 = ((|{~nRst_IFD, xRst}) | ~DCM_Locked);

always @(posedge Buf_ClkIn or posedge Rst_M65C02)
begin
    if (Rst_M65C02)
        Rst_Dly <= #1 ~0;
    else
        Rst_Dly <= #1 {1'b0, Rst_Dly[3:1]};
end

//  synchronize Rst to DCM/DFS output clock (if DCM Locked)

fedet   FE2 (
            .rst(Rst_M65C02),       
            .clk(Clk),              // System Clock
            .din(|Rst_Dly),         // System Reset Delay
            .pls(FE_Rst_Dly)        // Falling Edge of Rst_Dly
        );

always @(posedge Clk or posedge Rst_M65C02)
begin
    if(Rst_M65C02)
        Rst <= #1 1;
    else if(FE_Rst_Dly)
        Rst <= #1 0;
end

endmodule