Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sta/Sta.hh
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ public:
bool unconstrained_endpoints,
bool loops,
bool generated_clks);
void reportCheckTimingJson(const char *filename);
// Path from/thrus/to filter.
// from/thrus/to are owned and deleted by Search.
// PathEnds in the returned PathEndSeq are owned by Search PathGroups
Expand Down
69 changes: 63 additions & 6 deletions search/CheckTiming.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@

#include "CheckTiming.hh"

#include <fstream>
#include <string>

#include "ClkNetwork.hh"
#include "Error.hh"
#include "ExceptionPath.hh"
#include "Format.hh"
#include "Genclks.hh"
Expand Down Expand Up @@ -69,6 +73,7 @@ CheckTiming::clear()
{
deleteErrors();
errors_.clear();
json_results_.clear();
}

CheckErrorSeq &
Expand Down Expand Up @@ -120,7 +125,8 @@ CheckTiming::checkNoInputDelay()
}
}
delete pin_iter;
pushPinErrors("Warning: There {} {} input port{} missing set_input_delay.",no_arrival);
pushPinErrors("Warning: There {} {} input port{} missing set_input_delay.",
"no_input_delay", no_arrival);
}

void
Expand All @@ -129,7 +135,7 @@ CheckTiming::checkNoOutputDelay()
PinSet no_departure(network_);
checkNoOutputDelay(no_departure);
pushPinErrors("Warning: There {} {} output port{} missing set_output_delay.",
no_departure);
"no_output_delay", no_departure);
}

void
Expand Down Expand Up @@ -176,9 +182,9 @@ CheckTiming::checkRegClks(bool reg_multiple_clks,
multiple_clk_pins.insert(pin);
}
pushPinErrors("Warning: There {} {} unclocked register/latch pin{}.",
no_clk_pins);
"unclocked", no_clk_pins);
pushPinErrors("Warning: There {} {} register/latch pin{} with multiple clocks.",
multiple_clk_pins);
"multiple_clock", multiple_clk_pins);
}

static const char *
Expand Down Expand Up @@ -241,7 +247,7 @@ CheckTiming::checkUnconstrainedEndpoints()
checkUnconstrainedOutputs(unconstrained_ends);
checkUnconstrainedSetups(unconstrained_ends);
pushPinErrors("Warning: There {} {} unconstrained endpoint{}.",
unconstrained_ends);
"unconstrained", unconstrained_ends);
}

void
Expand Down Expand Up @@ -347,12 +353,13 @@ CheckTiming::checkGeneratedClocks()
}
}
pushClkErrors("Warning: There {} {} generated clock{} not connected to a clock source.",
gen_clk_errors);
"generated_clock", gen_clk_errors);
}

// Report the "msg" error for each pin in "pins".
void
CheckTiming::pushPinErrors(std::string_view msg,
const char *json_key,
PinSet &pins)
{
if (!pins.empty()) {
Expand All @@ -368,11 +375,13 @@ CheckTiming::pushPinErrors(std::string_view msg,
error->push_back(sdc_network_->pathName(pin));
}
errors_.push_back(error);
json_results_.emplace_back(json_key, StringSeq(error->begin() + 1, error->end()));
}
}

void
CheckTiming::pushClkErrors(const char *msg,
const char *json_key,
ClockSet &clks)
{
if (!clks.empty()) {
Expand All @@ -388,7 +397,55 @@ CheckTiming::pushClkErrors(const char *msg,
error->push_back(clk->name());
}
errors_.push_back(error);
json_results_.emplace_back(json_key, StringSeq(error->begin() + 1, error->end()));
}
}

static std::string
jsonEscape(const std::string &s)
{
std::string out;
for (char c : s) {
switch (c) {
case '"': out += "\\\""; break;
case '\\': out += "\\\\"; break;
default: out += c;
}
}
return out;
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.

void
CheckTiming::reportJson(const char *filename) const
{
std::ofstream stream(filename);
if (!stream.is_open())
throw FileNotWritable(filename);

// Start JSON object.
stream << "{\n";
size_t n = json_results_.size();
for (size_t i = 0; i < n; i++) {
const std::string &key = json_results_[i].first;
const StringSeq &names = json_results_[i].second;
stream << " \"" << key << "\": [";
for (size_t j = 0; j < names.size(); j++) {
stream << "\n \"" << jsonEscape(names[j]) << "\"";
// Comma between elements only; the last element must not be followed by one.
if (j + 1 < names.size())
stream << ",";
}
// Close the array on its own indented line when it has contents.
if (!names.empty())
stream << "\n ";
stream << "]";
// Trailing commas are invalid JSON.
if (i + 1 < n)
stream << ",";
stream << "\n";
}
// Close JSON object.
stream << "}\n";
}
Comment thread
stanminlee marked this conversation as resolved.

} // namespace sta
6 changes: 6 additions & 0 deletions search/CheckTiming.hh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@

#pragma once

#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "GraphClass.hh"
Expand Down Expand Up @@ -54,6 +56,7 @@ public:
bool unconstrained_endpoints,
bool loops,
bool generated_clks);
void reportJson(const char *filename) const;

protected:
void clear();
Expand All @@ -73,11 +76,14 @@ protected:
bool hasMaxDelay(Pin *pin);
void checkGeneratedClocks();
void pushPinErrors(std::string_view msg,
const char *json_key,
PinSet &pins);
void pushClkErrors(const char *msg,
const char *json_key,
ClockSet &clks);

CheckErrorSeq errors_;
std::vector<std::pair<std::string, StringSeq>> json_results_;
const Mode *mode_{nullptr};
const Sdc *sdc_{nullptr};
const Sim *sim_{nullptr};
Expand Down
6 changes: 6 additions & 0 deletions search/Search.i
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,12 @@ check_timing_cmd(bool no_input_delay,
loops, generated_clks);
}

void
report_check_timing_json(const char *filename)
{
Sta::sta()->reportCheckTimingJson(filename);
}

////////////////////////////////////////////////////////////////

PinSet
Expand Down
13 changes: 11 additions & 2 deletions search/Search.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ define_cmd_args "check_setup" \
{ [-verbose] [-no_input_delay] [-no_output_delay]\
[-multiple_clock] [-no_clock]\
[-unconstrained_endpoints] [-loops] [-generated_clocks]\
[> filename] [>> filename] }
[-json filename] [> filename] [>> filename] }

proc_redirect check_setup {
check_setup_cmd "check_setup" $args
}

proc check_setup_cmd { cmd cmd_args } {
parse_key_args $cmd cmd_args keys {} flags {-verbose} 0
parse_key_args $cmd cmd_args keys {-json} flags {-verbose} 0
# When nothing is everything.
if { $cmd_args == {} } {
set unconstrained_endpoints 1
Expand Down Expand Up @@ -77,6 +77,15 @@ proc check_setup_cmd { cmd cmd_args } {
}
}
}
if { [info exists keys(-json)] } {
if { $keys(-json) == "" } {
sta_error 517 "$cmd -json requires an output file location."
}
if { $loops } {
sta_warn 518 "$cmd -json does not support -loops. Loops are not emitted."
}
report_check_timing_json $keys(-json)
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
# return value
expr [llength $errors] == 0
}
Expand Down
6 changes: 6 additions & 0 deletions search/Sta.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,12 @@ Sta::checkTiming(const Mode *mode,
unconstrained_endpoints, loops, generated_clks);
}

void
Sta::reportCheckTimingJson(const char *filename)
{
check_timing_->reportJson(filename);
}

////////////////////////////////////////////////////////////////

bool
Expand Down
22 changes: 22 additions & 0 deletions test/check_setup_json.ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Warning: There are 4 input ports missing set_input_delay.
Warning: There are 2 unclocked register/latch pins.
Warning: There are 4 unconstrained endpoints.
Warning 518: check_setup_json.tcl line 16, check_setup -json does not support -loops. Loops are not emitted.
{
"no_input_delay": [
"clk2",
"clk3",
"in1",
"in2"
],
"unclocked": [
"r2/CLK",
"r3/CLK"
],
"unconstrained": [
"out",
"r1/D",
"r2/D",
"r3/D"
]
}
18 changes: 18 additions & 0 deletions test/check_setup_json.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# check_setup -json
source helpers.tcl
read_liberty asap7_small.lib.gz
read_verilog reg1_asap7.v
link_design top

# Only constrain clk1; leave clk2/clk3, inputs, and outputs unconstrained
create_clock -name clk1 -period 500 clk1

set json_file [make_result_file "check_setup_json.json"]

# Dump JSON, should warn that loops aren't supported.
check_setup -unconstrained_endpoints -multiple_clock -no_clock \
-no_input_delay -generated_clocks \
-loop \
-json $json_file

report_file $json_file
1 change: 1 addition & 0 deletions test/regression_vars.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ record_example_tests {

record_public_tests {
collections
check_setup_json
delay_calc_no_inv
disable_clock_gating_check
disconnect_mcp_pin
Expand Down
Loading