blob: d4f7a4c85b86a805713f9fd3cc0a5eda2914b768 [file] [log] [blame]
Tim Edwardscd64af52020-08-07 11:11:58 -04001// (True) digital PLL
2//
3// Output goes to a trimmable ring oscillator (see documentation).
4// Ring oscillator should be trimmable to above and below maximum
5// ranges of the input.
6//
7// Input "osc" comes from a fixed clock source (e.g., crystal oscillator
8// output).
9//
10// Input "div" is the target number of clock cycles per oscillator cycle.
11// e.g., if div == 8 then this is an 8X PLL.
12//
13// Clock "clock" is the PLL output being trimmed.
14// (NOTE: To be done: Pass-through enable)
15//
16// Algorithm:
17//
18// 1) Trim is done by thermometer code. Reset to the highest value
19// in case the fastest rate clock is too fast for the logic.
20//
21// 2) Count the number of contiguous 1s and 0s in "osc"
22// periods of the master clock. If the count maxes out, it does
23// not roll over.
24//
25// 3) Add the two counts together.
26//
27// 4) If the sum is less than div, then the clock is too slow, so
28// decrease the trim code. If the sum is greater than div, the
29// clock is too fast, so increase the trim code. If the sum
30// is equal to div, the the trim code does not change.
31//
32
33module digital_pll_controller(reset, clock, osc, div, trim);
34 input reset;
35 input clock;
36 input osc;
37 input [4:0] div;
38 output [25:0] trim; // Use ring_osc2x13, with 26 trim bits
39
40 wire [25:0] trim;
41 reg [2:0] oscbuf;
42 reg [2:0] prep;
43
44 reg [4:0] count0;
45 reg [4:0] count1;
46 reg [6:0] tval; // Includes 2 bits fractional
47 wire [4:0] tint; // Integer part of the above
48
49 wire [5:0] sum;
50
51 assign sum = count0 + count1;
52
53 // Integer to thermometer code (maybe there's an algorithmic way?)
54 assign tint = tval[6:2];
55 // |<--second-->|<-- first-->|
56 assign trim = (tint == 5'd0) ? 26'b0000000000000_0000000000000 :
shalanfd13eb52020-08-21 16:48:07 +020057 (tint == 5'd1) ? 26'b0000000000000_0000000000001 :
58 (tint == 5'd2) ? 26'b0000000000000_0000001000001 :
59 (tint == 5'd3) ? 26'b0000000000000_0010001000001 :
60 (tint == 5'd4) ? 26'b0000000000000_0010001001001 :
61 (tint == 5'd5) ? 26'b0000000000000_0010101001001 :
62 (tint == 5'd6) ? 26'b0000000000000_1010101001001 :
63 (tint == 5'd7) ? 26'b0000000000000_1010101101001 :
64 (tint == 5'd8) ? 26'b0000000000000_1010101101101 :
65 (tint == 5'd9) ? 26'b0000000000000_1011101101101 :
66 (tint == 5'd10) ? 26'b0000000000000_1011101111101 :
67 (tint == 5'd11) ? 26'b0000000000000_1111101111101 :
68 (tint == 5'd12) ? 26'b0000000000000_1111101111111 :
69 (tint == 5'd13) ? 26'b0000000000000_1111111111111 :
70 (tint == 5'd14) ? 26'b0000000000001_1111111111111 :
71 (tint == 5'd15) ? 26'b0000001000001_1111111111111 :
72 (tint == 5'd16) ? 26'b0010001000001_1111111111111 :
73 (tint == 5'd17) ? 26'b0010001001001_1111111111111 :
74 (tint == 5'd18) ? 26'b0010101001001_1111111111111 :
75 (tint == 5'd19) ? 26'b1010101001001_1111111111111 :
76 (tint == 5'd20) ? 26'b1010101101001_1111111111111 :
77 (tint == 5'd21) ? 26'b1010101101101_1111111111111 :
78 (tint == 5'd22) ? 26'b1011101101101_1111111111111 :
79 (tint == 5'd23) ? 26'b1011101111101_1111111111111 :
80 (tint == 5'd24) ? 26'b1111101111101_1111111111111 :
81 (tint == 5'd25) ? 26'b1111101111111_1111111111111 :
82 26'b1111111111111_1111111111111;
Tim Edwardscd64af52020-08-07 11:11:58 -040083
84 always @(posedge clock or posedge reset) begin
shalanfd13eb52020-08-21 16:48:07 +020085 if (reset == 1'b1) begin
86 tval <= 7'd0; // Note: trim[0] must be zero for startup to work.
87 oscbuf <= 3'd0;
88 prep <= 3'd0;
89 count0 <= 5'd0;
90 count1 <= 5'd0;
Tim Edwardscd64af52020-08-07 11:11:58 -040091
shalanfd13eb52020-08-21 16:48:07 +020092 end else begin
93 oscbuf <= {oscbuf[1:0], osc};
Tim Edwardscd64af52020-08-07 11:11:58 -040094
shalanfd13eb52020-08-21 16:48:07 +020095 if (oscbuf[2] != oscbuf[1]) begin
96 count1 <= count0;
97 count0 <= 5'b00001;
98 prep <= {prep[1:0], 1'b1};
Tim Edwardscd64af52020-08-07 11:11:58 -040099
shalanfd13eb52020-08-21 16:48:07 +0200100 if (prep == 3'b111) begin
101 if (sum > div) begin
Tim Edwardsbb3cd692020-10-09 22:00:23 -0400102 if (tval < 127) begin
103 tval <= tval + 1;
104 end
shalanfd13eb52020-08-21 16:48:07 +0200105 end else if (sum < div) begin
Tim Edwardsbb3cd692020-10-09 22:00:23 -0400106 if (tval > 0) begin
107 tval <= tval - 1;
108 end
shalanfd13eb52020-08-21 16:48:07 +0200109 end
110 end
111 end else begin
112 if (count0 != 5'b11111) begin
113 count0 <= count0 + 1;
114 end
115 end
116 end
Tim Edwardscd64af52020-08-07 11:11:58 -0400117 end
118
119endmodule // digital_pll_controller