FEATURE: Add `read_vcd -begin_time`/`-end_time` activity windowing (#466)
* Add read_vcd -begin_time/-end_time activity windowing. Limit VCD transition and duty counting to an optional time window so activity annotation can ignore regions outside the interval of interest. Co-authored-by: Cursor <cursoragent@cursor.com> * Format VcdCount::setFilter parameters one per line. Co-authored-by: Cursor <cursoragent@cursor.com> * Address VCD begin/end review: VcdTime, sentinel, rename. Use VcdTime and vcd_null_time instead of int64_t/-1, rename VcdCount filter bounds to begin/end_time, rename the regression to vcd_begin_end_time, and document read_vcd -begin_time/-end_time in ChangeLog.txt. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: James Cherry <34749589+jjcherry56@users.noreply.github.com>
This commit is contained in:
parent
f29b6a43c6
commit
7fdc304e12
|
|
@ -4,6 +4,15 @@ OpenSTA Timing Analyzer Release Notes
|
||||||
This file summarizes user visible changes for each release.
|
This file summarizes user visible changes for each release.
|
||||||
See ApiChangeLog.txt for changes to the STA api.
|
See ApiChangeLog.txt for changes to the STA api.
|
||||||
|
|
||||||
|
2026/07/20
|
||||||
|
----------
|
||||||
|
|
||||||
|
The read_vcd command supports -begin_time / -end_time to limit
|
||||||
|
activity annotation to a VCD time window.
|
||||||
|
|
||||||
|
read_vcd [-scope scope] [-mode mode_name]
|
||||||
|
[-begin_time begin_time] [-end_time end_time] filename
|
||||||
|
|
||||||
2026/05/01
|
2026/05/01
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
//
|
//
|
||||||
// This notice may not be removed or altered from any source distribution.
|
// This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
%include "stdint.i"
|
||||||
|
|
||||||
%{
|
%{
|
||||||
#include "power/Power.hh"
|
#include "power/Power.hh"
|
||||||
|
|
||||||
|
|
@ -29,12 +31,16 @@
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
#include "Sta.hh"
|
#include "Sta.hh"
|
||||||
#include "power/SaifReader.hh"
|
#include "power/SaifReader.hh"
|
||||||
|
#include "power/VcdParse.hh"
|
||||||
#include "power/VcdReader.hh"
|
#include "power/VcdReader.hh"
|
||||||
|
|
||||||
using namespace sta;
|
using namespace sta;
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// Match power/VcdParse.hh vcd_null_time for Tcl defaults.
|
||||||
|
%constant int64_t vcd_null_time = -1;
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -201,11 +207,13 @@ clock_min_period(const char *mode_name)
|
||||||
void
|
void
|
||||||
read_vcd_file(const char *filename,
|
read_vcd_file(const char *filename,
|
||||||
const char *scope,
|
const char *scope,
|
||||||
const char *mode_name)
|
const char *mode_name,
|
||||||
|
int64_t begin_time,
|
||||||
|
int64_t end_time)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
sta->ensureLibLinked();
|
sta->ensureLibLinked();
|
||||||
readVcdActivities(filename, scope, mode_name, sta);
|
readVcdActivities(filename, scope, mode_name, begin_time, end_time, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -228,4 +236,12 @@ report_activity_annotation_cmd(bool report_unannotated,
|
||||||
report_annotated);
|
report_annotated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_power()
|
||||||
|
{
|
||||||
|
Power *power = Sta::sta()->power();
|
||||||
|
power->clear();
|
||||||
|
}
|
||||||
|
|
||||||
%} // inline
|
%} // inline
|
||||||
|
|
|
||||||
|
|
@ -238,16 +238,18 @@ proc read_power_activities { args } {
|
||||||
set scope $keys(-scope)
|
set scope $keys(-scope)
|
||||||
}
|
}
|
||||||
sta_warn 305 "read_power_activities is deprecated. Use read_vcd."
|
sta_warn 305 "read_power_activities is deprecated. Use read_vcd."
|
||||||
read_vcd_file $filename $scope
|
read_vcd_file $filename $scope [cmd_mode_name] \
|
||||||
|
$sta::vcd_null_time $sta::vcd_null_time
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
define_cmd_args "read_vcd" { [-scope scope] [-mode mode_name] filename }
|
define_cmd_args "read_vcd" \
|
||||||
|
{[-scope scope] [-mode mode_name] [-begin_time begin_time] [-end_time end_time] filename}
|
||||||
|
|
||||||
proc read_vcd { args } {
|
proc read_vcd { args } {
|
||||||
parse_key_args "read_vcd" args \
|
parse_key_args "read_vcd" args \
|
||||||
keys {-scope -mode_name} flags {}
|
keys {-scope -mode -begin_time -end_time} flags {}
|
||||||
|
|
||||||
check_argc_eq1 "read_vcd" $args
|
check_argc_eq1 "read_vcd" $args
|
||||||
set filename [file nativename [lindex $args 0]]
|
set filename [file nativename [lindex $args 0]]
|
||||||
|
|
@ -259,7 +261,15 @@ proc read_vcd { args } {
|
||||||
if { [info exists keys(-mode)] } {
|
if { [info exists keys(-mode)] } {
|
||||||
set mode_name $keys(-mode)
|
set mode_name $keys(-mode)
|
||||||
}
|
}
|
||||||
read_vcd_file $filename $scope $mode_name
|
set begin_time $sta::vcd_null_time
|
||||||
|
if { [info exists keys(-begin_time)] } {
|
||||||
|
set begin_time $keys(-begin_time)
|
||||||
|
}
|
||||||
|
set end_time $sta::vcd_null_time
|
||||||
|
if { [info exists keys(-end_time)] } {
|
||||||
|
set end_time $keys(-end_time)
|
||||||
|
}
|
||||||
|
read_vcd_file $filename $scope $mode_name $begin_time $end_time
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,13 @@ namespace sta {
|
||||||
|
|
||||||
void
|
void
|
||||||
VcdParse::read(const char *filename,
|
VcdParse::read(const char *filename,
|
||||||
VcdReader *reader)
|
VcdReader *reader,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time)
|
||||||
{
|
{
|
||||||
|
begin_time_ = begin_time;
|
||||||
|
end_time_ = end_time;
|
||||||
|
|
||||||
stream_ = gzopen(filename, "r");
|
stream_ = gzopen(filename, "r");
|
||||||
if (stream_) {
|
if (stream_) {
|
||||||
Stats stats(debug_, report_);
|
Stats stats(debug_, report_);
|
||||||
|
|
@ -51,6 +56,11 @@ VcdParse::read(const char *filename,
|
||||||
reader_ = reader;
|
reader_ = reader;
|
||||||
file_line_ = 0;
|
file_line_ = 0;
|
||||||
stmt_line_ = 0;
|
stmt_line_ = 0;
|
||||||
|
|
||||||
|
// If user specified a start time, set it now.
|
||||||
|
if (begin_time != vcd_null_time) {
|
||||||
|
reader_->setTimeMin(begin_time);
|
||||||
|
}
|
||||||
std::string token = getToken();
|
std::string token = getToken();
|
||||||
while (!token.empty()) {
|
while (!token.empty()) {
|
||||||
if (token == "$date")
|
if (token == "$date")
|
||||||
|
|
@ -87,7 +97,10 @@ VcdParse::read(const char *filename,
|
||||||
report_->fileError(806, filename_, file_line_, "time out of range {}",
|
report_->fileError(806, filename_, file_line_, "time out of range {}",
|
||||||
token.substr(1));
|
token.substr(1));
|
||||||
}
|
}
|
||||||
|
// Set time min to start time if it is not set at beginning
|
||||||
|
if (begin_time == vcd_null_time) {
|
||||||
reader_->setTimeMin(time_);
|
reader_->setTimeMin(time_);
|
||||||
|
}
|
||||||
prev_time_ = time_;
|
prev_time_ = time_;
|
||||||
}
|
}
|
||||||
else if (token[0] == '$')
|
else if (token[0] == '$')
|
||||||
|
|
@ -238,8 +251,14 @@ VcdParse::parseVarValues()
|
||||||
}
|
}
|
||||||
token = getToken();
|
token = getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set time_max to end_time if specified, otherwise use actual parsed time
|
||||||
|
if (end_time_ != vcd_null_time) {
|
||||||
|
reader_->setTimeMax(end_time_);
|
||||||
|
} else {
|
||||||
reader_->setTimeMax(time_);
|
reader_->setTimeMax(time_);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
VcdParse::readStmtString()
|
VcdParse::readStmtString()
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ namespace sta {
|
||||||
using VcdTime = int64_t;
|
using VcdTime = int64_t;
|
||||||
using VcdScope = std::vector<std::string>;
|
using VcdScope = std::vector<std::string>;
|
||||||
|
|
||||||
|
// Sentinel for an unset begin/end time window bound.
|
||||||
|
constexpr VcdTime vcd_null_time = -1;
|
||||||
|
|
||||||
enum class VcdVarType {
|
enum class VcdVarType {
|
||||||
wire,
|
wire,
|
||||||
reg,
|
reg,
|
||||||
|
|
@ -64,7 +67,9 @@ public:
|
||||||
VcdParse(Report *report,
|
VcdParse(Report *report,
|
||||||
Debug *debug);
|
Debug *debug);
|
||||||
void read(const char *filename,
|
void read(const char *filename,
|
||||||
VcdReader *reader);
|
VcdReader *reader,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseTimescale();
|
void parseTimescale();
|
||||||
|
|
@ -87,6 +92,11 @@ private:
|
||||||
|
|
||||||
VcdTime time_ = 0;
|
VcdTime time_ = 0;
|
||||||
VcdTime prev_time_ = 0;
|
VcdTime prev_time_ = 0;
|
||||||
|
|
||||||
|
// Arguments to VcdParse
|
||||||
|
VcdTime begin_time_ = vcd_null_time;
|
||||||
|
VcdTime end_time_ = vcd_null_time;
|
||||||
|
|
||||||
VcdScope scope_;
|
VcdScope scope_;
|
||||||
|
|
||||||
Report *report_;
|
Report *report_;
|
||||||
|
|
|
||||||
|
|
@ -52,48 +52,89 @@ public:
|
||||||
VcdTime highTime(VcdTime time_max) const;
|
VcdTime highTime(VcdTime time_max) const;
|
||||||
void incrCounts(VcdTime time,
|
void incrCounts(VcdTime time,
|
||||||
char value);
|
char value);
|
||||||
void incrCounts(VcdTime time,
|
|
||||||
int64_t value);
|
|
||||||
void addPin(const Pin *pin);
|
void addPin(const Pin *pin);
|
||||||
const PinSeq &pins() const { return pins_; }
|
const PinSeq &pins() const { return pins_; }
|
||||||
|
|
||||||
|
static void setFilter(VcdTime begin,
|
||||||
|
VcdTime end);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
VcdTime clippedIntervalStart() const;
|
||||||
PinSeq pins_;
|
PinSeq pins_;
|
||||||
VcdTime prev_time_ = -1;
|
VcdTime prev_time_ = vcd_null_time;
|
||||||
char prev_value_ = '\0';
|
char prev_value_ = '\0';
|
||||||
VcdTime high_time_ = 0;
|
VcdTime high_time_ = 0;
|
||||||
double transition_count_ = 0;
|
double transition_count_ = 0;
|
||||||
|
|
||||||
|
static VcdTime begin_time_;
|
||||||
|
static VcdTime end_time_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Define static members
|
||||||
|
VcdTime VcdCount::begin_time_ = vcd_null_time;
|
||||||
|
VcdTime VcdCount::end_time_ = vcd_null_time;
|
||||||
|
|
||||||
void
|
void
|
||||||
VcdCount::addPin(const Pin *pin)
|
VcdCount::addPin(const Pin *pin)
|
||||||
{
|
{
|
||||||
pins_.push_back(pin);
|
pins_.push_back(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VcdTime
|
||||||
|
VcdCount::clippedIntervalStart() const
|
||||||
|
{
|
||||||
|
// Clip prev_time_ to begin_time if signal went high before the window.
|
||||||
|
return (begin_time_ != vcd_null_time && prev_time_ < begin_time_)
|
||||||
|
? begin_time_ : prev_time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VcdCount::setFilter(VcdTime begin,
|
||||||
|
VcdTime end)
|
||||||
|
{
|
||||||
|
begin_time_ = begin;
|
||||||
|
end_time_ = end;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VcdCount::incrCounts(VcdTime time,
|
VcdCount::incrCounts(VcdTime time,
|
||||||
char value)
|
char value)
|
||||||
{
|
{
|
||||||
// Initial value does not coontribute to transitions or high time.
|
// Determine if this time point is within the filter window
|
||||||
if (prev_time_ != -1) {
|
bool in_window = (begin_time_ == vcd_null_time || time >= begin_time_)
|
||||||
if (prev_value_ == '1')
|
&& (end_time_ == vcd_null_time || time <= end_time_);
|
||||||
high_time_ += time - prev_time_;
|
|
||||||
|
// Initial value does not contribute to transitions or high time.
|
||||||
|
if (prev_time_ != vcd_null_time && in_window) {
|
||||||
|
if (prev_value_ == '1') {
|
||||||
|
VcdTime interval_start = clippedIntervalStart();
|
||||||
|
if (time > interval_start)
|
||||||
|
high_time_ += time - interval_start;
|
||||||
|
}
|
||||||
if (value != prev_value_)
|
if (value != prev_value_)
|
||||||
transition_count_ +=
|
transition_count_ +=
|
||||||
(value == 'X' || value == 'Z' || prev_value_ == 'X' || prev_value_ == 'Z')
|
(value == 'X' || value == 'Z' || prev_value_ == 'X' || prev_value_ == 'Z')
|
||||||
? .5
|
? .5
|
||||||
: 1.0;
|
: 1.0;
|
||||||
}
|
}
|
||||||
|
// Update state for transitions before or within the window.
|
||||||
|
// This prevents values after window boundaries corrupting high time.
|
||||||
|
if (end_time_ == vcd_null_time || time <= end_time_) {
|
||||||
prev_time_ = time;
|
prev_time_ = time;
|
||||||
prev_value_ = value;
|
prev_value_ = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VcdTime
|
VcdTime
|
||||||
VcdCount::highTime(VcdTime time_max) const
|
VcdCount::highTime(VcdTime time_max) const
|
||||||
{
|
{
|
||||||
if (prev_value_ == '1')
|
if (prev_value_ == '1') {
|
||||||
return high_time_ + time_max - prev_time_;
|
VcdTime interval_start = clippedIntervalStart();
|
||||||
|
if (time_max > interval_start)
|
||||||
|
return high_time_ + time_max - interval_start;
|
||||||
|
else
|
||||||
|
return high_time_;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return high_time_;
|
return high_time_;
|
||||||
}
|
}
|
||||||
|
|
@ -180,12 +221,14 @@ VcdCountReader::setTimeUnit(std::string_view ,
|
||||||
void
|
void
|
||||||
VcdCountReader::setTimeMin(VcdTime time)
|
VcdCountReader::setTimeMin(VcdTime time)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "read_vcd", 1, "setTimeMin called with time {}", time);
|
||||||
time_min_ = time;
|
time_min_ = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VcdCountReader::setTimeMax(VcdTime time)
|
VcdCountReader::setTimeMax(VcdTime time)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "read_vcd", 1, "setTimeMax called with time {}", time);
|
||||||
time_max_ = time;
|
time_max_ = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -335,6 +378,8 @@ class ReadVcdActivities : public StaState
|
||||||
public:
|
public:
|
||||||
ReadVcdActivities(std::string_view filename,
|
ReadVcdActivities(std::string_view filename,
|
||||||
std::string_view scope,
|
std::string_view scope,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time,
|
||||||
const Sdc *sdc,
|
const Sdc *sdc,
|
||||||
Sta *sta);
|
Sta *sta);
|
||||||
void readActivities();
|
void readActivities();
|
||||||
|
|
@ -345,6 +390,8 @@ private:
|
||||||
double transition_count);
|
double transition_count);
|
||||||
|
|
||||||
const std::string filename_;
|
const std::string filename_;
|
||||||
|
VcdTime begin_time_;
|
||||||
|
VcdTime end_time_;
|
||||||
|
|
||||||
std::set<const Pin *> annotated_pins_;
|
std::set<const Pin *> annotated_pins_;
|
||||||
VcdCountReader vcd_reader_;
|
VcdCountReader vcd_reader_;
|
||||||
|
|
@ -359,20 +406,26 @@ void
|
||||||
readVcdActivities(std::string_view filename,
|
readVcdActivities(std::string_view filename,
|
||||||
std::string_view scope,
|
std::string_view scope,
|
||||||
std::string_view mode_name,
|
std::string_view mode_name,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time,
|
||||||
Sta *sta)
|
Sta *sta)
|
||||||
{
|
{
|
||||||
const Mode *mode = sta->findMode(mode_name);
|
const Mode *mode = sta->findMode(mode_name);
|
||||||
const Sdc *sdc = mode->sdc();
|
const Sdc *sdc = mode->sdc();
|
||||||
ReadVcdActivities reader(filename, scope, sdc, sta);
|
ReadVcdActivities reader(filename, scope, begin_time, end_time, sdc, sta);
|
||||||
reader.readActivities();
|
reader.readActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadVcdActivities::ReadVcdActivities(std::string_view filename,
|
ReadVcdActivities::ReadVcdActivities(std::string_view filename,
|
||||||
std::string_view scope,
|
std::string_view scope,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time,
|
||||||
const Sdc *sdc,
|
const Sdc *sdc,
|
||||||
Sta *sta) :
|
Sta *sta) :
|
||||||
StaState(sta),
|
StaState(sta),
|
||||||
filename_(filename),
|
filename_(filename),
|
||||||
|
begin_time_(begin_time),
|
||||||
|
end_time_(end_time),
|
||||||
vcd_reader_(scope,
|
vcd_reader_(scope,
|
||||||
sdc_network_,
|
sdc_network_,
|
||||||
report_,
|
report_,
|
||||||
|
|
@ -391,7 +444,9 @@ ReadVcdActivities::readActivities()
|
||||||
if (clks.empty())
|
if (clks.empty())
|
||||||
report_->error(820, "No clocks have been defined.");
|
report_->error(820, "No clocks have been defined.");
|
||||||
|
|
||||||
vcd_parse_.read(filename_.c_str(), &vcd_reader_);
|
// Set the time window filter once globally
|
||||||
|
VcdCount::setFilter(begin_time_, end_time_);
|
||||||
|
vcd_parse_.read(filename_.c_str(), &vcd_reader_, begin_time_, end_time_);
|
||||||
|
|
||||||
if (vcd_reader_.timeMax() > 0)
|
if (vcd_reader_.timeMax() > 0)
|
||||||
setActivities();
|
setActivities();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "VcdParse.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
class Sta;
|
class Sta;
|
||||||
|
|
@ -34,6 +36,8 @@ void
|
||||||
readVcdActivities(std::string_view filename,
|
readVcdActivities(std::string_view filename,
|
||||||
std::string_view scope,
|
std::string_view scope,
|
||||||
std::string_view mode_name,
|
std::string_view mode_name,
|
||||||
|
VcdTime begin_time,
|
||||||
|
VcdTime end_time,
|
||||||
Sta *sta);
|
Sta *sta);
|
||||||
|
|
||||||
} // namespace sta
|
} // namespace sta
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,7 @@ record_public_tests {
|
||||||
report_json2
|
report_json2
|
||||||
suppress_msg
|
suppress_msg
|
||||||
user_properties
|
user_properties
|
||||||
|
vcd_begin_end_time
|
||||||
verilog_attribute
|
verilog_attribute
|
||||||
verilog_well_supplies
|
verilog_well_supplies
|
||||||
verilog_specify
|
verilog_specify
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.0666665 0.667
|
||||||
|
u_inv/A 0.0666665 0.333
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.1 1.000
|
||||||
|
u_inv/A 0.1 0.000
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.2 0.000
|
||||||
|
u_inv/A 0.2 1.000
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.1 1.000
|
||||||
|
u_inv/A 0.1 0.000
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.25 0.500
|
||||||
|
u_inv/A 0.25 0.500
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.125 0.750
|
||||||
|
u_inv/A 0.125 0.250
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.125 0.250
|
||||||
|
u_inv/A 0.125 0.750
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.25 0.500
|
||||||
|
u_inv/A 0.25 0.500
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.125 0.250
|
||||||
|
u_inv/A 0.125 0.750
|
||||||
|
|
||||||
|
Annotated 2 pin activities.
|
||||||
|
Pin Name Activity Duty Cycle
|
||||||
|
--------------------------------------------------------
|
||||||
|
u_inv/Y 0.125 0.750
|
||||||
|
u_inv/A 0.125 0.250
|
||||||
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Report pin activities
|
||||||
|
proc report_activities { } {
|
||||||
|
set pins [get_pins -hierarchical *]
|
||||||
|
set clk_freq [expr 1.0 / (10 * 1e-12)]
|
||||||
|
puts "Pin Name Activity Duty Cycle"
|
||||||
|
puts "--------------------------------------------------------"
|
||||||
|
foreach pin $pins {
|
||||||
|
set prop [get_property $pin activity]
|
||||||
|
set transitions_per_sec [lindex $prop 0]
|
||||||
|
set duty [lindex $prop 1]
|
||||||
|
set activity [expr double($transitions_per_sec) / [expr $clk_freq * 2]]
|
||||||
|
puts "[get_full_name $pin] $activity $duty"
|
||||||
|
}
|
||||||
|
puts ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
read_liberty asap7_invbuf.lib.gz
|
||||||
|
read_verilog vcd_begin_end_time.v
|
||||||
|
link_design top
|
||||||
|
|
||||||
|
# Define clock period in ps
|
||||||
|
create_clock -name vclk -period 10
|
||||||
|
|
||||||
|
# Full VCD reading works (normal behavior)
|
||||||
|
# VCD changes at time 50 and 100 (inverter)
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
# Read VCD from start to first transition point
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -end_time 50
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
# Read VCD from first transition point to second transition point
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 50 -end_time 100
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
# Read VCD from second transition point to end
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 100
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
# Read VCD around the first transition point
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 40 -end_time 60
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 20 -end_time 60
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 40 -end_time 80
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
# Read VCD around the second transition point (should mirror the first)
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 90 -end_time 110
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 70 -end_time 110
|
||||||
|
report_activities
|
||||||
|
|
||||||
|
sta::clear_power
|
||||||
|
read_vcd vcd_begin_end_time.vcd -scope top -begin_time 90 -end_time 130
|
||||||
|
report_activities
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
|
module top (
|
||||||
|
input wire A,
|
||||||
|
input wire clk,
|
||||||
|
output wire Y
|
||||||
|
);
|
||||||
|
|
||||||
|
INVx2_ASAP7_75t_R u_inv (
|
||||||
|
.A(A),
|
||||||
|
.Y(Y)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
$date
|
||||||
|
Mon Mar 16 2026
|
||||||
|
$end
|
||||||
|
$version
|
||||||
|
VCD Test File
|
||||||
|
$end
|
||||||
|
$timescale
|
||||||
|
1ps
|
||||||
|
$end
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 ! A $end
|
||||||
|
$var wire 1 " Y $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
#0
|
||||||
|
$dumpvars
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
$end
|
||||||
|
#50
|
||||||
|
1!
|
||||||
|
0"
|
||||||
|
#100
|
||||||
|
0!
|
||||||
|
1"
|
||||||
|
#150
|
||||||
Loading…
Reference in New Issue