Tcl · Module 21
Generating the Report Set
The netlist is what the run produced; the reports are how anyone knows whether to use it. A run that compiled successfully and wrote no reports has produced nothing anybody can sign off.
Advanced16 min readtcledapart-iisynthesisreportsfilesvalidation
Part II · Module 21 · Chapter 21.8 · Generating the Report Set
Compile produces a netlist. The reports are how anybody decides whether that netlist is usable — and a run without them has produced an artefact nobody can evaluate.
Writing them is almost entirely Part I: making a directory, opening files, checking they landed.
1. What a run must leave behind
Four reports, minimum, and each answers a question somebody will ask:
| Report | Answers |
|---|---|
| timing | did it meet the constraints, and where is the worst path? |
| area | how big is it? |
| power | what does it cost to run? |
| quality | the summary numbers — worst slack, total negative slack, violation counts |
The quality report is the one read first, because it is the one that decides whether the others need reading at all.
To these add the session log — Chapter 21.5 §3's elaboration warnings live there, and without it an unresolved reference has no record.
2. Create the directory first
proc ensure_dir {path} {
if {[file exists $path] && ![file isdirectory $path]} {
error "'$path' exists and is not a directory" {} {RUN NOTDIR}
}
file mkdir $path
if {![file writable $path]} { error "'$path' is not writable" {} {RUN NOWRITE} }
return $path
}
ensure_dir [file join $RUN reports]
ensure_dir [file join $RUN netlist]=== 1. create the output directory BEFORE anything writes to it ===
created: /private/tmp/m21/run/reports
created: /private/tmp/m21/run/netlistThree deliberate details, all from Chapter 14.11:
- The not-a-directory check first.
file mkdiron a path occupied by a file fails with a message about the path; checking first gives a message about the situation. file mkdircreates intermediate directories and is not an error if the directory already exists — so it is safe to call every run.- The writable check. A directory that exists and cannot be written to is the case that produces zero-byte reports later.
3. Write them, and check each landed
proc write_report {path body} {
set fp [open $path w]
puts $fp $body
close $fp
if {![file isfile $path] || [file size $path] == 0} {
error "report '$path' was not written" {} [list REPORT EMPTY $path]
}
return [file size $path]
}=== 2. write the report set, checking each one landed ===
timing.rpt 47 bytes
area.rpt 35 bytes
power.rpt 17 bytes
qor.rpt 20 bytes
-> 4 report(s)In a real flow the body comes from the tool's report command rather than a literal, but the wrapper is the same: produce it, write it, check it is non-zero.
4. Check the set is complete
proc check_reports {dir expected} {
set missing {} ; set empty {}
foreach r $expected {
set p [file join $dir $r]
if {![file isfile $p]} { lappend missing $r ; continue }
if {[file size $p] == 0} { lappend empty $r }
}
return [list $missing $empty]
}=== 3. the check: every expected report present and non-empty ===
missing: <none>
empty : <none>
with clock.rpt expected too -> missing: clock.rptThe expected list is declared, which is the point. Checking "are there some files in the reports directory" passes on a run that wrote one report; checking against a stated list catches the three that are absent.
This is Chapter 19.5 §6's expectation idea again: a count or a set you predicted and then verified says far more than one you merely observed.
5. Extracting the numbers
The reports are for humans, but the summary numbers should also be machine-readable, because that is how runs get compared:
proc qor_number {path key} {
set fp [open $path r]
set text [read $fp]
close $fp
if {![regexp "${key}\\s+(\\S+)" $text -> value]} {
error "no '$key' line in [file tail $path]" {} [list QOR MISSING $key]
}
return $value
}One regexp per number — Module 13 — with an error rather than an empty string when the line is absent, so a changed report format is noticed rather than silently producing blanks.
Then the run can state its own result:
set wns [qor_number [file join $RUN reports qor.rpt] wns]
puts " worst negative slack: $wns"6. Where the reports go
One directory per run, named so two runs cannot collide:
set RUN [file join $PROJECT runs ${TOP}_${CORNER}_[clock format [clock seconds] -format %Y%m%d_%H%M%S]]Three properties worth having:
- Unique, so a new run never overwrites the evidence for the last one.
- Sortable, because a timestamp in
%Y%m%d_%H%M%Ssorts chronologically as a string. - Self-describing, so the directory name alone says which block and which corner.
And since Chapter 21.9 puts the netlist in the same run directory, the netlist and the evidence for it stay together — which is the whole point of the next chapter.
7. Exercises
Exercise 1. Name the four reports a run must leave, and which is read first.
Exercise 2. Why create the output directories at the start of the run rather than before the report phase?
Exercise 3. Name the three checks in ensure_dir and what each catches.
Exercise 4. Why is a zero-byte report worse than a missing one?
Exercise 5. Why check against a declared list of expected reports rather than counting files?
Exercise 6. Why should qor_number raise rather than return an empty string?
Exercise 7. Give three properties a run directory name should have.
Where this fits
Part of the Tcl curriculum.
