Added carry select adder mapping files
diff --git a/sky130/Makefile.in b/sky130/Makefile.in
index edee408..2d94f6d 100644
--- a/sky130/Makefile.in
+++ b/sky130/Makefile.in
@@ -270,7 +270,7 @@
# standard cell libraries, so these are collected in one definition
# here:
OPENLANE_COMMON = config.tcl tracks.info no_synth.cells drc_exclude.cells
-OPENLANE_COMMON += tribuff_map.v latch_map.v mux2_map.v mux4_map.v fa_map.v rca_map.v
+OPENLANE_COMMON += tribuff_map.v latch_map.v mux2_map.v mux4_map.v fa_map.v rca_map.v csa_map.v
# Where cpp syntax is followed, this is equivalent to cpp, but it does not
# mangle non-C source files under the belief that they are actually C code.
diff --git a/sky130/openlane/config.tcl b/sky130/openlane/config.tcl
index f26d033..e11c34d 100755
--- a/sky130/openlane/config.tcl
+++ b/sky130/openlane/config.tcl
@@ -84,6 +84,9 @@
# Ripple carry adder mapping
set ::env(RIPPLE_CARRY_ADDER_MAP) "$::env(PDK_ROOT)/$::env(PDK)/libs.tech/openlane/$::env(STD_CELL_LIBRARY)/rca_map.v"
+# Carry select adder mapping
+set ::env(CARRY_SELECT_ADDER_MAP) "$::env(PDK_ROOT)/$::env(PDK)/libs.tech/openlane/$::env(STD_CELL_LIBRARY)/csa_map.v"
+
# Default No Synth List
set ::env(NO_SYNTH_CELL_LIST) "$::env(PDK_ROOT)/$::env(PDK)/libs.tech/openlane/$::env(STD_CELL_LIBRARY)/no_synth.cells"
diff --git a/sky130/openlane/sky130_fd_sc_hd/csa_map.v b/sky130/openlane/sky130_fd_sc_hd/csa_map.v
new file mode 100644
index 0000000..f9e5107
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_hd/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_hd__conb_1
+`define FA_CELL sky130_fd_sc_hd__fa_1
+`define MUX2x1_CELL sky130_fd_sc_hd__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule
diff --git a/sky130/openlane/sky130_fd_sc_hdll/csa_map.v b/sky130/openlane/sky130_fd_sc_hdll/csa_map.v
new file mode 100644
index 0000000..3f95c4e
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_hdll/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_hdll__conb_1
+`define FA_CELL sky130_fd_sc_hdll__fa_1
+`define MUX2x1_CELL sky130_fd_sc_hdll__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule
diff --git a/sky130/openlane/sky130_fd_sc_hs/csa_map.v b/sky130/openlane/sky130_fd_sc_hs/csa_map.v
new file mode 100644
index 0000000..39a6e64
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_hs/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_hs__conb_1
+`define FA_CELL sky130_fd_sc_hs__fa_1
+`define MUX2x1_CELL sky130_fd_sc_hs__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule
diff --git a/sky130/openlane/sky130_fd_sc_hvl/csa_map.v b/sky130/openlane/sky130_fd_sc_hvl/csa_map.v
new file mode 100644
index 0000000..1c7c098
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_hvl/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_hvl__conb_1
+`define FA_CELL sky130_fd_sc_hvl__fa_1
+`define MUX2x1_CELL sky130_fd_sc_hvl__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule
diff --git a/sky130/openlane/sky130_fd_sc_ls/csa_map.v b/sky130/openlane/sky130_fd_sc_ls/csa_map.v
new file mode 100644
index 0000000..9aa90c1
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_ls/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_ls__conb_1
+`define FA_CELL sky130_fd_sc_ls__fa_1
+`define MUX2x1_CELL sky130_fd_sc_ls__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule
diff --git a/sky130/openlane/sky130_fd_sc_ms/csa_map.v b/sky130/openlane/sky130_fd_sc_ms/csa_map.v
new file mode 100644
index 0000000..867a13c
--- /dev/null
+++ b/sky130/openlane/sky130_fd_sc_ms/csa_map.v
@@ -0,0 +1,257 @@
+`define TIE_CELL sky130_fd_sc_ms__conb_1
+`define FA_CELL sky130_fd_sc_ms__fa_1
+`define MUX2x1_CELL sky130_fd_sc_ms__mux2_1
+
+// n-bit RCA using n FA instances
+module rca #(parameter n=32) (
+ input [n-1:0] a, b,
+ input ci,
+ output [n-1:0] s,
+ output co
+);
+ wire [n:0] c;
+
+ assign c[0] = ci;
+ assign co = c[n];
+
+ generate
+ genvar i;
+ for(i=0; i<n; i=i+1)
+ `FA_CELL FA ( .COUT(c[i+1]), .CIN(c[i]), .A(a[i]), .B(b[i]), .SUM(s[i]) );
+ endgenerate
+
+endmodule
+
+module csa8_4(
+ input [7:0] a, b,
+ input ci,
+ output [7:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [3:0] s10, s11;
+ rca #(4) A0 (.a(a[3:0]), .b(b[3:0]), .ci(ci), .co(co0), .s(s[3:0]) );
+ rca #(4) A10 (.a(a[7:4]), .b(b[7:4]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(4) A11 (.a(a[7:4]), .b(b[7:4]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [3:0] ( .X(s[7:4]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa16_8(
+ input [15:0] a, b,
+ input ci,
+ output [15:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [7:0] s10, s11;
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [7:0] ( .X(s[15:8]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8x4(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ csa8_4 A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ csa8_4 A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ csa8_4 A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ csa8_4 A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ csa8_4 A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ csa8_4 A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ csa8_4 A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+
+// 32-bit Carry Select Adder 2x16rca
+module csa32_16(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+
+ wire co0, co10, co11;
+ wire [15:0] s10, s11;
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(1'b0), .co(co10), .s(s10) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(1'b1), .co(co11), .s(s11) );
+ `MUX2x1_CELL SMUX [15:0] ( .X(s[31:16]), .A0(s10), .A1(s11), .S(co0) );
+ `MUX2x1_CELL CMUX ( .X(co), .A0(co10), .A1(co11), .S(co0) );
+
+endmodule
+
+module csa32_8(
+ input [31:0] a, b,
+ input ci,
+ output [31:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [7:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(8) A0 (.a(a[7:0]), .b(b[7:0]), .ci(ci), .co(co0), .s(s[7:0]) );
+
+ rca #(8) A10 (.a(a[15:8]), .b(b[15:8]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(8) A11 (.a(a[15:8]), .b(b[15:8]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [7:0] ( .X(s[15:8]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(8) A20 (.a(a[23:16]), .b(b[23:16]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(8) A21 (.a(a[23:16]), .b(b[23:16]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [7:0] ( .X(s[23:16]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(8) A30 (.a(a[31:24]), .b(b[31:24]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(8) A31 (.a(a[31:24]), .b(b[31:24]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [7:0] ( .X(s[31:24]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[3]), .A1(c1[3]), .S(co2) );
+endmodule
+
+module csa64_16(
+ input [63:0] a, b,
+ input ci,
+ output [63:0] s,
+ output co
+);
+ wire co0, co1, co2, co3;
+ wire [3:1] c0, c1;
+ wire [15:0] s0[3:1], s1[3:1];
+ wire lo, hi;
+
+ `TIE_CELL TIE (.LO(lo), .HI(hi));
+
+ rca #(16) A0 (.a(a[15:0]), .b(b[15:0]), .ci(ci), .co(co0), .s(s[15:0]) );
+
+ rca #(16) A10 (.a(a[31:16]), .b(b[31:16]), .ci(lo), .co(c0[1]), .s(s0[1]) );
+ rca #(16) A11 (.a(a[31:16]), .b(b[31:16]), .ci(hi), .co(c1[1]), .s(s1[1]) );
+ `MUX2x1_CELL SMUX1 [15:0] ( .X(s[31:16]), .A0(s0[1]), .A1(s1[1]), .S(co0) );
+ `MUX2x1_CELL CMUX1 ( .X(co1), .A0(c0[1]), .A1(c1[1]), .S(co0) );
+
+ rca #(16) A20 (.a(a[47:32]), .b(b[47:32]), .ci(lo), .co(c0[2]), .s(s0[2]) );
+ rca #(16) A21 (.a(a[47:32]), .b(b[47:32]), .ci(hi), .co(c1[2]), .s(s1[2]) );
+ `MUX2x1_CELL SMUX2 [15:0] ( .X(s[47:32]), .A0(s0[2]), .A1(s1[2]), .S(co1) );
+ `MUX2x1_CELL CMUX2 ( .X(co2), .A0(c0[2]), .A1(c1[2]), .S(co1) );
+
+ rca #(16) A30 (.a(a[63:48]), .b(b[63:48]), .ci(lo), .co(c0[3]), .s(s0[3]) );
+ rca #(16) A31 (.a(a[63:48]), .b(b[63:48]), .ci(hi), .co(c1[3]), .s(s1[3]) );
+ `MUX2x1_CELL SMUX3 [15:0] ( .X(s[63:48]), .A0(s0[3]), .A1(s1[3]), .S(co2) );
+ `MUX2x1_CELL CMUX3 ( .X(co), .A0(c0[2]), .A1(c1[2]), .S(co2) );
+
+endmodule
+
+(* techmap_celltype = "$add" *)
+module sky130_csa (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add64(.a(AA), .b(BB), .ci(1'b0), .s(Y));
+ endgenerate
+
+endmodule
+
+(* techmap_celltype = "$sub" *)
+module sky130_csa_sub (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ (* force_downto *)
+ input [A_WIDTH-1:0] A;
+ (* force_downto *)
+ input [B_WIDTH-1:0] B;
+ (* force_downto *)
+ output [Y_WIDTH-1:0] Y;
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = (Y_WIDTH != 8) & (Y_WIDTH != 16) & (Y_WIDTH != 32) & (Y_WIDTH != 64);
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = ~B_buf;
+
+ generate
+ if (Y_WIDTH == 8)
+ csa8_4 add8(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 16)
+ csa16_8 add16(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ else if (Y_WIDTH == 32)
+ csa32_16 add32(.a(AA), .b(BB), .ci(1'b1),.s(Y));
+ else if (Y_WIDTH == 64)
+ csa64_16 add32(.a(AA), .b(BB), .ci(1'b1), .s(Y));
+ endgenerate
+
+endmodule