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