Attention

This documentation is a work in progress. Expect to see errors and unfinished things.

phase_diff Source File

 1`timescale 1ns / 1ns
 2
 3// DMTD measurement of clock phasing
 4module phase_diff #(
 5     // Default parameters tuned for LCLS-II LLRF Digitizer,
 6     // where unknown clocks are 94.286 MHz and sampling clock is 200 MHz.
 7     parameter order1=1,
 8     parameter order2=1,
 9     parameter dw=14,
10     parameter adv=3861,
11     parameter delta=16
12
13) (
14     input uclk1,  // unknown clock 1
15     input uclk2,  // unknown clock 2
16     input uclk2g,
17     input sclk,   // sampling clock
18     input rclk,   // readout clock (data transfer, local bus)
19     output err,
20     // the following are in rclk domain
21     output [dw-2:0] phdiff_out,
22     output [dw-1:0] vfreq_out,
23     output err_ff
24);
25// For the default dw=14 case, the previous 32-bit status word
26// (fully in the rclk domain) can be constructed externally as
27//   wire [31:0] status_out = {err_ff, vfreq_out, 4'b0, phdiff_out};
28//   32                     =  1     + 14       + 4   + 13
29
30// XXX vfreq_out could have extra msbs added by unwrapping, or better still,
31// adding higher-order bits to phaset.
32
33// Two phase trackers
34wire [dw-1:0] phaset_out1, phaset_out2;
35wire fault1, fault2;
36phaset #(.order(order1), .dw(dw), .adv(adv), .delta(delta)) track1(
37     .uclk(uclk1), .uclkg(1'b1), .sclk(sclk),
38     .phase(phaset_out1), .fault(fault1));
39phaset #(.order(order2), .dw(dw), .adv(adv), .delta(delta)) track2(
40     .uclk(uclk2), .uclkg(uclk2g), .sclk(sclk),
41     .phase(phaset_out2), .fault(fault2));
42
43// Don't assume sclk phase is stable, just report the difference.
44// msb of phaset_out* is useless, just represents internal divider state;
45// that msb will be dropped in the pass through data_xdomain below.
46reg [dw-1:0] ph_diff_sclk=0;
47reg [dw-1:0] ph_sum=0, ph_sum_old=0, vernier_freq=0;
48reg [9:0] cnt=0;
49wire tick = &cnt;
50wire fault = fault1 | fault2;
51reg err_r=0;
52always @(posedge sclk) begin
53     ph_diff_sclk <= phaset_out1 - phaset_out2;
54     ph_sum <= phaset_out1 + phaset_out2;
55     cnt <= cnt+1;
56     if (tick | fault) err_r <= fault;
57     if (tick) begin
58             ph_sum_old <= ph_sum;
59             vernier_freq <= ph_sum - ph_sum_old;
60     end
61end
62assign err = err_r;  // no fancy clock domain crossing
63
64// Periodically pass the result to rclk domain
65data_xdomain #(.size(dw-1)) xdom1(
66     .clk_in(sclk), .gate_in(&cnt[4:0]), .data_in(ph_diff_sclk[dw-2:0]),
67     .clk_out(rclk), .data_out(phdiff_out));
68data_xdomain #(.size(dw)) xdom2(  // inefficient
69     .clk_in(sclk), .gate_in(&cnt[4:0]), .data_in(vernier_freq),
70     .clk_out(rclk), .data_out(vfreq_out));
71
72reg_tech_cdc err_cdc(.I(err_r), .C(rclk), .O(err_ff));
73endmodule