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