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