Skip to content
Open
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
4 changes: 2 additions & 2 deletions docs/tutorials/FlowTutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ abc.constr klayout.lyt klayout_tech.lef lib
| `congestion.rpt` | `VDD.rpt` | `VSS.rpt` |
| `5_route_drc.rpt` | `final_clocks.webp` | `final_placement.webp` |
| `antenna.log` | `final_clocks.webp` | `final.webp` |
| `synth_stat.txt` | `synth_check.txt` | `final_resizer.webp` |
| `synth_stat.json` | `synth_check.txt` | `final_resizer.webp` |

The table below briefly describes the reports directory files.

Expand All @@ -325,7 +325,7 @@ The table below briefly describes the reports directory files.
| `antenna.log` | Antenna check log report. |
| `final_placement.webp` | Extracted image after final placement. |
| `final.webp` | Extracted image after routing. |
| `synth_stat.txt` | Post synthesis design statistics log saved here. |
| `synth_stat.json` | Post synthesis design statistics in JSON format. |

The flow completes with the message below by creating a merged final GDS file.

Expand Down
2 changes: 1 addition & 1 deletion flow/scripts/synth.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ if { $::env(SYNTH_INSBUF) } {
# Reports
tee -o $::env(REPORTS_DIR)/synth_check.txt check

tee -o $::env(REPORTS_DIR)/synth_stat.txt stat {*}$lib_args
tee -o $::env(REPORTS_DIR)/synth_stat.json stat -json {*}$lib_args
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should tee to a log file and use the -o option to output a valid JSON:
https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/index_backends.html#json-write-design-in-json-format

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The json backend (write_json -o) outputs the design netlist rather than synthesis statistics, it doesn't include aggregated cell count or area values that we need for metrics. stat -json provides these but doesn't support -o; its docs recommend using tee for file output. Our current approach uses tee -oto capture stat -json and skips any log prefix (e.g. "Found gzip magic") in genMetrics.py before parsing. Would this be acceptable?


# check the design is composed exclusively of target cells, and
# check for other problems
Expand Down
56 changes: 43 additions & 13 deletions flow/util/genMetrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,20 +231,50 @@ def extract_metrics(
# Synthesis
# =========================================================================

# The new format (>= 0.57) is: <count> <area> cells
extractTagFromFile(
"synth__design__instance__count__stdcell",
metrics_dict,
"^\\s+(\\d+)\\s+[-0-9.]+\\s+cells$",
rptPath + "/synth_stat.txt",
)
synth_stat_file = rptPath + "/synth_stat.json"
try:
with open(synth_stat_file) as f:
content = f.read()
# yosys may emit log messages (e.g. "Found gzip magic in file...")
# before the JSON when reading compressed liberty files. Skip them.
Comment on lines +235 to +239
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the above is implemented we likely will not need this post-processing.

synth_stat = json.loads(content[content.index("{") :])
modules = synth_stat.get("modules", {})
# Prefer lookup by design name; yosys may prefix module names with a
# backslash in JSON output, so try both forms. Fall back to the last
# module in the output, which yosys emits last for the top-level module.
top_module = (
modules.get(design)
or modules.get("\\" + design)
or (list(modules.values())[-1] if modules else None)
)

num_cells = top_module.get("num_cells") if top_module else None
if num_cells is None:
print(
"[WARN] Tag synth__design__instance__count__stdcell not found in {}.".format(
synth_stat_file
),
"Will use N/A.",
)
metrics_dict["synth__design__instance__count__stdcell"] = "N/A"
else:
metrics_dict["synth__design__instance__count__stdcell"] = int(num_cells)

extractTagFromFile(
"synth__design__instance__area__stdcell",
metrics_dict,
"Chip area for (?:top )?module.*: +(\\S+)",
rptPath + "/synth_stat.txt",
)
area = top_module.get("area") if top_module else None
if area is None:
print(
"[WARN] Tag synth__design__instance__area__stdcell not found in {}.".format(
synth_stat_file
),
"Will use N/A.",
)
metrics_dict["synth__design__instance__area__stdcell"] = "N/A"
else:
metrics_dict["synth__design__instance__area__stdcell"] = float(area)
except (IOError, json.JSONDecodeError, ValueError):
print("[ERROR] Failed to open file:", synth_stat_file)
metrics_dict["synth__design__instance__count__stdcell"] = "ERR"
metrics_dict["synth__design__instance__area__stdcell"] = "ERR"

# Clocks
# =========================================================================
Expand Down