//
//						clkrec.v - Recover Clock for FSK/PSK
//
//					(C) Copyright 2008-2010 John B. Stephensen
//
// This Verilog source file and all its derivatives are licensed only for
// personal non-profit educational use in the Amateur Radio Service and
// the license is not transferrable. The information is provided as-is for
// experimental purposes and the author does not warranty its freedom
// from defects or its suitability for any specific application.
//
// This module examines samples coming from the FM demodulator and separates
// timing information from data. It assumes that the signal is oversampled and
// operates on 3 adjacent samples -- early, nominal and late. The magnitude of
// the difference between the early and nominal samples and the magnitude of
// the difference between the nominal and late samples is averaged over 8 sets
// of samples and made available for timing error correction.
//
// 34 slices are used and the maximum clock rate is 228 MHz.
//
// History:
//		5-15-10	generate two errors signals instead of one
//
module clkrec (
    input [7:0] din,		// input signal
	 input fv,				// final sample valid
    input iv,				// input valid
    output [7:0] dout,	// nominal sample
	 output [7:0] tout1,	// early timing error
	 output [7:0] tout2,	// late timing error
    output ov,				// output valid
    input clk,				// master clock and reset
	 input rst
    );
// internal signals
reg [7:0] d1,d2;	// two adjacent samples
wire [7:0] dif;	// difference between samples
wire [9:0] a0;		// first accumulator
reg [9:0] a1;		// second accumulator
reg [7:0] a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
wire [7:0] e0;		// 1st average error
reg [7:0] e1;		// 2nd average error
reg fv1,fv2;		// delayed final data valid flag
wire ce;				// accumulator and shift register clock enable
// calculate difference between input and 2 samples earlier
// use sample in between as data
always @ (posedge clk)
begin
	if (rst) fv1 <= 0; else fv1 <= fv & iv;	// delayed data valid creates timing
	if (rst) fv2 <= 0; else fv2 <= fv1;
	if (iv) d1 <= din;		// save last 2 samples
	if (iv) d2 <= d1;
end
assign dif = d1 - d2;		// measure slope
assign ce = (fv&iv)|fv1;	// enable accumulators and shift register for 2 clock cycles
addsub10s acc (
	.SUB(dif[7]),	// subtract negative number to get magnitude
	.A(a1),
	.B({dif[7],dif[7],dif}),	// 8->10 bits (8*128 = 1024)
	.CI(dif[7]),	// carry in is one for subtraction
	.CO(),
	.Q(a0),			// sum (first accumulator output)
	.CE(ce),			// accumulate when final value received
	.CLK(clk),
	.RST(rst)
	);
always @ (posedge clk)
begin
	if (rst) a1 <= 0;			// second accumulator
	else if (ce) a1 <= a0;
	if (ce) a2 <= a1[9:2];	// shift register
	if (ce) a3 <= a2;
	if (ce) a4 <= a3;
	if (ce) a5 <= a4;
	if (ce) a6 <= a5;
	if (ce) a7 <= a6;
	if (ce) a8 <= a7;
	if (ce) a9 <= a8; 
	if (ce) a10 <= a9;
	if (ce) a11 <= a10;
	if (ce) a12 <= a11;
	if (ce) a13 <= a12;
	if (ce) a14 <= a13;
	if (ce) a15 <= a14;
	if (ce) a16 <= a15; 
	e1 <= e0;	// second error
end
assign e0 = a0[9:2] - a16;
// connect outputs
assign dout = d2;		// nominal sample
assign ov = fv2;		// compensate for register delay
assign tout1 = e1;	// timing error
assign tout2 = e0;
endmodule
