write_lib
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
7ac4af5bcb
commit
82dfa21484
|
|
@ -133,7 +133,7 @@ public:
|
||||||
TableTemplateType type);
|
TableTemplateType type);
|
||||||
TableTemplate *findTableTemplate(const char *name,
|
TableTemplate *findTableTemplate(const char *name,
|
||||||
TableTemplateType type);
|
TableTemplateType type);
|
||||||
float nominalProcess() { return nominal_process_; }
|
float nominalProcess() const { return nominal_process_; }
|
||||||
void setNominalProcess(float process);
|
void setNominalProcess(float process);
|
||||||
float nominalVoltage() const { return nominal_voltage_; }
|
float nominalVoltage() const { return nominal_voltage_; }
|
||||||
void setNominalVoltage(float voltage);
|
void setNominalVoltage(float voltage);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
class StaState;
|
||||||
|
|
||||||
void
|
void
|
||||||
writeLiberty(LibertyLibrary *lib,
|
writeLiberty(LibertyLibrary *lib,
|
||||||
const char *filename);
|
const char *filename,
|
||||||
|
StaState *sta);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public:
|
||||||
void operator=(const Unit &unit);
|
void operator=(const Unit &unit);
|
||||||
float scale() const { return scale_; }
|
float scale() const { return scale_; }
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
const char *scaleAbreviation();
|
const char *scaleAbreviation() const;
|
||||||
const char *suffix() const { return suffix_; }
|
const char *suffix() const { return suffix_; }
|
||||||
void setSuffix(const char *suffix);
|
void setSuffix(const char *suffix);
|
||||||
int digits() const { return digits_; }
|
int digits() const { return digits_; }
|
||||||
|
|
|
||||||
|
|
@ -18,35 +18,51 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "Liberty.hh"
|
|
||||||
#include "Units.hh"
|
#include "Units.hh"
|
||||||
|
#include "FuncExpr.hh"
|
||||||
|
#include "PortDirection.hh"
|
||||||
|
#include "Liberty.hh"
|
||||||
|
#include "TimingRole.hh"
|
||||||
|
#include "TimingArc.hh"
|
||||||
|
#include "StaState.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
class LibertyWriter
|
class LibertyWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LibertyWriter(LibertyLibrary *lib,
|
LibertyWriter(const LibertyLibrary *lib,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
FILE *stream);
|
FILE *stream,
|
||||||
|
Report *report);
|
||||||
void writeLibrary();
|
void writeLibrary();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeFooter();
|
void writeFooter();
|
||||||
|
void writeCell(const LibertyCell *cell);
|
||||||
|
void writePort(const LibertyPort *port);
|
||||||
|
void writeTimingArcSet(const TimingArcSet *arc_set);
|
||||||
|
const char *asString(bool value);
|
||||||
|
const char *asString(const PortDirection *dir);
|
||||||
|
const char *timingTypeString(const TimingArcSet *arc_set);
|
||||||
|
|
||||||
LibertyLibrary *library_;
|
const LibertyLibrary *library_;
|
||||||
const char *filename_;
|
const char *filename_;
|
||||||
FILE *stream_;
|
FILE *stream_;
|
||||||
|
Report *report_;
|
||||||
|
const Unit *time_unit_;
|
||||||
|
const Unit *cap_unit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
writeLiberty(LibertyLibrary *lib,
|
writeLiberty(LibertyLibrary *lib,
|
||||||
const char *filename)
|
const char *filename,
|
||||||
|
StaState *sta)
|
||||||
{
|
{
|
||||||
FILE *stream = fopen(filename, "w");
|
FILE *stream = fopen(filename, "w");
|
||||||
if (stream) {
|
if (stream) {
|
||||||
LibertyWriter writer(lib, filename, stream);
|
LibertyWriter writer(lib, filename, stream, sta->report());
|
||||||
writer.writeLibrary();
|
writer.writeLibrary();
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
}
|
}
|
||||||
|
|
@ -54,12 +70,16 @@ writeLiberty(LibertyLibrary *lib,
|
||||||
throw FileNotWritable(filename);
|
throw FileNotWritable(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibertyWriter::LibertyWriter(LibertyLibrary *lib,
|
LibertyWriter::LibertyWriter(const LibertyLibrary *lib,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
FILE *stream) :
|
FILE *stream,
|
||||||
|
Report *report) :
|
||||||
library_(lib),
|
library_(lib),
|
||||||
filename_(filename),
|
filename_(filename),
|
||||||
stream_(stream)
|
stream_(stream),
|
||||||
|
report_(report),
|
||||||
|
time_unit_(lib->units()->timeUnit()),
|
||||||
|
cap_unit_(lib->units()->capacitanceUnit())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +87,11 @@ void
|
||||||
LibertyWriter::writeLibrary()
|
LibertyWriter::writeLibrary()
|
||||||
{
|
{
|
||||||
writeHeader();
|
writeHeader();
|
||||||
|
LibertyCellIterator cell_iter(library_);
|
||||||
|
while (cell_iter.hasNext()) {
|
||||||
|
const LibertyCell *cell = cell_iter.next();
|
||||||
|
writeCell(cell);
|
||||||
|
}
|
||||||
writeFooter();
|
writeFooter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,24 +102,24 @@ LibertyWriter::writeHeader()
|
||||||
fprintf(stream_, " comment : \"\";\n");
|
fprintf(stream_, " comment : \"\";\n");
|
||||||
fprintf(stream_, " delay_model : table_lookup;\n");
|
fprintf(stream_, " delay_model : table_lookup;\n");
|
||||||
fprintf(stream_, " simulation : false;\n");
|
fprintf(stream_, " simulation : false;\n");
|
||||||
Unit *cap_unit = library_->units()->capacitanceUnit();
|
const Unit *cap_unit = library_->units()->capacitanceUnit();
|
||||||
fprintf(stream_, " capacitive_load_unit (1,%s%s);\n",
|
fprintf(stream_, " capacitive_load_unit (1,%s%s);\n",
|
||||||
cap_unit->scaleAbreviation(),
|
cap_unit->scaleAbreviation(),
|
||||||
cap_unit->suffix());
|
cap_unit->suffix());
|
||||||
fprintf(stream_, " leakage_power_unit : 1pW;\n");
|
fprintf(stream_, " leakage_power_unit : 1pW;\n");
|
||||||
Unit *current_unit = library_->units()->currentUnit();
|
const Unit *current_unit = library_->units()->currentUnit();
|
||||||
fprintf(stream_, " current_unit : \"1%s%s\";\n",
|
fprintf(stream_, " current_unit : \"1%s%s\";\n",
|
||||||
current_unit->scaleAbreviation(),
|
current_unit->scaleAbreviation(),
|
||||||
current_unit->suffix());
|
current_unit->suffix());
|
||||||
Unit *res_unit = library_->units()->resistanceUnit();
|
const Unit *res_unit = library_->units()->resistanceUnit();
|
||||||
fprintf(stream_, " pulling_resistance_unit : \"1%s%s\";\n",
|
fprintf(stream_, " pulling_resistance_unit : \"1%s%s\";\n",
|
||||||
res_unit->scaleAbreviation(),
|
res_unit->scaleAbreviation(),
|
||||||
res_unit->suffix());
|
res_unit->suffix());
|
||||||
Unit *time_unit = library_->units()->timeUnit();
|
const Unit *time_unit = library_->units()->timeUnit();
|
||||||
fprintf(stream_, " time_unit : \"1%s%s\";\n",
|
fprintf(stream_, " time_unit : \"1%s%s\";\n",
|
||||||
time_unit->scaleAbreviation(),
|
time_unit->scaleAbreviation(),
|
||||||
time_unit->suffix());
|
time_unit->suffix());
|
||||||
Unit *volt_unit = library_->units()->voltageUnit();
|
const Unit *volt_unit = library_->units()->voltageUnit();
|
||||||
fprintf(stream_, " voltage_unit : \"1%s%s\";\n",
|
fprintf(stream_, " voltage_unit : \"1%s%s\";\n",
|
||||||
volt_unit->scaleAbreviation(),
|
volt_unit->scaleAbreviation(),
|
||||||
volt_unit->suffix());
|
volt_unit->suffix());
|
||||||
|
|
@ -121,17 +146,98 @@ LibertyWriter::writeHeader()
|
||||||
library_->slewDerateFromLibrary());
|
library_->slewDerateFromLibrary());
|
||||||
fprintf(stream_, "\n");
|
fprintf(stream_, "\n");
|
||||||
|
|
||||||
fprintf(stream_, " default_max_fanout : 40;\n");
|
bool exists;
|
||||||
fprintf(stream_, " default_max_transition : 2.00;\n");
|
float max_fanout;
|
||||||
fprintf(stream_, " default_cell_leakage_power : 100;\n");
|
library_->defaultFanoutLoad(max_fanout, exists);
|
||||||
fprintf(stream_, " default_fanout_load : 1.0;\n");
|
if (exists)
|
||||||
fprintf(stream_, " default_inout_pin_cap : 0.0;\n");
|
fprintf(stream_, " default_max_fanout : %.0f;\n", max_fanout);
|
||||||
fprintf(stream_, " default_input_pin_cap : 0.0;\n");
|
float max_slew;
|
||||||
fprintf(stream_, " default_output_pin_cap : 0.0;\n");
|
library_->defaultMaxSlew(max_slew, exists);
|
||||||
|
if (exists)
|
||||||
|
fprintf(stream_, " default_max_transition : %s;\n",
|
||||||
|
time_unit_->asString(max_slew, 3));
|
||||||
|
float max_cap;
|
||||||
|
library_->defaultMaxCapacitance(max_cap, exists);
|
||||||
|
if (exists)
|
||||||
|
fprintf(stream_, " default_max_capacitance : %s;\n",
|
||||||
|
cap_unit_->asString(max_cap, 3));
|
||||||
|
float fanout_load;
|
||||||
|
library_->defaultFanoutLoad(fanout_load, exists);
|
||||||
|
if (exists)
|
||||||
|
fprintf(stream_, " default_fanout_load : %.2f;\n", fanout_load);
|
||||||
fprintf(stream_, "\n");
|
fprintf(stream_, "\n");
|
||||||
fprintf(stream_, " nom_process : 1.0;\n");
|
fprintf(stream_, " nom_process : %.1f;\n",
|
||||||
fprintf(stream_, " nom_temperature : 125.00;\n");
|
library_->nominalProcess());
|
||||||
fprintf(stream_, " nom_voltage : 1.62;\n");
|
fprintf(stream_, " nom_temperature : %.1f;\n",
|
||||||
|
library_->nominalTemperature());
|
||||||
|
fprintf(stream_, " nom_voltage : %.2f;\n",
|
||||||
|
library_->nominalVoltage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibertyWriter::writeCell(const LibertyCell *cell)
|
||||||
|
{
|
||||||
|
fprintf(stream_, " cell (\"%s\") {\n", cell->name());
|
||||||
|
fprintf(stream_, " area : %.3f \n", cell->area());
|
||||||
|
if (cell->isMacro())
|
||||||
|
fprintf(stream_, " is_macro : true;\n");
|
||||||
|
|
||||||
|
LibertyCellPortBitIterator port_iter(cell);
|
||||||
|
while (port_iter.hasNext()) {
|
||||||
|
const LibertyPort *port = port_iter.next();
|
||||||
|
writePort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stream_, " }\n");
|
||||||
|
fprintf(stream_, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibertyWriter::writePort(const LibertyPort *port)
|
||||||
|
{
|
||||||
|
fprintf(stream_, " pin(\"%s\") {\n", port->name());
|
||||||
|
auto func = port->function();
|
||||||
|
if (func)
|
||||||
|
fprintf(stream_, " function : \"%s\";\n", func->asString());
|
||||||
|
fprintf(stream_, " direction : %s;\n" , asString(port->direction()));
|
||||||
|
if (port->isClock())
|
||||||
|
fprintf(stream_, " clock : true;\n");
|
||||||
|
fprintf(stream_, " capacitance : %s;\n",
|
||||||
|
cap_unit_->asString(port->capacitance(), 4));
|
||||||
|
|
||||||
|
float limit;
|
||||||
|
bool exists;
|
||||||
|
port->slewLimit(MinMax::max(), limit, exists);
|
||||||
|
if (exists)
|
||||||
|
fprintf(stream_, " max_transition : %s;\n",
|
||||||
|
time_unit_->asString(limit, 3));
|
||||||
|
port->capacitanceLimit(MinMax::max(), limit, exists);
|
||||||
|
if (exists)
|
||||||
|
fprintf(stream_, " max_capacitance : %s;\n",
|
||||||
|
cap_unit_->asString(limit, 3));
|
||||||
|
|
||||||
|
LibertyCellTimingArcSetIterator set_iter(port->libertyCell(),
|
||||||
|
nullptr, port);
|
||||||
|
while (set_iter.hasNext()) {
|
||||||
|
const TimingArcSet *arc_set = set_iter.next();
|
||||||
|
writeTimingArcSet(arc_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stream_, " }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set)
|
||||||
|
{
|
||||||
|
fprintf(stream_, " timing() {\n");
|
||||||
|
fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name());
|
||||||
|
if (arc_set->sense() != TimingSense::non_unate)
|
||||||
|
fprintf(stream_, " timing_sense : %s;\n",
|
||||||
|
timingSenseString(arc_set->sense()));
|
||||||
|
const char *timing_type = timingTypeString(arc_set);
|
||||||
|
if (timing_type)
|
||||||
|
fprintf(stream_, " timing_type : %s;\n", timing_type);
|
||||||
|
fprintf(stream_, " }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -140,4 +246,74 @@ LibertyWriter::writeFooter()
|
||||||
fprintf(stream_, "}\n");
|
fprintf(stream_, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
LibertyWriter::asString(bool value)
|
||||||
|
{
|
||||||
|
return value ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
LibertyWriter::asString(const PortDirection *dir)
|
||||||
|
{
|
||||||
|
if (dir == PortDirection::input())
|
||||||
|
return "input";
|
||||||
|
else if (dir == PortDirection::output()
|
||||||
|
|| (dir == PortDirection::tristate()))
|
||||||
|
return "output";
|
||||||
|
else if (dir == PortDirection::internal())
|
||||||
|
return "internal";
|
||||||
|
else if (dir == PortDirection::bidirect())
|
||||||
|
return "inout";
|
||||||
|
else if (dir == PortDirection::ground()
|
||||||
|
|| dir == PortDirection::power())
|
||||||
|
return "input";
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
LibertyWriter::timingTypeString(const TimingArcSet *arc_set)
|
||||||
|
{
|
||||||
|
const TimingRole *role = arc_set->role();
|
||||||
|
if (role == TimingRole::combinational())
|
||||||
|
return "combinational";
|
||||||
|
else if (role == TimingRole::tristateDisable())
|
||||||
|
return "three_state_disable";
|
||||||
|
else if (role == TimingRole::tristateEnable())
|
||||||
|
return "three_state_enable";
|
||||||
|
else if (role == TimingRole::regClkToQ()
|
||||||
|
|| role == TimingRole::latchEnToQ()) {
|
||||||
|
const TimingArc *arc = arc_set->arcs()[0];
|
||||||
|
if (arc->fromEdge()->asRiseFall() == RiseFall::rise())
|
||||||
|
return "rising_edge";
|
||||||
|
else
|
||||||
|
return "falling_edge";
|
||||||
|
}
|
||||||
|
else if (role == TimingRole::latchDtoQ())
|
||||||
|
return nullptr;
|
||||||
|
else if (role == TimingRole::regSetClr())
|
||||||
|
return "clear";
|
||||||
|
else if (role == TimingRole::setup()
|
||||||
|
|| role == TimingRole::recovery()) {
|
||||||
|
const TimingArc *arc = arc_set->arcs()[0];
|
||||||
|
if (arc->fromEdge()->asRiseFall() == RiseFall::rise())
|
||||||
|
return "setup_rising";
|
||||||
|
else
|
||||||
|
return "setup_falling";
|
||||||
|
}
|
||||||
|
else if (role == TimingRole::hold()
|
||||||
|
|| role == TimingRole::removal()) {
|
||||||
|
const TimingArc *arc = arc_set->arcs()[0];
|
||||||
|
if (arc->fromEdge()->asRiseFall() == RiseFall::rise())
|
||||||
|
return "hold_rising";
|
||||||
|
else
|
||||||
|
return "hold_falling";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
report_->reportLine("timing arc type %s not supported yet.",
|
||||||
|
role->asString());
|
||||||
|
criticalError(700, "timing arc type not supported yet.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ Unit::setScale(float scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
Unit::scaleAbreviation()
|
Unit::scaleAbreviation() const
|
||||||
{
|
{
|
||||||
if (fuzzyEqual(scale_, 1E+6))
|
if (fuzzyEqual(scale_, 1E+6))
|
||||||
return "M";
|
return "M";
|
||||||
|
|
|
||||||
|
|
@ -476,3 +476,4 @@
|
||||||
0622 PathVertex.cc:279 missing requireds.
|
0622 PathVertex.cc:279 missing requireds.
|
||||||
0623 PathVertexRep.cc:153 missing arrivals.
|
0623 PathVertexRep.cc:153 missing arrivals.
|
||||||
0624 PathVertexRep.cc:150 missing arrivals
|
0624 PathVertexRep.cc:150 missing arrivals
|
||||||
|
700
|
||||||
|
|
|
||||||
|
|
@ -2179,7 +2179,7 @@ void
|
||||||
write_liberty_cmd(LibertyLibrary *library,
|
write_liberty_cmd(LibertyLibrary *library,
|
||||||
char *filename)
|
char *filename)
|
||||||
{
|
{
|
||||||
writeLiberty(library, filename);
|
writeLiberty(library, filename, Sta::sta());
|
||||||
}
|
}
|
||||||
|
|
||||||
Library *
|
Library *
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue