From 145c7362ca46ebe35e6cff4499b3f12a9908b1be Mon Sep 17 00:00:00 2001 From: Felipe Garay Date: Wed, 24 May 2023 16:58:44 -0700 Subject: [PATCH 1/2] dft: Adding support for clock mixing Signed-off-by: Felipe Garay --- src/dft/src/architect/ScanArchitect.cpp | 9 +- src/dft/src/clock_domain/ClockDomain.cpp | 2 + src/dft/src/config/ScanArchitectConfig.cpp | 2 + src/dft/src/config/ScanArchitectConfig.hh | 3 +- src/dft/src/dft.i | 18 ++ src/dft/src/dft.tcl | 8 +- src/dft/test/regression_tests.tcl | 1 + .../test/scan_architect_clock_mix_sky130.ok | 58 ++++++ .../test/scan_architect_clock_mix_sky130.tcl | 32 +++ .../test/scan_architect_clock_mix_sky130.vok | 187 ++++++++++++++++++ 10 files changed, 317 insertions(+), 3 deletions(-) create mode 100644 src/dft/test/scan_architect_clock_mix_sky130.ok create mode 100644 src/dft/test/scan_architect_clock_mix_sky130.tcl create mode 100644 src/dft/test/scan_architect_clock_mix_sky130.vok diff --git a/src/dft/src/architect/ScanArchitect.cpp b/src/dft/src/architect/ScanArchitect.cpp index 4cc19f15b68..da9e4b65b20 100644 --- a/src/dft/src/architect/ScanArchitect.cpp +++ b/src/dft/src/architect/ScanArchitect.cpp @@ -45,7 +45,14 @@ bool CompareScanCells(const std::shared_ptr& lhs, // If they have the same number of bits, then we compare the names of the // cells so they are ordered by name if (lhs->getBits() == rhs->getBits()) { - return lhs->getName() < rhs->getName(); + const ClockDomain& lhs_clock_domain = lhs->getClockDomain(); + const ClockDomain& rhs_clock_domain = rhs->getClockDomain(); + + if (lhs_clock_domain.getClockName() == rhs_clock_domain.getClockName()) { + return lhs_clock_domain.getClockEdge() < rhs_clock_domain.getClockEdge(); + } + + return lhs_clock_domain.getClockName() < rhs_clock_domain.getClockName(); } // Bigger elements last return lhs->getBits() < rhs->getBits(); diff --git a/src/dft/src/clock_domain/ClockDomain.cpp b/src/dft/src/clock_domain/ClockDomain.cpp index 33cc45605ff..d353a115110 100644 --- a/src/dft/src/clock_domain/ClockDomain.cpp +++ b/src/dft/src/clock_domain/ClockDomain.cpp @@ -45,6 +45,8 @@ std::function GetClockDomainHashFn( return std::hash{}(clock_domain.getClockName()) ^ std::hash{}(clock_domain.getClockEdge()); }; + case ScanArchitectConfig::ClockMixing::ClockMix: + return [](const ClockDomain& clock_domain) { return 1; }; default: // Not implemented logger->error(utl::DFT, 4, "Clock mix config requested is not supported"); diff --git a/src/dft/src/config/ScanArchitectConfig.cpp b/src/dft/src/config/ScanArchitectConfig.cpp index 9e2f7712e5d..ef25174e36c 100644 --- a/src/dft/src/config/ScanArchitectConfig.cpp +++ b/src/dft/src/config/ScanArchitectConfig.cpp @@ -69,6 +69,8 @@ std::string ScanArchitectConfig::ClockMixingName( switch (clock_mixing) { case ScanArchitectConfig::ClockMixing::NoMix: return "No Mix"; + case ScanArchitectConfig::ClockMixing::ClockMix: + return "Clock Mix"; default: return "Missing case in ClockMixingName"; } diff --git a/src/dft/src/config/ScanArchitectConfig.hh b/src/dft/src/config/ScanArchitectConfig.hh index 98a2a41aca3..2c9628921c0 100644 --- a/src/dft/src/config/ScanArchitectConfig.hh +++ b/src/dft/src/config/ScanArchitectConfig.hh @@ -44,7 +44,8 @@ class ScanArchitectConfig // TODO Add suport for mix_edges, mix_clocks, mix_clocks_not_edges enum class ClockMixing { - NoMix // We create different scan chains for each clock and edge + NoMix, // We create different scan chains for each clock and edge + ClockMix // We architect the flops of different clock and edge together }; void setClockMixing(ClockMixing clock_mixing); diff --git a/src/dft/src/dft.i b/src/dft/src/dft.i index 0fc7ac4f74a..49745e63e3d 100644 --- a/src/dft/src/dft.i +++ b/src/dft/src/dft.i @@ -37,12 +37,18 @@ #include "dft/Dft.hh" #include "DftConfig.hh" #include "ord/OpenRoad.hh" +#include "ScanArchitect.hh" dft::Dft * getDft() { return ord::OpenRoad::openRoad()->getDft(); } +utl::Logger* getLogger() +{ + return ord::OpenRoad::openRoad()->getLogger(); +} + %} %inline @@ -63,6 +69,18 @@ void set_dft_config_max_length(int max_length) getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setMaxLength(max_length); } +void set_dft_config_clock_mixing(const char* clock_mixing_ptr) +{ + std::string_view clock_mixing(clock_mixing_ptr); + if (clock_mixing == "no_mix") { + getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setClockMixing(dft::ScanArchitectConfig::ClockMixing::NoMix); + } else if (clock_mixing == "clock_mix") { + getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setClockMixing(dft::ScanArchitectConfig::ClockMixing::ClockMix); + } else { + getLogger()->error(utl::DFT, 5, "Requested clock mixing config not valid"); + } +} + void report_dft_config() { getDft()->reportDftConfig(); } diff --git a/src/dft/src/dft.tcl b/src/dft/src/dft.tcl index ccdd78e934e..77a6c9b7d98 100644 --- a/src/dft/src/dft.tcl +++ b/src/dft/src/dft.tcl @@ -47,7 +47,7 @@ proc insert_dft {} { proc set_dft_config { args } { sta::parse_key_args "set_dft_config" args \ - keys {-max_length} \ + keys {-max_length -clock_mixing} \ flags {} sta::check_argc_eq0 "set_dft_config" $args @@ -57,6 +57,12 @@ proc set_dft_config { args } { sta::check_positive_integer "-max_length" $max_length dft::set_dft_config_max_length $max_length } + + if [info exists keys(-clock_mixing)] { + set clock_mixing $keys(-clock_mixing) + puts $clock_mixing + dft::set_dft_config_clock_mixing $clock_mixing + } } proc report_dft_config {} { diff --git a/src/dft/test/regression_tests.tcl b/src/dft/test/regression_tests.tcl index 0f3c35e19f5..816fb50f1c3 100644 --- a/src/dft/test/regression_tests.tcl +++ b/src/dft/test/regression_tests.tcl @@ -3,6 +3,7 @@ record_tests { one_cell_nangate45 sub_modules_sky130 scan_architect_no_mix_sky130 + scan_architect_clock_mix_sky130 } diff --git a/src/dft/test/scan_architect_clock_mix_sky130.ok b/src/dft/test/scan_architect_clock_mix_sky130.ok new file mode 100644 index 00000000000..a59fabb1c62 --- /dev/null +++ b/src/dft/test/scan_architect_clock_mix_sky130.ok @@ -0,0 +1,58 @@ +[INFO ODB-0222] Reading LEF file: sky130hd/sky130hd.tlef +[INFO ODB-0223] Created 13 technology layers +[INFO ODB-0224] Created 25 technology vias +[INFO ODB-0226] Finished LEF file: sky130hd/sky130hd.tlef +[INFO ODB-0222] Reading LEF file: sky130hd/sky130_fd_sc_hd_merged.lef +[INFO ODB-0225] Created 437 library cells +[INFO ODB-0226] Finished LEF file: sky130hd/sky130_fd_sc_hd_merged.lef +clock_mix +*************************** +Preview DFT Report +Number of chains: 7 +Clock domain: Clock Mix +*************************** + +Scan chain 'chain_0' has 3 cells (3 bits) + + ff8_clk2_falling (clock2, falling) + ff2_clk2_falling + ff6_clk2_falling + +Scan chain 'chain_1' has 3 cells (3 bits) + + ff10_clk2_falling (clock2, falling) + ff4_clk2_falling + ff10_clk2_rising + +Scan chain 'chain_2' has 3 cells (3 bits) + + ff8_clk2_rising (clock2, rising) + ff2_clk2_rising + ff6_clk2_rising + +Scan chain 'chain_3' has 3 cells (3 bits) + + ff1_clk1_falling (clock1, falling) + ff3_clk1_falling + ff4_clk2_rising (clock2, rising) + +Scan chain 'chain_4' has 3 cells (3 bits) + + ff7_clk1_falling (clock1, falling) + ff9_clk1_falling + ff5_clk1_falling + +Scan chain 'chain_5' has 3 cells (3 bits) + + ff3_clk1_rising (clock1, rising) + ff5_clk1_rising + ff7_clk1_rising + +Scan chain 'chain_6' has 2 cells (2 bits) + + ff1_clk1_rising (clock1, rising) + ff9_clk1_rising + + +No differences found. +No differences found. diff --git a/src/dft/test/scan_architect_clock_mix_sky130.tcl b/src/dft/test/scan_architect_clock_mix_sky130.tcl new file mode 100644 index 00000000000..231eb16bc86 --- /dev/null +++ b/src/dft/test/scan_architect_clock_mix_sky130.tcl @@ -0,0 +1,32 @@ +source "helpers.tcl" + +read_lef sky130hd/sky130hd.tlef +read_lef sky130hd/sky130_fd_sc_hd_merged.lef +read_liberty sky130hd/sky130_fd_sc_hd__tt_025C_1v80.lib + +read_verilog scan_architect_sky130.v +link_design scan_architect + +create_clock -name clock1 -period 2.0000 -waveform {0.0000 1.0000} [get_ports {clock1}] +create_clock -name clock2 -period 2.0000 -waveform {0.0000 1.0000} [get_ports {clock2}] + +set_dft_config -max_length 3 -clock_mixing clock_mix + + +set verilog_file_before_preview [make_result_file scan_architect_clock_mix_sky130_before_preview.v] +write_verilog -sort $verilog_file_before_preview + +preview_dft -verbose + +# Preview should not modify the net +set verilog_file_after_preview [make_result_file scan_architect_clock_mix_sky130_after_preview.v] +write_verilog -sort $verilog_file_after_preview + +# Before and after preview, the netlist should be the same +diff_files $verilog_file_after_preview $verilog_file_before_preview + +insert_dft + +set verilog_file [make_result_file scan_architect_clock_mix_sky130.v] +write_verilog $verilog_file +diff_files $verilog_file scan_architect_clock_mix_sky130.vok diff --git a/src/dft/test/scan_architect_clock_mix_sky130.vok b/src/dft/test/scan_architect_clock_mix_sky130.vok new file mode 100644 index 00000000000..25f9a4f7372 --- /dev/null +++ b/src/dft/test/scan_architect_clock_mix_sky130.vok @@ -0,0 +1,187 @@ +module scan_architect (clock1, + clock2, + output1, + output10, + output11, + output12, + output13, + output14, + output15, + output16, + output17, + output18, + output19, + output2, + output20, + output3, + output4, + output5, + output6, + output7, + output8, + output9, + port1, + set_b, + scan_enable_1, + scan_in_1, + scan_in_2, + scan_in_3, + scan_in_4, + scan_in_5, + scan_in_6, + scan_in_7); + input clock1; + input clock2; + output output1; + output output10; + output output11; + output output12; + output output13; + output output14; + output output15; + output output16; + output output17; + output output18; + output output19; + output output2; + output output20; + output output3; + output output4; + output output5; + output output6; + output output7; + output output8; + output output9; + input port1; + input set_b; + input scan_enable_1; + input scan_in_1; + input scan_in_2; + input scan_in_3; + input scan_in_4; + input scan_in_5; + input scan_in_6; + input scan_in_7; + + + sky130_fd_sc_hd__sdfsbp_1 ff1_clk1_rising (.D(port1), + .Q(output1), + .SCD(scan_in_7), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock1)); + sky130_fd_sc_hd__sdfbbn_1 ff2_clk2_falling (.D(port1), + .Q(output12), + .SCD(output18), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock2)); + sky130_fd_sc_hd__sdfsbp_1 ff2_clk2_rising (.D(port1), + .Q(output2), + .SCD(output8), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock2)); + sky130_fd_sc_hd__sdfbbn_1 ff3_clk1_falling (.D(port1), + .Q(output13), + .SCD(output11), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock1)); + sky130_fd_sc_hd__sdfsbp_1 ff3_clk1_rising (.D(port1), + .Q(output3), + .SCD(scan_in_6), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock1)); + sky130_fd_sc_hd__sdfbbn_1 ff4_clk2_falling (.D(port1), + .Q(output14), + .SCD(output20), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock2)); + sky130_fd_sc_hd__sdfsbp_1 ff4_clk2_rising (.D(port1), + .Q(output4), + .SCD(output13), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock2)); + sky130_fd_sc_hd__sdfbbn_1 ff5_clk1_falling (.D(port1), + .Q(output15), + .SCD(output19), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock1)); + sky130_fd_sc_hd__sdfsbp_1 ff5_clk1_rising (.D(port1), + .Q(output5), + .SCD(output3), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock1)); + sky130_fd_sc_hd__sdfbbn_1 ff6_clk2_falling (.D(port1), + .Q(output16), + .SCD(output12), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock2)); + sky130_fd_sc_hd__sdfsbp_1 ff6_clk2_rising (.D(port1), + .Q(output6), + .SCD(output2), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock2)); + sky130_fd_sc_hd__sdfbbn_1 ff7_clk1_falling (.D(port1), + .Q(output17), + .SCD(scan_in_5), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock1)); + sky130_fd_sc_hd__sdfsbp_1 ff7_clk1_rising (.D(port1), + .Q(output7), + .SCD(output5), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock1)); + sky130_fd_sc_hd__sdfbbn_1 ff8_clk2_falling (.D(port1), + .Q(output18), + .SCD(scan_in_1), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock2)); + sky130_fd_sc_hd__sdfsbp_1 ff8_clk2_rising (.D(port1), + .Q(output8), + .SCD(scan_in_3), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock2)); + sky130_fd_sc_hd__sdfbbn_1 ff9_clk1_falling (.D(port1), + .Q(output19), + .SCD(output17), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock1)); + sky130_fd_sc_hd__sdfsbp_1 ff9_clk1_rising (.D(port1), + .Q(output9), + .SCD(output1), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock1)); + sky130_fd_sc_hd__sdfbbn_1 ff10_clk2_falling (.D(port1), + .Q(output20), + .SCD(scan_in_2), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock2)); + sky130_fd_sc_hd__sdfsbp_1 ff10_clk2_rising (.D(port1), + .Q(output10), + .SCD(output14), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK(clock2)); + sky130_fd_sc_hd__sdfbbn_1 ff1_clk1_falling (.D(port1), + .Q(output11), + .SCD(scan_in_4), + .SCE(scan_enable_1), + .SET_B(set_b), + .CLK_N(clock1)); +endmodule From 54af2a1efa0ea57b8b95f052fceefeb582814e27 Mon Sep 17 00:00:00 2001 From: Felipe Garay Date: Fri, 26 May 2023 17:28:10 -0700 Subject: [PATCH 2/2] dft: updating readme to document current status of the tool Signed-off-by: Felipe Garay --- src/dft/README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/src/dft/README.md b/src/dft/README.md index 985c90d6e39..084c9a9a406 100644 --- a/src/dft/README.md +++ b/src/dft/README.md @@ -12,11 +12,80 @@ A simple DFT insertion consist of the following parts: * A scan_enable pin to allow your design to enter and leave the test mode. -# Supported Features +# TCL Commands -TODO +## set_dft_config +``` +set_dft_config [-max_length ] + [-clock_mixing ] +``` + +* `-max_length`: The maxinum number of bits that can be in each scan chain. +* `-clock_mixing`: How architect will mix the scan flops based on the clock driver. + * `no_mix`: Creates scan chains with only one type of clock and edge. This + may create unbalanced chains. + * `clock_mix`: Craetes scan chains mixing clocks and edges. Falling edge + flops are going to be stitched before rising edge. + +## report_dft_config + +``` +report_dft_config +``` + +Prints the current DFT configuration to be used by `preview_dft` and +`insert_dft`. + +## preview_dft + +``` +preview_dft [-verbose] +``` + +Prints a preview of the scan chains that will be stitched by `insert_dft`. Use +this command to iterate and try different DFT configurations. This command do +not perform any modification to the design. + +* `-verbose`: Shows more information about each one of the scan chains that will + be created. + + +## insert_dft + +``` +insert_dft +``` + +Implements the scan chains into the design by performing the following actions: + +1. Scan Replace. +2. Scan Architect. +3. Scan Stitch. + +The end result will be a design with scan flops connected to form the scan +chains. + +# Example + +This example will create scan chains with a max length of 10 bits mixing all the +scan flops in the scan chains. + +``` +set_dft_config -max_length 10 -clock_mixing clock_mix +report_dft_config +preview_dft -verbose +insert_dft +``` + +# Limitations + +* There are no optimizations for the scan chains. This is a WIP. +* There is no way to specify existing scan ports to be used by scan insertion. +* There is currently no way to define a user defined scan path. +* We can only work with one bit cells. + ## License BSD 3-Clause License. See [LICENSE](../../LICENSE) file.