|  | `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 |