Add ringosc and tweak build
diff --git a/ip/randsack/rtl/collapsering.v b/ip/randsack/rtl/collapsering.v
index 04ce4c9..6c686ad 100644
--- a/ip/randsack/rtl/collapsering.v
+++ b/ip/randsack/rtl/collapsering.v
@@ -106,7 +106,7 @@
);
-sky130_fd_sc_hd__clkbuf_4
+sky130_fd_sc_hd__clkbuf_8
#(
)
x35 (
diff --git a/ip/randsack/rtl/collapsering_macro.v b/ip/randsack/rtl/collapsering_macro.v
index fd17492..1b4c50d 100644
--- a/ip/randsack/rtl/collapsering_macro.v
+++ b/ip/randsack/rtl/collapsering_macro.v
@@ -42,6 +42,12 @@
reg [31:0] clk_cnt;
reg fake_clk;
+ wire [31:0] max_cnt = trim_a + trim_b + clkmux;
+
+ always @(max_cnt) begin
+ $display("collapsering_macro max count = 'h%h", max_cnt);
+ end
+
initial begin
clk_cnt <= 0;
fake_clk <= 1'b0;
@@ -57,7 +63,7 @@
always #5 fake_clk <= ~fake_clk;
- assign clk_out = fake_clk & start & (clk_cnt < 100);
+ assign clk_out = fake_clk & start & (clk_cnt < max_cnt);
`endif
endmodule // module collapsering_macro
diff --git a/ip/randsack/rtl/digitalcore_macro.v b/ip/randsack/rtl/digitalcore_macro.v
index 9c41fb7..16e2be4 100644
--- a/ip/randsack/rtl/digitalcore_macro.v
+++ b/ip/randsack/rtl/digitalcore_macro.v
@@ -51,7 +51,13 @@
output ring0_start,
output [27:0] ring0_trim_a,
output [27:0] ring0_trim_b,
- output [2:0] ring0_clkmux
+ output [2:0] ring0_clkmux,
+
+ // ring1 collapsering macro
+ input ring1_clk,
+ output ring1_start,
+ output [25:0] ring1_trim_a,
+ output [2:0] ring1_clkmux
);
// Filter wishbone accesses from Caravel.
@@ -67,6 +73,8 @@
parameter UART0_BASE_ADDR = 32'h3082_0000;
parameter RING0_ADDR_MASK = 32'hffff_0000;
parameter RING0_BASE_ADDR = 32'h3083_0000;
+ parameter RING1_ADDR_MASK = 32'hffff_0000;
+ parameter RING1_BASE_ADDR = 32'h3084_0000;
// Filter addresses from Caravel since we want to be absolutely sure it is
// selecting us before letting it access the arbiter. This is mostly needed
@@ -75,7 +83,7 @@
wire wbs_addr_sel;
assign wbs_addr_sel = (wbs_adr_i & DTOP_MASK) == DTOP_ADDR;
- wb_mux_3 interconnect (
+ wb_mux_4 interconnect (
.wbm_adr_i(wbs_adr_i),
.wbm_dat_i(wbs_dat_i),
.wbm_dat_o(wbs_dat_o),
@@ -124,7 +132,20 @@
.wbs2_rty_i(1'b0),
.wbs2_cyc_o(ring0_cyc_i),
.wbs2_addr(RING0_BASE_ADDR),
- .wbs2_addr_msk(RING0_ADDR_MASK)
+ .wbs2_addr_msk(RING0_ADDR_MASK),
+
+ .wbs3_adr_o(ring1_adr_i),
+ .wbs3_dat_i(ring1_dat_o),
+ .wbs3_dat_o(ring1_dat_i),
+ .wbs3_we_o(ring1_we_i),
+ .wbs3_sel_o(ring1_sel_i),
+ .wbs3_stb_o(ring1_stb_i),
+ .wbs3_ack_i(ring1_ack_o),
+ .wbs3_err_i(1'b0),
+ .wbs3_rty_i(1'b0),
+ .wbs3_cyc_o(ring1_cyc_i),
+ .wbs3_addr(RING1_BASE_ADDR),
+ .wbs3_addr_msk(RING1_ADDR_MASK)
);
// GPIO signals.
@@ -204,6 +225,8 @@
wire ring0_stb_i;
wire ring0_ack_o;
wire [31:0] ring0_dat_o;
+ wire ring0_test_en;
+ wire ring0_test_out;
ring_control #(
.CLKMUX_BITS(3),
@@ -226,17 +249,59 @@
.ring_start(ring0_start),
.ring_trim_a(ring0_trim_a),
.ring_trim_b(ring0_trim_b),
- .ring_clkmux(ring0_clkmux)
+ .ring_clkmux(ring0_clkmux),
+
+ .test_en(ring0_test_en),
+ .test_out(ring0_test_out)
+ );
+
+ // RING1 signals.
+ wire [31:0] ring1_adr_i;
+ wire [31:0] ring1_dat_i;
+ wire [3:0] ring1_sel_i;
+ wire ring1_we_i;
+ wire ring1_cyc_i;
+ wire ring1_stb_i;
+ wire ring1_ack_o;
+ wire [31:0] ring1_dat_o;
+ wire ring1_test_en;
+ wire ring1_test_out;
+
+ ring_control #(
+ .CLKMUX_BITS(3),
+ .TRIM_BITS(26)
+ ) ring1 (
+ .wb_clk_i(wb_clk_i),
+ .wb_rst_i(wb_rst_i),
+
+ .wb_stb_i(ring1_stb_i),
+ .wb_cyc_i(ring1_cyc_i),
+ .wb_we_i(ring1_we_i),
+ .wb_sel_i(ring1_sel_i),
+ .wb_dat_i(ring1_dat_i),
+ .wb_adr_i(ring1_adr_i),
+
+ .wb_ack_o(ring1_ack_o),
+ .wb_dat_o(ring1_dat_o),
+
+ .ring_clk(ring1_clk),
+ .ring_start(ring1_start),
+ .ring_trim_a(ring1_trim_a),
+ .ring_trim_b(),
+ .ring_clkmux(ring1_clkmux),
+
+ .test_en(ring1_test_en),
+ .test_out(ring1_test_out)
);
// Connect up external ports.
assign gpio_in = io_in[37:6];
- assign uart_rx = io_in[2];
+ assign uart_rx = io_in[35];
- assign io_out[5:0] = {1'b0, uart_tx, 4'b0};
- assign io_out[37:6] = gpio_out;
- assign io_oeb[5:0] = {1'b1, ~uart_enabled, 4'b1};
- assign io_oeb[37:6] = gpio_oeb;
+ assign io_out[5:0] = 6'b0;
+ assign io_out[37:6] = gpio_out | {uart_tx & uart_enabled, 4'b0, ring0_test_out, 26'b0};
+ assign io_oeb[5:0] = 6'b0;
+ assign io_oeb[37:6] = gpio_oeb & {~uart_enabled, {4{1'b1}}, ~ring0_test_en, {26{1'b1}}};
assign la_data_out = 128'b0;
diff --git a/ip/randsack/rtl/ring_control.v b/ip/randsack/rtl/ring_control.v
index 5efe222..cc01661 100644
--- a/ip/randsack/rtl/ring_control.v
+++ b/ip/randsack/rtl/ring_control.v
@@ -36,7 +36,10 @@
output reg ring_start,
output reg [TRIM_BITS-1:0] ring_trim_a,
output reg [TRIM_BITS-1:0] ring_trim_b,
- output reg [CLKMUX_BITS-1:0] ring_clkmux
+ output reg [CLKMUX_BITS-1:0] ring_clkmux,
+
+ output reg test_en,
+ output test_out
);
// Register addresses.
localparam COUNT_VALUE_ADDR = 8'h00;
@@ -59,6 +62,9 @@
reg counter_resetb;
reg [16:0] counter_value;
+ // Test port mux.
+ assign test_out = test_en ? ring_clk : 1'b0;
+
// Ring oscillator counter.
// NOTE: This reset is pretty nasty, but the idea is we have full control
// over the reset timing so we don't need to synchronize it.
@@ -77,9 +83,10 @@
wb_dat_o <= 32'h0;
counter_resetb <= 1'b0;
ring_start <= 1'b0;
- ring_clkmux <= {CLKMUX_BITS{1'b1}};
- ring_trim_a <= {TRIM_BITS{1'b1}};
- ring_trim_b <= {TRIM_BITS{1'b1}};
+ ring_clkmux <= {CLKMUX_BITS{1'b0}};
+ ring_trim_a <= {TRIM_BITS{1'b0}};
+ ring_trim_b <= {TRIM_BITS{1'b0}};
+ test_en <= 1'b0;
end else begin
wb_ack_o <= 1'b0;
@@ -89,6 +96,7 @@
if (control_sel) begin
counter_resetb <= ~wb_dat_i[0];
ring_start <= wb_dat_i[1];
+ test_en <= wb_dat_i[2];
ring_clkmux <= wb_dat_i[CLKMUX_BITS-1+8:8];
end else if (trima_sel) begin
ring_trim_a <= wb_dat_i[TRIM_BITS-1:0];
diff --git a/ip/randsack/rtl/ringosc_macro.v b/ip/randsack/rtl/ringosc_macro.v
new file mode 100644
index 0000000..6a7011c
--- /dev/null
+++ b/ip/randsack/rtl/ringosc_macro.v
@@ -0,0 +1,74 @@
+// SPDX-FileCopyrightText: 2021 Harrison Pham
+//
+// 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
+
+module ringosc_macro #(
+ parameter TRIM_BITS = 26
+) (
+`ifdef USE_POWER_PINS
+ inout vccd1,
+ inout vssd1,
+`endif
+
+ input start,
+ input [TRIM_BITS-1:0] trim_a,
+ input [2:0] clkmux,
+
+ output clk_out
+);
+
+ wire [1:0] clockp;
+ wire clk = clockp[0];
+
+ ring_osc2x13 ring (
+ .reset(~start),
+ .trim(trim_a),
+ .clockp(clockp)
+ );
+
+ // Clock dividers.
+ reg s0;
+ always @(posedge clk or negedge start) begin
+ if (!start) begin
+ s0 <= 1'b0;
+ end else begin
+ s0 <= ~s0;
+ end
+ end
+
+ reg s1;
+ always @(posedge s0 or negedge start) begin
+ if (!start) begin
+ s1 <= 1'b0;
+ end else begin
+ s1 <= ~s1;
+ end
+ end
+
+ reg s2;
+ always @(posedge s1 or negedge start) begin
+ if (!start) begin
+ s2 <= 1'b0;
+ end else begin
+ s2 <= ~s2;
+ end
+ end
+
+ assign clk_out = (clkmux == 3'b000) ? clk :
+ (clkmux == 3'b001) ? s0 :
+ (clkmux == 3'b010) ? s1 :
+ (clkmux == 3'b011) ? s2 :
+ clk;
+
+endmodule // module ringosc_macro
diff --git a/ip/randsack/sch/collapsering.sch b/ip/randsack/sch/collapsering.sch
index 2550fff..982a316 100644
--- a/ip/randsack/sch/collapsering.sch
+++ b/ip/randsack/sch/collapsering.sch
@@ -305,7 +305,7 @@
C {devices/title-2.sym} 0 -40 0 0 {name=l26 author="Harrison Pham" rev=1.0}
C {devices/lab_wire.sym} 3100 -1140 0 0 {name=l18 sig_type=std_logic lab=outb}
C {devices/lab_wire.sym} 3100 -1530 0 0 {name=l9 sig_type=std_logic lab=outa}
-C {sky130_stdcells/clkbuf_4.sym} 3160 -800 0 0 {name=x35 VGND=VGND VNB=VNB VPB=VPB VPWR=VPWR prefix=sky130_fd_sc_hd__ }
+C {sky130_stdcells/clkbuf_8.sym} 3160 -800 0 0 {name=x35 VGND=VGND VNB=VNB VPB=VPB VPWR=VPWR prefix=sky130_fd_sc_hd__ }
C {devices/opin.sym} 3230 -800 0 0 {name=p1 lab=CLKBUFOUT}
C {devices/ipin.sym} 110 -1690 0 0 {name=p2 lab=START}
C {devices/lab_pin.sym} 400 -1660 0 0 {name=l1 sig_type=std_logic lab=TRIMA[0]}
diff --git a/ip/third_party/caravel/ring_osc2x13.v b/ip/third_party/caravel/ring_osc2x13.v
new file mode 100644
index 0000000..f20110e
--- /dev/null
+++ b/ip/third_party/caravel/ring_osc2x13.v
@@ -0,0 +1,250 @@
+// 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
diff --git a/openlane/collapsering_macro/config.tcl b/openlane/collapsering_macro/config.tcl
index f73eedc..76760b1 100755
--- a/openlane/collapsering_macro/config.tcl
+++ b/openlane/collapsering_macro/config.tcl
@@ -26,11 +26,12 @@
# Disable optimizations and CTS to preserve our hand picked stdcells.
set ::env(SYNTH_BUFFERING) 0
+set ::env(SYNTH_SIZING) 0
set ::env(SYNTH_SHARE_RESOURCES) 0
+set ::env(CLOCK_TREE_SYNTH) 0
set ::env(PL_RESIZER_DESIGN_OPTIMIZATIONS) 0
set ::env(PL_RESIZER_TIMING_OPTIMIZATIONS) 0
set ::env(PL_OPENPHYSYN_OPTIMIZATIONS) 0
-set ::env(CLOCK_TREE_SYNTH) 0
set ::env(GLB_RESIZER_TIMING_OPTIMIZATIONS) 0
set ::env(DESIGN_IS_CORE) 0
@@ -44,12 +45,13 @@
set ::env(CLOCK_PERIOD) "10"
set ::env(FP_SIZING) absolute
+# 85 85 is optimal but wont fit into PDN
set ::env(DIE_AREA) "0 0 50 150"
set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg
set ::env(PL_BASIC_PLACEMENT) 1
-set ::env(PL_TARGET_DENSITY) 0.5
+set ::env(PL_TARGET_DENSITY) 0.75
# Maximum layer used for routing is metal 4.
# This is because this macro will be inserted in a top level (user_project_wrapper)
diff --git a/openlane/collapsering_macro/pin_order.cfg b/openlane/collapsering_macro/pin_order.cfg
index 46201b2..1a9c694 100644
--- a/openlane/collapsering_macro/pin_order.cfg
+++ b/openlane/collapsering_macro/pin_order.cfg
@@ -9,6 +9,6 @@
#E
trim_a.*
+trim_b.*
#W
-trim_b.*
diff --git a/openlane/digitalcore_macro/base.sdc b/openlane/digitalcore_macro/base.sdc
index 5efe131..c1a7a33 100644
--- a/openlane/digitalcore_macro/base.sdc
+++ b/openlane/digitalcore_macro/base.sdc
@@ -15,12 +15,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set ::env(WB_CLOCK_PERIOD) "10"
+set ::env(WB_CLOCK_PERIOD) "15"
set ::env(WB_CLOCK_PORT) "wb_clk_i"
-set ::env(RING0_CLOCK_PERIOD) "10"
+set ::env(RING0_CLOCK_PERIOD) "15"
set ::env(RING0_CLOCK_PORT) "ring0_clk"
+set ::env(RING1_CLOCK_PERIOD) "15"
+set ::env(RING1_CLOCK_PORT) "ring1_clk"
+
if {[info exists ::env(WB_CLOCK_PORT)] && $::env(WB_CLOCK_PORT) != ""} {
create_clock [get_ports $::env(WB_CLOCK_PORT)] -name $::env(WB_CLOCK_PORT) -period $::env(CLOCK_PERIOD)
} else {
@@ -55,3 +58,4 @@
# Extra clocks for macros.
# NOTE: These don't need any input/output delays since this design just uses it for clock counting.
create_clock [get_ports $::env(RING0_CLOCK_PORT)] -name $::env(RING0_CLOCK_PORT) -period $::env(RING0_CLOCK_PERIOD)
+create_clock [get_ports $::env(RING1_CLOCK_PORT)] -name $::env(RING1_CLOCK_PORT) -period $::env(RING1_CLOCK_PERIOD)
diff --git a/openlane/digitalcore_macro/config.tcl b/openlane/digitalcore_macro/config.tcl
index 76c41aa..984323c 100755
--- a/openlane/digitalcore_macro/config.tcl
+++ b/openlane/digitalcore_macro/config.tcl
@@ -22,7 +22,7 @@
$script_dir/../../ip/randsack/rtl/digitalcore_macro.v \
$script_dir/../../ip/third_party/picorv32_wb/gpio32_wb.v \
$script_dir/../../ip/third_party/picorv32_wb/simpleuart_div16_wb.v \
- $script_dir/../../ip/third_party/verilog-wishbone/rtl/wb_mux_3.v \
+ $script_dir/../../ip/third_party/verilog-wishbone/rtl/wb_mux_4.v \
$script_dir/../../ip/randsack/rtl/ring_control.v"
set ::env(DESIGN_IS_CORE) 0
@@ -31,8 +31,8 @@
set ::env(BASE_SDC_FILE) "$script_dir/base.sdc"
# NOTE: Make sure to add all clocks manually to base.sdc!
-set ::env(CLOCK_PORT) "wb_clk_i ring0_clk"
-set ::env(CLOCK_PERIOD) "10"
+set ::env(CLOCK_PORT) "wb_clk_i ring0_clk ring1_clk"
+set ::env(CLOCK_PERIOD) "15"
set ::env(FP_SIZING) absolute
set ::env(DIE_AREA) "0 0 500 500"
diff --git a/openlane/ringosc_macro/config.tcl b/openlane/ringosc_macro/config.tcl
new file mode 100755
index 0000000..60d4a8f
--- /dev/null
+++ b/openlane/ringosc_macro/config.tcl
@@ -0,0 +1,70 @@
+# 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
+
+set script_dir [file dirname [file normalize [info script]]]
+
+set ::env(DESIGN_NAME) ringosc_macro
+
+set ::env(VERILOG_FILES) "\
+ $script_dir/../../ip/randsack/rtl/ringosc_macro.v \
+ $script_dir/../../ip/third_party/caravel/ring_osc2x13.v"
+
+# Preserve manually instantiated stdcells.
+set ::env(SYNTH_READ_BLACKBOX_LIB) 1
+
+# Disable optimizations and CTS to preserve our hand picked stdcells.
+set ::env(SYNTH_BUFFERING) 0
+set ::env(SYNTH_SIZING) 0
+set ::env(SYNTH_SHARE_RESOURCES) 0
+set ::env(CLOCK_TREE_SYNTH) 0
+set ::env(PL_RESIZER_DESIGN_OPTIMIZATIONS) 0
+set ::env(PL_RESIZER_TIMING_OPTIMIZATIONS) 0
+set ::env(PL_OPENPHYSYN_OPTIMIZATIONS) 0
+set ::env(GLB_RESIZER_TIMING_OPTIMIZATIONS) 0
+
+set ::env(DESIGN_IS_CORE) 0
+
+# TODO(hdpham): Properly disable STA.
+set ::env(CLOCK_PORT) "clk_out"
+# set ::env(CLOCK_NET) "ring.clk_ff0"
+set ::env(CLOCK_PERIOD) "10"
+
+set ::env(FP_SIZING) absolute
+# 70 70 is optimal but won't fit in PDN.
+set ::env(DIE_AREA) "0 0 50 150"
+
+set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg
+
+set ::env(PL_BASIC_PLACEMENT) 1
+set ::env(PL_TARGET_DENSITY) 0.75
+
+# Maximum layer used for routing is metal 4.
+# This is because this macro will be inserted in a top level (user_project_wrapper)
+# where the PDN is planned on metal 5. So, to avoid having shorts between routes
+# in this macro and the top level metal 5 stripes, we have to restrict routes to metal4.
+# TODO(hdpham): Figure out why blocking li1 doesn't work.
+#set ::env(GLB_RT_MINLAYER) 2
+set ::env(GLB_RT_MAXLAYER) 5
+
+# Really force the router to not use li1/met5.
+#set ::env(GLB_RT_OBS) "li1 0 0 50 200, met5 0 0 50 200"
+
+# You can draw more power domains if you need to
+set ::env(VDD_NETS) [list {vccd1}]
+set ::env(GND_NETS) [list {vssd1}]
+
+set ::env(DIODE_INSERTION_STRATEGY) 4
+# If you're going to use multiple power domains, then disable cvc run.
+set ::env(RUN_CVC) 1
diff --git a/openlane/ringosc_macro/pin_order.cfg b/openlane/ringosc_macro/pin_order.cfg
new file mode 100644
index 0000000..dbbb80f
--- /dev/null
+++ b/openlane/ringosc_macro/pin_order.cfg
@@ -0,0 +1,13 @@
+#BUS_SORT
+
+#S
+clkmux.*
+clk_out
+start
+
+#N
+
+#E
+trim_a.*
+
+#W
diff --git a/openlane/user_project_wrapper/config.tcl b/openlane/user_project_wrapper/config.tcl
index 80814ac..7cef48f 100755
--- a/openlane/user_project_wrapper/config.tcl
+++ b/openlane/user_project_wrapper/config.tcl
@@ -53,17 +53,20 @@
$::env(CARAVEL_ROOT)/verilog/rtl/defines.v \
$script_dir/../../verilog/rtl/user_proj_example.v \
$script_dir/../../ip/randsack/rtl/digitalcore_macro.v \
- $script_dir/../../ip/randsack/rtl/collapsering_macro.v"
+ $script_dir/../../ip/randsack/rtl/collapsering_macro.v \
+ $script_dir/../../ip/randsack/rtl/ringosc_macro.v"
set ::env(EXTRA_LEFS) "\
$script_dir/../../lef/user_proj_example.lef \
$script_dir/../../lef/digitalcore_macro.lef \
- $script_dir/../../lef/collapsering_macro.lef"
+ $script_dir/../../lef/collapsering_macro.lef \
+ $script_dir/../../lef/ringosc_macro.lef"
set ::env(EXTRA_GDS_FILES) "\
$script_dir/../../gds/user_proj_example.gds \
$script_dir/../../gds/digitalcore_macro.gds \
- $script_dir/../../gds/collapsering_macro.gds"
+ $script_dir/../../gds/collapsering_macro.gds \
+ $script_dir/../../gds/ringosc_macro.gds"
set ::env(GLB_RT_MAXLAYER) 5
diff --git a/openlane/user_project_wrapper/macro.cfg b/openlane/user_project_wrapper/macro.cfg
index 732f5ab..e02b4fd 100644
--- a/openlane/user_project_wrapper/macro.cfg
+++ b/openlane/user_project_wrapper/macro.cfg
@@ -1,2 +1,3 @@
digitalcore 1000 500 N
-collapsering0 700 620 N
+ring0 800 620 N
+ring1 800 800 N
diff --git a/verilog/dv/randsack_netlists.v b/verilog/dv/randsack_netlists.v
index 2eb9750..68f604b 100644
--- a/verilog/dv/randsack_netlists.v
+++ b/verilog/dv/randsack_netlists.v
@@ -25,8 +25,9 @@
`include "user_project_wrapper.v"
`include "digitalcore_macro.v"
`include "collapsering_macro.v"
+ `include "ringosc_macro.v"
`include "ring_control.v"
`include "picorv32_wb/gpio32_wb.v"
`include "picorv32_wb/simpleuart_div16_wb.v"
- `include "verilog-wishbone/rtl/wb_mux_3.v"
+ `include "verilog-wishbone/rtl/wb_mux_4.v"
`endif
diff --git a/verilog/dv/randsack_regrw_directed/randsack_regrw_directed.c b/verilog/dv/randsack_regrw_directed/randsack_regrw_directed.c
index 2218b98..ff29a94 100644
--- a/verilog/dv/randsack_regrw_directed/randsack_regrw_directed.c
+++ b/verilog/dv/randsack_regrw_directed/randsack_regrw_directed.c
@@ -35,6 +35,7 @@
#define RANDSACK_RING_CONTROL_ADDR 0x04
#define RANDSACK_RING_TRIMA_ADDR 0x08
#define RANDSACK_RING_TRIMB_ADDR 0x0c
+#define RANDSACK_RING_CLKMUX_OFFSET 8
#define RANDSACK_RING_CONTROL_RESET_MASK (1 << 0)
#define RANDSACK_RING_CONTROL_START_MASK (1 << 1)
@@ -80,18 +81,24 @@
REG(RANDSACK_GPIO0_BASE + RANDSACK_GPIO_DATA) = 0x55550000;
// Reset ring osc.
+ REG(RANDSACK_RING0_BASE + RANDSACK_RING_TRIMA_ADDR) = 50;
+ REG(RANDSACK_RING0_BASE + RANDSACK_RING_TRIMB_ADDR) = 60;
REG(RANDSACK_RING0_BASE + RANDSACK_RING_CONTROL_ADDR) = RANDSACK_RING_CONTROL_RESET_MASK;
REG(RANDSACK_RING0_BASE + RANDSACK_RING_CONTROL_ADDR) = 0;
// Start ring osc.
- REG(RANDSACK_RING0_BASE + RANDSACK_RING_CONTROL_ADDR) = RANDSACK_RING_CONTROL_START_MASK;
+ REG(RANDSACK_RING0_BASE + RANDSACK_RING_CONTROL_ADDR) = RANDSACK_RING_CONTROL_START_MASK + (4 << RANDSACK_RING_CLKMUX_OFFSET);
REG(RANDSACK_GPIO0_BASE + RANDSACK_GPIO_DATA) = 0xaaaa0000;
// Wait for valid value.
- while (REG(RANDSACK_RING0_BASE + RANDSACK_RING_COUNT_ADDR) < 100) {
+ while (REG(RANDSACK_RING0_BASE + RANDSACK_RING_COUNT_ADDR) < 114) {
REG(RANDSACK_GPIO0_BASE + RANDSACK_GPIO_DATA) = 0xdead0000;
}
- REG(RANDSACK_GPIO0_BASE + RANDSACK_GPIO_DATA) = 0xfeed0000;
+ // Check to make sure the counter stopped. Our CPU is really slow so this
+ // is a safe check.
+ if (REG(RANDSACK_RING0_BASE + RANDSACK_RING_COUNT_ADDR) == 114) {
+ REG(RANDSACK_GPIO0_BASE + RANDSACK_GPIO_DATA) = 0xfeed0000;
+ }
}