Started adding RTL for the Caravel project
diff --git a/verilog/rtl/digital_pll_controller.v b/verilog/rtl/digital_pll_controller.v
new file mode 100644
index 0000000..b88cc33
--- /dev/null
+++ b/verilog/rtl/digital_pll_controller.v
@@ -0,0 +1,115 @@
+// (True) digital PLL
+//
+// Output goes to a trimmable ring oscillator (see documentation).
+// Ring oscillator should be trimmable to above and below maximum
+// ranges of the input.
+//
+// Input "osc" comes from a fixed clock source (e.g., crystal oscillator
+// output).
+//
+// Input "div" is the target number of clock cycles per oscillator cycle.
+// e.g., if div == 8 then this is an 8X PLL.
+//
+// Clock "clock" is the PLL output being trimmed.
+// (NOTE: To be done: Pass-through enable)
+//
+// Algorithm:
+//
+// 1) Trim is done by thermometer code. Reset to the highest value
+// in case the fastest rate clock is too fast for the logic.
+//
+// 2) Count the number of contiguous 1s and 0s in "osc"
+// periods of the master clock. If the count maxes out, it does
+// not roll over.
+//
+// 3) Add the two counts together.
+//
+// 4) If the sum is less than div, then the clock is too slow, so
+// decrease the trim code. If the sum is greater than div, the
+// clock is too fast, so increase the trim code. If the sum
+// is equal to div, the the trim code does not change.
+//
+
+module digital_pll_controller(reset, clock, osc, div, trim);
+ input reset;
+ input clock;
+ input osc;
+ input [4:0] div;
+ output [25:0] trim; // Use ring_osc2x13, with 26 trim bits
+
+ wire [25:0] trim;
+ reg [2:0] oscbuf;
+ reg [2:0] prep;
+
+ reg [4:0] count0;
+ reg [4:0] count1;
+ reg [6:0] tval; // Includes 2 bits fractional
+ wire [4:0] tint; // Integer part of the above
+
+ wire [5:0] sum;
+
+ assign sum = count0 + count1;
+
+ // Integer to thermometer code (maybe there's an algorithmic way?)
+ assign tint = tval[6:2];
+ // |<--second-->|<-- first-->|
+ assign trim = (tint == 5'd0) ? 26'b0000000000000_0000000000000 :
+ (tint == 5'd1) ? 26'b0000000000000_0000000000001 :
+ (tint == 5'd2) ? 26'b0000000000000_0000001000001 :
+ (tint == 5'd3) ? 26'b0000000000000_0010001000001 :
+ (tint == 5'd4) ? 26'b0000000000000_0010001001001 :
+ (tint == 5'd5) ? 26'b0000000000000_0010101001001 :
+ (tint == 5'd6) ? 26'b0000000000000_1010101001001 :
+ (tint == 5'd7) ? 26'b0000000000000_1010101101001 :
+ (tint == 5'd8) ? 26'b0000000000000_1010101101101 :
+ (tint == 5'd9) ? 26'b0000000000000_1011101101101 :
+ (tint == 5'd10) ? 26'b0000000000000_1011101111101 :
+ (tint == 5'd11) ? 26'b0000000000000_1111101111101 :
+ (tint == 5'd12) ? 26'b0000000000000_1111101111111 :
+ (tint == 5'd13) ? 26'b0000000000000_1111111111111 :
+ (tint == 5'd14) ? 26'b0000000000001_1111111111111 :
+ (tint == 5'd15) ? 26'b0000001000001_1111111111111 :
+ (tint == 5'd16) ? 26'b0010001000001_1111111111111 :
+ (tint == 5'd17) ? 26'b0010001001001_1111111111111 :
+ (tint == 5'd18) ? 26'b0010101001001_1111111111111 :
+ (tint == 5'd19) ? 26'b1010101001001_1111111111111 :
+ (tint == 5'd20) ? 26'b1010101101001_1111111111111 :
+ (tint == 5'd21) ? 26'b1010101101101_1111111111111 :
+ (tint == 5'd22) ? 26'b1011101101101_1111111111111 :
+ (tint == 5'd23) ? 26'b1011101111101_1111111111111 :
+ (tint == 5'd24) ? 26'b1111101111101_1111111111111 :
+ (tint == 5'd25) ? 26'b1111101111111_1111111111111 :
+ 26'b1111111111111_1111111111111;
+
+ always @(posedge clock or posedge reset) begin
+ if (reset == 1'b1) begin
+ tval <= 7'd0; // Note: trim[0] must be zero for startup to work.
+ oscbuf <= 3'd0;
+ prep <= 3'd0;
+ count0 <= 5'd0;
+ count1 <= 5'd0;
+
+ end else begin
+ oscbuf <= {oscbuf[1:0], osc};
+
+ if (oscbuf[2] != oscbuf[1]) begin
+ count1 <= count0;
+ count0 <= 5'b00001;
+ prep <= {prep[1:0], 1'b1};
+
+ if (prep == 3'b111) begin
+ if (sum > div) begin
+ tval <= tval + 1;
+ end else if (sum < div) begin
+ tval <= tval - 1;
+ end
+ end
+ end else begin
+ if (count0 != 5'b11111) begin
+ count0 <= count0 + 1;
+ end
+ end
+ end
+ end
+
+endmodule // digital_pll_controller