blob: 9bf6252bbfd8bf725d22d46f7bba23fdf5789b8e [file] [log] [blame]
// 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;
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