mirror of https://github.com/efabless/caravel.git
251 lines
5.2 KiB
Verilog
251 lines
5.2 KiB
Verilog
// SPDX-FileCopyrightText: 2020 Efabless Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
`default_nettype none
|
|
// Tunable ring oscillator---synthesizable (physical) version.
|
|
//
|
|
// NOTE: This netlist cannot be simulated correctly due to lack
|
|
// of accurate timing in the digital cell verilog models.
|
|
|
|
module delay_stage(in, trim, out);
|
|
input in;
|
|
input [1:0] trim;
|
|
output out;
|
|
|
|
wire d0, d1, d2, ts;
|
|
|
|
sky130_fd_sc_hd__clkbuf_2 delaybuf0 (
|
|
.A(in),
|
|
.X(ts)
|
|
);
|
|
|
|
sky130_fd_sc_hd__clkbuf_1 delaybuf1 (
|
|
.A(ts),
|
|
.X(d0)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvp_2 delayen1 (
|
|
.A(d0),
|
|
.TE(trim[1]),
|
|
.Z(d1)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvn_4 delayenb1 (
|
|
.A(ts),
|
|
.TE_B(trim[1]),
|
|
.Z(d1)
|
|
);
|
|
|
|
sky130_fd_sc_hd__clkinv_1 delayint0 (
|
|
.A(d1),
|
|
.Y(d2)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvp_2 delayen0 (
|
|
.A(d2),
|
|
.TE(trim[0]),
|
|
.Z(out)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvn_8 delayenb0 (
|
|
.A(ts),
|
|
.TE_B(trim[0]),
|
|
.Z(out)
|
|
);
|
|
|
|
endmodule
|
|
|
|
module start_stage(in, trim, reset, out);
|
|
input in;
|
|
input [1:0] trim;
|
|
input reset;
|
|
output out;
|
|
|
|
wire d0, d1, d2, ctrl0, one;
|
|
|
|
sky130_fd_sc_hd__clkbuf_1 delaybuf0 (
|
|
.A(in),
|
|
.X(d0)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvp_2 delayen1 (
|
|
.A(d0),
|
|
.TE(trim[1]),
|
|
.Z(d1)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvn_4 delayenb1 (
|
|
.A(in),
|
|
.TE_B(trim[1]),
|
|
.Z(d1)
|
|
);
|
|
|
|
sky130_fd_sc_hd__clkinv_1 delayint0 (
|
|
.A(d1),
|
|
.Y(d2)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvp_2 delayen0 (
|
|
.A(d2),
|
|
.TE(trim[0]),
|
|
.Z(out)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvn_8 delayenb0 (
|
|
.A(in),
|
|
.TE_B(ctrl0),
|
|
.Z(out)
|
|
);
|
|
|
|
sky130_fd_sc_hd__einvp_1 reseten0 (
|
|
.A(one),
|
|
.TE(reset),
|
|
.Z(out)
|
|
);
|
|
|
|
sky130_fd_sc_hd__or2_2 ctrlen0 (
|
|
.A(reset),
|
|
.B(trim[0]),
|
|
.X(ctrl0)
|
|
);
|
|
|
|
sky130_fd_sc_hd__conb_1 const1 (
|
|
.HI(one),
|
|
.LO()
|
|
);
|
|
|
|
endmodule
|
|
|
|
// Ring oscillator with 13 stages, each with two trim bits delay
|
|
// (see above). Trim is not binary: For trim[1:0], lower bit
|
|
// trim[0] is primary trim and must be applied first; upper
|
|
// bit trim[1] is secondary trim and should only be applied
|
|
// after the primary trim is applied, or it has no effect.
|
|
//
|
|
// Total effective number of inverter stages in this oscillator
|
|
// ranges from 13 at trim 0 to 65 at trim 24. The intention is
|
|
// to cover a range greater than 2x so that the midrange can be
|
|
// reached over all PVT conditions.
|
|
//
|
|
// Frequency of this ring oscillator under SPICE simulations at
|
|
// nominal PVT is maximum 214 MHz (trim 0), minimum 90 MHz (trim 24).
|
|
|
|
module ring_osc2x13(reset, trim, clockp);
|
|
input reset;
|
|
input [25:0] trim;
|
|
output[1:0] clockp;
|
|
|
|
`ifdef FUNCTIONAL // i.e., behavioral model below
|
|
|
|
reg [1:0] clockp;
|
|
reg hiclock;
|
|
integer i;
|
|
real delay;
|
|
wire [5:0] bcount;
|
|
|
|
assign bcount = trim[0] + trim[1] + trim[2]
|
|
+ trim[3] + trim[4] + trim[5] + trim[6] + trim[7]
|
|
+ trim[8] + trim[9] + trim[10] + trim[11] + trim[12]
|
|
+ trim[13] + trim[14] + trim[15] + trim[16] + trim[17]
|
|
+ trim[18] + trim[19] + trim[20] + trim[21] + trim[22]
|
|
+ trim[23] + trim[24] + trim[25];
|
|
|
|
initial begin
|
|
hiclock <= 1'b0;
|
|
delay = 3.0;
|
|
end
|
|
|
|
// Fastest operation is 214 MHz = 4.67ns
|
|
// Delay per trim is 0.02385
|
|
// Run "hiclock" at 2x this rate, then use positive and negative
|
|
// edges to derive the 0 and 90 degree phase clocks.
|
|
|
|
always #delay begin
|
|
hiclock <= (hiclock === 1'b0);
|
|
end
|
|
|
|
always @(trim) begin
|
|
// Implement trim as a variable delay, one delay per trim bit
|
|
delay = 1.168 + 0.012 * $itor(bcount);
|
|
end
|
|
|
|
always @(posedge hiclock or posedge reset) begin
|
|
if (reset == 1'b1) begin
|
|
clockp[0] <= 1'b0;
|
|
end else begin
|
|
clockp[0] <= (clockp[0] === 1'b0);
|
|
end
|
|
end
|
|
|
|
always @(negedge hiclock or posedge reset) begin
|
|
if (reset == 1'b1) begin
|
|
clockp[1] <= 1'b0;
|
|
end else begin
|
|
clockp[1] <= (clockp[1] === 1'b0);
|
|
end
|
|
end
|
|
|
|
`else // !FUNCTIONAL; i.e., gate level netlist below
|
|
|
|
wire [1:0] clockp;
|
|
wire [12:0] d;
|
|
wire [1:0] c;
|
|
|
|
// Main oscillator loop stages
|
|
|
|
genvar i;
|
|
generate
|
|
for (i = 0; i < 12; i = i + 1) begin : dstage
|
|
delay_stage id (
|
|
.in(d[i]),
|
|
.trim({trim[i+13], trim[i]}),
|
|
.out(d[i+1])
|
|
);
|
|
end
|
|
endgenerate
|
|
|
|
// Reset/startup stage
|
|
|
|
start_stage iss (
|
|
.in(d[12]),
|
|
.trim({trim[25], trim[12]}),
|
|
.reset(reset),
|
|
.out(d[0])
|
|
);
|
|
|
|
// Buffered outputs a 0 and 90 degrees phase (approximately)
|
|
|
|
sky130_fd_sc_hd__clkinv_2 ibufp00 (
|
|
.A(d[0]),
|
|
.Y(c[0])
|
|
);
|
|
sky130_fd_sc_hd__clkinv_8 ibufp01 (
|
|
.A(c[0]),
|
|
.Y(clockp[0])
|
|
);
|
|
sky130_fd_sc_hd__clkinv_2 ibufp10 (
|
|
.A(d[6]),
|
|
.Y(c[1])
|
|
);
|
|
sky130_fd_sc_hd__clkinv_8 ibufp11 (
|
|
.A(c[1]),
|
|
.Y(clockp[1])
|
|
);
|
|
|
|
`endif // !FUNCTIONAL
|
|
|
|
endmodule
|
|
`default_nettype wire
|