diff --git a/hw/ip/prim/README.md b/hw/ip/prim/README.md index 6698ca9f4c2bd..ea4cf8d7766ba 100644 --- a/hw/ip/prim/README.md +++ b/hw/ip/prim/README.md @@ -348,9 +348,9 @@ After synthesizing the top module `prim_sdc_example` the following checks should 1. In the synthesized netlist, the following number of size_only instances must be present: -| cell names | buf | and2 | xor | xnor | flop | clock_mux2 | clock_gating | -| -----------| ---- |------|----- |------ |------|------------|--------------| -| #instances | 328 | 56 | 120 | 56 | 252 | 2 | 2 | +| cell names | buf | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | +| -----------| ---- |------|----- |------ |------|-----|------------|--------------| +| #instances | 328 | 56 | 120 | 56 | 252 | 32 | 2 | 2 | 2. None of the test_*_o signals can be driven by a constant 0 or 1. The instantiated `size_only` instances must prevent logic optimizations and keep the output comparators. diff --git a/hw/ip/prim/prim.core b/hw/ip/prim/prim.core index befc14071f576..557274a1414e2 100644 --- a/hw/ip/prim/prim.core +++ b/hw/ip/prim/prim.core @@ -15,6 +15,7 @@ filesets: - lowrisc:prim:pad_wrapper - lowrisc:prim:clock_mux2 - lowrisc:prim:clock_inv + - lowrisc:prim:const - lowrisc:prim:buf - lowrisc:prim:flop - lowrisc:prim:flop_en diff --git a/hw/ip/prim/prim_sec_anchor.core b/hw/ip/prim/prim_sec_anchor.core index 12f574927fe63..0335cc60ecbd5 100644 --- a/hw/ip/prim/prim_sec_anchor.core +++ b/hw/ip/prim/prim_sec_anchor.core @@ -9,6 +9,7 @@ filesets: files_rtl: files: - rtl/prim_sec_anchor_buf.sv + - rtl/prim_sec_anchor_const.sv - rtl/prim_sec_anchor_flop.sv file_type: systemVerilogSource depend: diff --git a/hw/ip/prim/rtl/prim_sdc_example.sv b/hw/ip/prim/rtl/prim_sdc_example.sv index 5d64d0da2529b..b0c56ab3b6c56 100644 --- a/hw/ip/prim/rtl/prim_sdc_example.sv +++ b/hw/ip/prim/rtl/prim_sdc_example.sv @@ -9,21 +9,21 @@ // // 1. In the synthesized netlist, the following number of size_only instances must be present: // e.g. grep -c -R u_size_only_x netlist.v (make sure the design is uniquified) -// |-------------------------------------------------------------------| -// | Test | buf | and2 | xor | xnor | flop | clock_mux2 | clock_gating | -// | -----| ----|------|-----|------|------|------------|--------------| -// | 1 | 192 | - | - | - | - | - | - | -// | 2 | - | - | 64 | - | - | - | - | -// | 3 | 48 | 48 | 48 | 48 | 144 | - | - | -// | 4 | 8 | 8 | 8 | 8 | 24 | - | - | -// | 5 | 36 | - | - | - | 24 | - | - | -// | 6 | 16 | - | - | - | 8 | - | - | -// | 7 | - | - | - | - | 32 | 2 | 2 | -// | 8 | 16 | - | - | - | 8 | - | - | -// | 9 | 12 | - | - | - | 12 | - | - | -// | -----| ----|------|-----|------|------|------------|--------------| -// |total | 328 | 56 | 120 | 56 | 252 | 2 | 2 | -// |-------------------------------------------------------------------| +// |-------------------------------------------------------------------------| +// | Test | buf | and2 | xor | xnor | flop | tie | clock_mux2 | clock_gating | +// | -----| ----|------|-----|------|------|-----|------------|--------------| +// | 1 | 192 | - | - | - | - | 32 | - | - | +// | 2 | - | - | 64 | - | - | - | - | - | +// | 3 | 48 | 48 | 48 | 48 | 144 | - | - | - | +// | 4 | 8 | 8 | 8 | 8 | 24 | - | - | - | +// | 5 | 36 | - | - | - | 24 | - | - | - | +// | 6 | 16 | - | - | - | 8 | - | - | - | +// | 7 | - | - | - | - | 32 | - | 2 | 2 | +// | 8 | 16 | - | - | - | 8 | - | - | - | +// | 9 | 12 | - | - | - | 12 | - | - | - | +// | -----| ----|------|-----|------|------|-----|------------|--------------| +// |total | 328 | 56 | 120 | 56 | 252 | 32 | 2 | 2 | +// |-------------------------------------------------------------------------| // // 2. None of the test_*_o signals can be driven by a constant 0 or 1. // The instantiated size_only instances must prevent logic optimizations and keep @@ -76,12 +76,22 @@ module prim_sdc_example #( // It is not allowed that arithmetic operations are merged across prim_bufs // The following size_only cells are expected: // 6*32 size_only_buf + // It is not allowed to combine consts: + // 32 size_only TIE cells are expected localparam int unsigned NumStages = 3; - localparam int unsigned ConstA = 32'h0FF0_ABBA; + localparam logic [31:0] ConstA = 32'h0FF0_ABBA; logic [NumStages-1:0][31:0] res, res_buf; logic [31:0] data_a, data_b, data_c; + logic [31:0] const_a; + + prim_const #( + .Width(32), + .ConstVal(ConstA) + ) u_const_a ( + .out_o(const_a) + ); prim_buf #( .Width(32) @@ -113,7 +123,7 @@ module prim_sdc_example #( .out_o(res_buf[0]) ); - assign res[1] = res_buf[0] + ConstA; + assign res[1] = res_buf[0] + const_a; prim_buf #( .Width(32) diff --git a/hw/ip/prim/rtl/prim_sec_anchor_const.sv b/hw/ip/prim/rtl/prim_sec_anchor_const.sv new file mode 100644 index 0000000000000..fec7579468e03 --- /dev/null +++ b/hw/ip/prim/rtl/prim_sec_anchor_const.sv @@ -0,0 +1,21 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "prim_assert.sv" + +module prim_sec_anchor_const #( + parameter int Width = 1, + parameter logic [Width-1:0] ConstVal = '0 +) ( + output logic [Width-1:0] out_o +); + + prim_const #( + .Width(Width), + .ConstVal(ConstVal) + ) u_secure_anchor_const ( + .out_o + ); + +endmodule diff --git a/hw/ip/prim_asap7/prim_asap7.core b/hw/ip/prim_asap7/prim_asap7.core index 4f139415cecfe..0246a9f85a646 100644 --- a/hw/ip/prim_asap7/prim_asap7.core +++ b/hw/ip/prim_asap7/prim_asap7.core @@ -20,6 +20,7 @@ filesets: - lowrisc:prim_asap7:clock_inv - lowrisc:prim_asap7:clock_mux2 - lowrisc:prim_asap7:flop + - lowrisc:prim_asap7:const - lowrisc:prim_generic:flop_2sync - lowrisc:prim_generic:rst_sync - lowrisc:prim_asap7:flop_en @@ -46,6 +47,7 @@ mapping: "lowrisc:prim:clock_gating" : "lowrisc:prim_asap7:clock_gating" "lowrisc:prim:clock_inv" : "lowrisc:prim_asap7:clock_inv" "lowrisc:prim:clock_mux2" : "lowrisc:prim_asap7:clock_mux2" + "lowrisc:prim:const" : "lowrisc:prim_asap7:const" "lowrisc:prim:flop" : "lowrisc:prim_asap7:flop" "lowrisc:prim:flop_2sync" : "lowrisc:prim_generic:flop_2sync" "lowrisc:prim:rst_sync" : "lowrisc:prim_generic:rst_sync" diff --git a/hw/ip/prim_asap7/prim_asap7_const.core b/hw/ip/prim_asap7/prim_asap7_const.core new file mode 100644 index 0000000000000..fc7880f96e8f4 --- /dev/null +++ b/hw/ip/prim_asap7/prim_asap7_const.core @@ -0,0 +1,38 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_asap7:const" +description: "asap7 const instantiation with TIE cells" +virtual: + - lowrisc:prim:const + +filesets: + files_rtl: + files: + - rtl/prim_const.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/hw/ip/prim_asap7/rtl/prim_const.sv b/hw/ip/prim_asap7/rtl/prim_const.sv new file mode 100644 index 0000000000000..1878b64e902fd --- /dev/null +++ b/hw/ip/prim_asap7/rtl/prim_const.sv @@ -0,0 +1,30 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// This module utilizes manual instantiation of standard cells to define constant values. By +// employing dedicated TIE cells or specific logic gates and disabling tool-driven optimization, we +// ensure that constants remain accessible for modification via metal-layer engineering change +// orders (ECOs). Means of changing the value should be provisioned in the physical design, +// such as spare inverters, TIE cells of opposite value, or metal-configurable cells. + +module prim_const #( + parameter int Width = 1, + parameter logic [Width-1:0] ConstVal = '0 +) ( + output logic [Width-1:0] out_o +); + + for (genvar i = 0; i < Width; i++) begin : gen_bits + if (ConstVal[i]) begin : gen_hi + TIEHIx1_ASAP7_75t_L u_size_only_tie_hi ( + .H (out_o[i]) + ); + end else begin : gen_lo + TIELOx1_ASAP7_75t_L u_size_only_tie_lo ( + .L (out_o[i]) + ); + end + end + +endmodule diff --git a/hw/ip/prim_generic/prim_generic.core b/hw/ip/prim_generic/prim_generic.core index e7f3a43db6ff9..1ae5d5bf819a7 100644 --- a/hw/ip/prim_generic/prim_generic.core +++ b/hw/ip/prim_generic/prim_generic.core @@ -17,6 +17,7 @@ filesets: - lowrisc:prim_generic:clock_gating - lowrisc:prim_generic:clock_inv - lowrisc:prim_generic:clock_mux2 + - lowrisc:prim_generic:const - lowrisc:prim_generic:flop - lowrisc:prim_generic:flop_2sync - lowrisc:prim_generic:rst_sync @@ -44,6 +45,7 @@ mapping: "lowrisc:prim:clock_gating" : "lowrisc:prim_generic:clock_gating" "lowrisc:prim:clock_inv" : "lowrisc:prim_generic:clock_inv" "lowrisc:prim:clock_mux2" : "lowrisc:prim_generic:clock_mux2" + "lowrisc:prim:const" : "lowrisc:prim_generic:const" "lowrisc:prim:flop" : "lowrisc:prim_generic:flop" "lowrisc:prim:flop_2sync" : "lowrisc:prim_generic:flop_2sync" "lowrisc:prim:rst_sync" : "lowrisc:prim_generic:rst_sync" diff --git a/hw/ip/prim_generic/prim_generic_const.core b/hw/ip/prim_generic/prim_generic_const.core new file mode 100644 index 0000000000000..eac35a49fbffc --- /dev/null +++ b/hw/ip/prim_generic/prim_generic_const.core @@ -0,0 +1,38 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: "lowrisc:prim_generic:const" +description: "const instantiation" +virtual: + - lowrisc:prim:const + +filesets: + files_rtl: + files: + - rtl/prim_const.sv + file_type: systemVerilogSource + + files_verilator_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_ascentlint_waiver: + depend: + # common waivers + - lowrisc:lint:common + + files_veriblelint_waiver: + depend: + # common waivers + - lowrisc:lint:common + +targets: + default: + filesets: + - tool_verilator ? (files_verilator_waiver) + - tool_ascentlint ? (files_ascentlint_waiver) + - tool_veriblelint ? (files_veriblelint_waiver) + - files_rtl diff --git a/hw/ip/prim_generic/rtl/prim_const.sv b/hw/ip/prim_generic/rtl/prim_const.sv new file mode 100644 index 0000000000000..98f18604da2f1 --- /dev/null +++ b/hw/ip/prim_generic/rtl/prim_const.sv @@ -0,0 +1,29 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// This module utilizes manual instantiation of standard cells to define constant values. By +// employing dedicated TIE cells or specific logic gates and disabling tool-driven optimization, we +// ensure that constants remain accessible for modification via metal-layer engineering change +// orders (ECOs). Means of changing the value should be provisioned in the physical design, +// such as spare inverters, TIE cells of opposite value, or metal-configurable cells. +// The generic implementation is done with assign statements. + +module prim_const #( + parameter int Width = 1, + parameter logic [Width-1:0] ConstVal = '0 +) ( + output logic [Width-1:0] out_o +); + + for (genvar i = 0; i < Width; i++) begin : gen_bits + if (ConstVal[i]) begin : gen_hi + // instantiate size_only TIE-HI + assign out_o[i] = 1'b1; + end else begin : gen_lo + // instantiate size_only TIE-LO + assign out_o[i] = 1'b0; + end + end + +endmodule diff --git a/hw/ip/prim_xilinx/prim_xilinx.core b/hw/ip/prim_xilinx/prim_xilinx.core index c456b761e1f5f..0b806abeeb441 100644 --- a/hw/ip/prim_xilinx/prim_xilinx.core +++ b/hw/ip/prim_xilinx/prim_xilinx.core @@ -17,6 +17,7 @@ filesets: - lowrisc:prim_xilinx:clock_gating - lowrisc:prim_generic:clock_inv - lowrisc:prim_xilinx:clock_mux2 + - lowrisc:prim_generic:const - lowrisc:prim_xilinx:flop - lowrisc:prim_generic:flop_2sync - lowrisc:prim_generic:rst_sync @@ -43,6 +44,7 @@ mapping: "lowrisc:prim:clock_gating" : lowrisc:prim_xilinx:clock_gating "lowrisc:prim:clock_inv" : lowrisc:prim_generic:clock_inv "lowrisc:prim:clock_mux2" : lowrisc:prim_xilinx:clock_mux2 + "lowrisc:prim:const" : lowrisc:prim_generic:const "lowrisc:prim:flop" : lowrisc:prim_xilinx:flop "lowrisc:prim:flop_2sync" : lowrisc:prim_generic:flop_2sync "lowrisc:prim:rst_sync" : lowrisc:prim_generic:rst_sync diff --git a/hw/ip/prim_xilinx_ultrascale/prim_xilinx_ultrascale.core b/hw/ip/prim_xilinx_ultrascale/prim_xilinx_ultrascale.core index 52b20dc27668a..e2bdd8e4ea21f 100644 --- a/hw/ip/prim_xilinx_ultrascale/prim_xilinx_ultrascale.core +++ b/hw/ip/prim_xilinx_ultrascale/prim_xilinx_ultrascale.core @@ -17,6 +17,7 @@ filesets: - lowrisc:prim_xilinx_ultrascale:clock_gating - lowrisc:prim_xilinx_ultrascale:clock_inv - lowrisc:prim_xilinx:clock_mux2 + - lowrisc:prim_generic:const - lowrisc:prim_xilinx:flop - lowrisc:prim_generic:flop_2sync - lowrisc:prim_generic:rst_sync @@ -43,6 +44,7 @@ mapping: "lowrisc:prim:clock_gating" : lowrisc:prim_xilinx_ultrascale:clock_gating "lowrisc:prim:clock_inv" : lowrisc:prim_xilinx_ultrascale:clock_inv "lowrisc:prim:clock_mux2" : lowrisc:prim_xilinx:clock_mux2 + "lowrisc:prim:const" : lowrisc:prim_generic:const "lowrisc:prim:flop" : lowrisc:prim_xilinx:flop "lowrisc:prim:flop_2sync" : lowrisc:prim_generic:flop_2sync "lowrisc:prim:rst_sync" : lowrisc:prim_generic:rst_sync diff --git a/hw/ip_templates/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/ip_templates/otp_ctrl/rtl/otp_ctrl_scrmbl.sv index c245fc5c07e19..4ccf679b11f06 100644 --- a/hw/ip_templates/otp_ctrl/rtl/otp_ctrl_scrmbl.sv +++ b/hw/ip_templates/otp_ctrl/rtl/otp_ctrl_scrmbl.sv @@ -109,26 +109,26 @@ module otp_ctrl_scrmbl digest_iv_array_t rnd_cnst_digest_iv_anchor; for (genvar i = 0; i < NumScrmblKeys; i++) begin : gen_anchor_keys - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_key_anchor_buf ( - .in_i(RndCnstKey[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstKey[i]) + ) u_key_anchor_const ( .out_o(rnd_cnst_key_anchor[i]) ); end for (genvar i = 0; i < NumDigestSets; i++) begin : gen_anchor_digests - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_const_anchor_buf ( - .in_i(RndCnstDigestConst[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstDigestConst[i]) + ) u_digest_anchor_const ( .out_o(rnd_cnst_digest_anchor[i]) ); - prim_sec_anchor_buf #( - .Width(ScrmblBlockWidth) - ) u_iv_anchor_buf ( - .in_i(RndCnstDigestIV[i]), + prim_sec_anchor_const #( + .Width(ScrmblBlockWidth), + .ConstVal(RndCnstDigestIV[i]) + ) u_iv_anchor_const ( .out_o(rnd_cnst_digest_iv_anchor[i]) ); end diff --git a/hw/top_darjeeling/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/top_darjeeling/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv index c245fc5c07e19..4ccf679b11f06 100644 --- a/hw/top_darjeeling/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv +++ b/hw/top_darjeeling/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv @@ -109,26 +109,26 @@ module otp_ctrl_scrmbl digest_iv_array_t rnd_cnst_digest_iv_anchor; for (genvar i = 0; i < NumScrmblKeys; i++) begin : gen_anchor_keys - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_key_anchor_buf ( - .in_i(RndCnstKey[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstKey[i]) + ) u_key_anchor_const ( .out_o(rnd_cnst_key_anchor[i]) ); end for (genvar i = 0; i < NumDigestSets; i++) begin : gen_anchor_digests - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_const_anchor_buf ( - .in_i(RndCnstDigestConst[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstDigestConst[i]) + ) u_digest_anchor_const ( .out_o(rnd_cnst_digest_anchor[i]) ); - prim_sec_anchor_buf #( - .Width(ScrmblBlockWidth) - ) u_iv_anchor_buf ( - .in_i(RndCnstDigestIV[i]), + prim_sec_anchor_const #( + .Width(ScrmblBlockWidth), + .ConstVal(RndCnstDigestIV[i]) + ) u_iv_anchor_const ( .out_o(rnd_cnst_digest_iv_anchor[i]) ); end diff --git a/hw/top_earlgrey/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/top_earlgrey/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv index c245fc5c07e19..4ccf679b11f06 100644 --- a/hw/top_earlgrey/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv +++ b/hw/top_earlgrey/ip_autogen/otp_ctrl/rtl/otp_ctrl_scrmbl.sv @@ -109,26 +109,26 @@ module otp_ctrl_scrmbl digest_iv_array_t rnd_cnst_digest_iv_anchor; for (genvar i = 0; i < NumScrmblKeys; i++) begin : gen_anchor_keys - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_key_anchor_buf ( - .in_i(RndCnstKey[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstKey[i]) + ) u_key_anchor_const ( .out_o(rnd_cnst_key_anchor[i]) ); end for (genvar i = 0; i < NumDigestSets; i++) begin : gen_anchor_digests - prim_sec_anchor_buf #( - .Width(ScrmblKeyWidth) - ) u_const_anchor_buf ( - .in_i(RndCnstDigestConst[i]), + prim_sec_anchor_const #( + .Width(ScrmblKeyWidth), + .ConstVal(RndCnstDigestConst[i]) + ) u_digest_anchor_const ( .out_o(rnd_cnst_digest_anchor[i]) ); - prim_sec_anchor_buf #( - .Width(ScrmblBlockWidth) - ) u_iv_anchor_buf ( - .in_i(RndCnstDigestIV[i]), + prim_sec_anchor_const #( + .Width(ScrmblBlockWidth), + .ConstVal(RndCnstDigestIV[i]) + ) u_iv_anchor_const ( .out_o(rnd_cnst_digest_iv_anchor[i]) ); end diff --git a/util/design/check-netlist.py b/util/design/check-netlist.py index 1947d3d1f88bd..5081843d48f93 100755 --- a/util/design/check-netlist.py +++ b/util/design/check-netlist.py @@ -24,7 +24,7 @@ class Parser: "u_size_only", "u_size_only_xor", "u_size_only_xnor", "u_size_only_and", "u_size_only_mux", "u_size_only_flop", "u_size_only_buf", - "u_size_only_clock_gate" + "u_size_only_tie", "u_size_only_clock_gate" ] # Regex to find ".lc_en_i, ( ... )" and capture the content