Add {`instance`, `cell`, `verilog_src`, `pin`, `net`, `hier_pins`, `capacitance`} fields to `report_checks -format json` for paths (#135)

* Add {`inst`, `cell`, `src`, `nets`} to `report_checks -format json`

* Smallfix

* Improved nets

* Race condition fix

* Fixes

* Small whitespace fix

* Add no paths corner case stuff

* Adjustments to naming of fields

* Requested fixes

* Reintroduce escapeBackslashes, use stringCopy to prevent stack memory warning

* Fix escapeBackslashes to use preferred style

* No backslash escaping

* Make requested fixes
This commit is contained in:
Akash Levy 2025-01-13 19:28:04 -08:00 committed by GitHub
parent 560eba7dae
commit 44e7316da1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 207 additions and 52 deletions

View File

@ -911,6 +911,7 @@ public:
PathEnd *prev_end,
bool last);
void reportPathEnd(PathEnd *end);
void reportPathEnds(PathEndSeq *ends);
ReportPath *reportPath() { return report_path_; }
void reportPath(Path *path);

View File

@ -55,6 +55,15 @@
namespace sta {
static void
hierPinsAbove(const Net *net,
const Network *network,
PinSeq &pins_above);
static void
hierPinsAbove(const Pin *pin,
const Network *network,
PinSeq &pins_above);
static PinSeq
hierPinsThruEdge(const Edge *edge,
const Network *network,
@ -326,14 +335,14 @@ void
ReportPath::reportPathEnds(PathEndSeq *ends)
{
reportPathEndHeader();
PathEndSeq::Iterator end_iter(ends);
PathEnd *prev_end = nullptr;
while (end_iter.hasNext()) {
PathEnd *end = end_iter.next();
reportEndpointHeader(end, prev_end);
end->reportFull(this);
reportBlankLine();
prev_end = end;
if (ends) {
PathEndSeq::Iterator end_iter(ends);
PathEnd *prev_end = nullptr;
while (end_iter.hasNext()) {
PathEnd *end = end_iter.next();
reportPathEnd(end, prev_end, !end_iter.hasNext());
prev_end = end;
}
}
reportPathEndFooter();
}
@ -1086,9 +1095,9 @@ ReportPath::reportJson(const PathEnd *end,
const Pin *startpoint = expanded.startPath()->vertex(this)->pin();
const Pin *endpoint = expanded.endPath()->vertex(this)->pin();
stringAppend(result, " \"startpoint\": \"%s\",\n",
network_->pathName(startpoint));
sdc_network_->pathName(startpoint));
stringAppend(result, " \"endpoint\": \"%s\",\n",
network_->pathName(endpoint));
sdc_network_->pathName(endpoint));
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
const PathVertex *tgt_clk_path = end->targetClkPath();
@ -1171,10 +1180,51 @@ ReportPath::reportJson(const PathExpanded &expanded,
for (size_t i = 0; i < expanded.size(); i++) {
const PathRef *path = expanded.path(i);
const Pin *pin = path->vertex(this)->pin();
const Net *net = network_->net(pin);
const Instance *inst = network_->instance(pin);
const RiseFall *rf = path->transition(this);
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
bool is_driver = network_->isDriver(pin);
stringAppend(result, "%*s {\n", indent, "");
if (inst) {
stringAppend(result, "%*s \"instance\": \"%s\",\n",
indent, "",
sdc_network_->pathName(inst));
Cell *cell = network_->cell(inst);
if (cell)
stringAppend(result, "%*s \"cell\": \"%s\",\n",
indent, "",
sdc_network_->name(cell));
stringAppend(result, "%*s \"verilog_src\": \"%s\",\n",
indent, "",
sdc_network_->getAttribute(inst, "src").c_str());
}
stringAppend(result, "%*s \"pin\": \"%s\",\n",
indent, "",
network_->pathName(pin));
sdc_network_->pathName(pin));
if (net) {
stringAppend(result, "%*s \"net\": \"%s\",\n",
indent, "",
sdc_network_->pathName(net));
}
PinSeq pins_above;
hierPinsAbove(pin, network_, pins_above);
if (!pins_above.empty()) {
stringAppend(result, "%*s \"hier_pins\": [\n", indent, "");
for (const Pin *hpin : pins_above) {
stringAppend(result, "%*s \"%s\"%s\n",
indent, "",
sdc_network_->pathName(hpin),
(hpin != pins_above.back()) ? "," : "");
}
stringAppend(result, "%*s ],\n", indent, "");
}
double x, y;
bool exists;
network_->location(pin, x, y, exists);
@ -1186,6 +1236,10 @@ ReportPath::reportJson(const PathExpanded &expanded,
stringAppend(result, "%*s \"arrival\": %.3e,\n",
indent, "",
delayAsFloat(path->arrival(this)));
if (is_driver)
stringAppend(result, "%*s \"capacitance\": %.3e,\n",
indent, "",
graph_delay_calc_->loadCap(pin, rf, dcalc_ap));
stringAppend(result, "%*s \"slew\": %.3e\n",
indent, "",
delayAsFloat(path->slew(this)));
@ -3481,15 +3535,6 @@ ReportPath::latchDesc(const RiseFall *clk_rf) const
////////////////////////////////////////////////////////////////
static void
hierPinsAbove(const Net *net,
const Network *network,
PinSeq &pins_above);
static void
hierPinsAbove(const Pin *pin,
const Network *network,
PinSeq &pins_above);
static PinSeq
hierPinsThruEdge(const Edge *edge,
const Network *network,

View File

@ -38,6 +38,7 @@ class ReportPath : public StaState
public:
explicit ReportPath(StaState *sta);
virtual ~ReportPath();
ReportPathFormat pathFormat() const { return format_; }
void setPathFormat(ReportPathFormat format);
void setReportFieldOrder(StringSeq *field_names);
void setReportFields(bool report_input_pin,

View File

@ -509,6 +509,18 @@ report_path_cmd(PathRef *path)
Sta::sta()->reportPath(path);
}
void
report_path_ends(PathEndSeq *ends)
{
Sta *sta = Sta::sta();
Report *report = sta->report();
ReportPathFormat path_format = sta->reportPath()->pathFormat();
if (path_format == ReportPathFormat::json || (ends && ends->size() > 0))
sta->reportPathEnds(ends);
else
report->reportLine("No paths found.");
}
////////////////////////////////////////////////////////////////
void

View File

@ -420,14 +420,9 @@ define_cmd_args "report_checks" \
proc_redirect report_checks {
global sta_report_unconstrained_paths
parse_report_path_options "report_checks" args "full" 0
set path_ends [find_timing_paths_cmd "report_checks" args]
if { $path_ends == {} } {
report_line "No paths found."
} else {
report_path_ends $path_ends
}
report_path_ends $path_ends
}
################################################################
@ -1091,19 +1086,6 @@ proc parse_path_group_arg { group_names } {
return $names
}
proc report_path_ends { path_ends } {
report_path_end_header
set prev_end "NULL"
set end_count [llength $path_ends]
set i 0
foreach path_end $path_ends {
report_path_end2 $path_end $prev_end [expr $i == ($end_count - 1)]
set prev_end $path_end
incr i
}
report_path_end_footer
}
################################################################
define_cmd_args "report_clock_min_period" \

View File

@ -2555,6 +2555,12 @@ Sta::reportPathEnd(PathEnd *end,
report_path_->reportPathEnd(end, prev_end, last);
}
void
Sta::reportPathEnds(PathEndSeq *ends)
{
report_path_->reportPathEnds(ends);
}
void
Sta::reportPath(Path *path)
{

View File

@ -1286,6 +1286,10 @@ using namespace sta;
Tcl_SetObjResult(interp, obj);
}
%typemap(in) PathEndSeq* {
$1 = tclListSeqPtr<PathEnd*>($input, SWIGTYPE_p_PathEnd, interp);
}
%typemap(out) PathEndSeq* {
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
const PathEndSeq *path_ends = $1;

View File

@ -132,6 +132,8 @@ record_sta_tests {
get_objrefs
get_lib_pins_of_objects
report_checks_src_attr
report_json1
report_json2
liberty_latch3
}

View File

@ -1,5 +1,5 @@
Startpoint: in (input port clocked by clk)
Endpoint: _1415_ (rising edge-triggered flip-flop clocked by clk)
Startpoint: _1415_ (rising edge-triggered flip-flop clocked by clk)
Endpoint: _1416_[0] (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: max
@ -7,22 +7,22 @@ Path Type: max
---------------------------------------------------------------------------------------------------------------
0.00 0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 0.00 0.00 v in (in)
in (net)
0.00 0.00 0.00 v _1415_/D (sky130_fd_sc_hd__dfrtp_1) synthesis/tests/counter.v:22.3-28.6
0.00 data arrival time
0.00 0.00 0.00 ^ _1415_/CLK (sky130_fd_sc_hd__dfrtp_1) synthesis/tests/counter.v:22.3-28.6
0.00 0.04 0.33 0.33 v _1415_/Q (sky130_fd_sc_hd__dfrtp_1) synthesis/tests/counter.v:22.3-28.6
mid (net) synthesis/tests/counter.v:22.3-28.6
0.04 0.00 0.33 v _1416_[0]/D (sky130_fd_sc_hd__dfrtp_1) synthesis/tests/counter.v:22.3-28.6
0.33 data arrival time
0.00 10.00 10.00 clock clk (rise edge)
0.00 10.00 clock network delay (ideal)
0.00 10.00 clock reconvergence pessimism
10.00 ^ _1415_/CLK (sky130_fd_sc_hd__dfrtp_1)
-0.10 9.90 library setup time
9.90 data required time
10.00 ^ _1416_[0]/CLK (sky130_fd_sc_hd__dfrtp_1)
-0.12 9.88 library setup time
9.88 data required time
---------------------------------------------------------------------------------------------------------------
9.90 data required time
-0.00 data arrival time
9.88 data required time
-0.33 data arrival time
---------------------------------------------------------------------------------------------------------------
9.90 slack (MET)
9.55 slack (MET)

78
test/report_json1.ok Normal file
View File

@ -0,0 +1,78 @@
{"checks": [
{
"type": "check",
"path_group": "clk",
"path_type": "max",
"startpoint": "_1415_/Q",
"endpoint": "_1416_[0]/D",
"source_clock": "clk",
"source_clock_edge": "rise",
"source_path": [
{
"instance": "",
"cell": "counter",
"verilog_src": "",
"pin": "clk",
"arrival": 0.000e+00,
"capacitance": 3.742e-15,
"slew": 0.000e+00
},
{
"instance": "_1415_",
"cell": "sky130_fd_sc_hd__dfrtp_1",
"verilog_src": "synthesis/tests/counter.v:22.3-28.6",
"pin": "_1415_/CLK",
"net": "clk",
"arrival": 0.000e+00,
"slew": 0.000e+00
},
{
"instance": "_1415_",
"cell": "sky130_fd_sc_hd__dfrtp_1",
"verilog_src": "synthesis/tests/counter.v:22.3-28.6",
"pin": "_1415_/Q",
"net": "mid",
"arrival": 3.296e-10,
"capacitance": 1.949e-15,
"slew": 3.612e-11
},
{
"instance": "_1416_[0]",
"cell": "sky130_fd_sc_hd__dfrtp_1",
"verilog_src": "synthesis/tests/counter.v:22.3-28.6",
"pin": "_1416_[0]/D",
"net": "mid",
"arrival": 3.296e-10,
"slew": 3.612e-11
}
],
"target_clock": "clk",
"target_clock_edge": "rise",
"target_clock_path": [
{
"instance": "",
"cell": "counter",
"verilog_src": "",
"pin": "clk",
"arrival": 0.000e+00,
"capacitance": 3.742e-15,
"slew": 0.000e+00
},
{
"instance": "_1416_[0]",
"cell": "sky130_fd_sc_hd__dfrtp_1",
"verilog_src": "synthesis/tests/counter.v:22.3-28.6",
"pin": "_1416_[0]/CLK",
"net": "clk",
"arrival": 0.000e+00,
"slew": 0.000e+00
}
],
"data_arrival_time": 3.296e-10,
"crpr": 0.000e+00,
"margin": 1.207e-10,
"required_time": 9.879e-09,
"slack": 9.550e-09
}
]
}

7
test/report_json1.tcl Normal file
View File

@ -0,0 +1,7 @@
# report_checks -format json
read_liberty ../examples/sky130hd_tt.lib.gz
read_verilog verilog_attribute.v
link_design counter
create_clock -name clk -period 10 clk
set_input_delay -clock clk 0 [all_inputs -no_clocks]
report_checks -path_group clk -format json >> results/report_json1.log

3
test/report_json2.ok Normal file
View File

@ -0,0 +1,3 @@
{"checks": [
]
}

6
test/report_json2.tcl Normal file
View File

@ -0,0 +1,6 @@
# report_checks -format json with no paths
read_liberty ../examples/sky130hd_tt.lib.gz
read_verilog verilog_attribute.v
link_design counter
create_clock -name clk -period 10
report_checks -path_group clk -format json >> results/report_json2.log

View File

@ -11,11 +11,19 @@ module counter(clk, reset, in, out);
(* src = "synthesis/tests/counter.v:18.14-18.19" *)
input reset;
input in;
wire mid;
(* bottom_bound = 1'sh0 *)
(* src = "synthesis/tests/counter.v:22.3-28.6", attr1 = "test_attr1", attr2 = "test_attr2" *)
sky130_fd_sc_hd__dfrtp_1 _1415_ (
.CLK(clk),
.D(in),
.Q(mid),
.RESET_B(reset)
);
(* src = "synthesis/tests/counter.v:22.3-28.6" *)
sky130_fd_sc_hd__dfrtp_1 \_1416_[0] (
.CLK(clk),
.D(mid),
.Q(out),
.RESET_B(reset)
);