diff --git a/liberty/LibertyLex.ll b/liberty/LibertyLex.ll index 6aab5689..b6b4c449 100644 --- a/liberty/LibertyLex.ll +++ b/liberty/LibertyLex.ll @@ -74,7 +74,7 @@ HNAME ({PIN_NAME}|{BUS_NAME}|{MIXED_NAME})([\/.]({PIN_NAME}|{BUS_NAME}|{MIXED_NA /* default_operating_conditions : slow_100_3.00 ; */ /* revision : 1.0.17; */ /* default_wire_load : xc2v250-5_avg; */ -TOKEN ({ALPHA}|{DIGIT}|_)({ALPHA}|{DIGIT}|[._\-])*(:({ALPHA}|{DIGIT}|_)+)? +TOKEN ({ALPHA}|{DIGIT}|_|\$)({ALPHA}|{DIGIT}|[._\-$])*(:({ALPHA}|{DIGIT}|_)+)? /* bus_naming_style : %s[%d] ; */ BUS_STYLE "%s"{BUS_LEFT}"%d"{BUS_RIGHT} PUNCTUATION [,\:;|(){}+*&!'=] diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 695b2ccb..b27e5533 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include "Error.hh" #include "Format.hh" @@ -93,6 +94,27 @@ class LibertyWriter const Unit *cap_unit_; }; + +static std::string +portStaToLiberty(std::string_view sta_name) +{ + std::string liberty_name; + for (size_t i = 0; i < sta_name.length(); i += 1) { + char ch = sta_name[i]; + if (ch == '\\') { + char next_ch = sta_name[i + 1]; + if (next_ch == '\\') { + liberty_name += ch; + liberty_name += next_ch; + i++; + } + } + else + liberty_name += ch; + } + return liberty_name; +} + void writeLiberty(LibertyLibrary *lib, const char *filename, @@ -272,7 +294,7 @@ LibertyWriter::writeBusDcls() { BusDclSeq dcls = library_->busDcls(); for (BusDcl *dcl : dcls) { - sta::print(stream_, " type (\"{}\") {{\n", dcl->name()); + sta::print(stream_, " type (\"{}\") {{\n", portStaToLiberty(dcl->name())); sta::print(stream_, " base_type : array;\n"); sta::print(stream_, " data_type : bit;\n"); sta::print(stream_, " bit_width : {};\n", std::abs(dcl->from() - dcl->to()) + 1); @@ -295,7 +317,7 @@ LibertyWriter::writeCells() void LibertyWriter::writeCell(const LibertyCell *cell) { - sta::print(stream_, " cell (\"{}\") {{\n", cell->name()); + sta::print(stream_, " cell (\"{}\") {{\n", portStaToLiberty(cell->name())); float area = cell->area(); if (area > 0.0) sta::print(stream_, " area : {:.3f} \n", area); @@ -333,9 +355,9 @@ LibertyWriter::writeCell(const LibertyCell *cell) void LibertyWriter::writeBusPort(const LibertyPort *port) { - sta::print(stream_, " bus(\"{}\") {{\n", port->name()); + sta::print(stream_, " bus(\"{}\") {{\n", portStaToLiberty(port->name())); if (port->busDcl()) - sta::print(stream_, " bus_type : {};\n", port->busDcl()->name()); + sta::print(stream_, " bus_type : \"{}\";\n", portStaToLiberty(port->busDcl()->name())); writePortAttrs(port); LibertyPortMemberIterator member_iter(port); @@ -349,7 +371,7 @@ LibertyWriter::writeBusPort(const LibertyPort *port) void LibertyWriter::writePort(const LibertyPort *port) { - sta::print(stream_, " pin(\"{}\") {{\n", port->name()); + sta::print(stream_, " pin(\"{}\") {{\n", portStaToLiberty(port->name())); writePortAttrs(port); sta::print(stream_, " }}\n"); } @@ -362,18 +384,18 @@ LibertyWriter::writePortAttrs(const LibertyPort *port) if (func // cannot ref internal ports until sequentials are written && !(func->port() && func->port()->direction()->isInternal())) - sta::print(stream_, " function : \"{}\";\n", func->to_string()); + sta::print(stream_, " function : \"{}\";\n", portStaToLiberty(func->to_string())); auto tristate_enable = port->tristateEnable(); if (tristate_enable) { if (tristate_enable->op() == FuncExpr::Op::not_) { FuncExpr *three_state = tristate_enable->left(); sta::print(stream_, " three_state : \"{}\";\n", - three_state->to_string()); + portStaToLiberty(three_state->to_string())); } else { FuncExpr *three_state = tristate_enable->copy()->invert(); sta::print(stream_, " three_state : \"{}\";\n", - three_state->to_string()); + portStaToLiberty(three_state->to_string())); delete three_state; } } @@ -400,7 +422,7 @@ LibertyWriter::writePortAttrs(const LibertyPort *port) void LibertyWriter::writePwrGndPort(const LibertyPort *port) { - sta::print(stream_, " pg_pin(\"{}\") {{\n", port->name()); + sta::print(stream_, " pg_pin(\"{}\") {{\n", portStaToLiberty(port->name())); sta::print(stream_, " pg_type : \"{}\";\n", pwrGndTypeName(port->pwrGndType())); sta::print(stream_, " voltage_name : \"{}\";\n", port->voltageName()); sta::print(stream_, " }}\n"); @@ -426,7 +448,7 @@ LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set) { sta::print(stream_, " timing() {{\n"); if (arc_set->from()) - sta::print(stream_, " related_pin : \"{}\";\n", arc_set->from()->name()); + sta::print(stream_, " related_pin : \"{}\";\n", portStaToLiberty(arc_set->from()->name())); TimingSense sense = arc_set->sense(); if (sense != TimingSense::unknown && sense != TimingSense::non_unate) sta::print(stream_, " timing_sense : {};\n", to_string(sense)); diff --git a/test/liberty_write_escaped_names.lib b/test/liberty_write_escaped_names.lib new file mode 100644 index 00000000..dcb73cb6 --- /dev/null +++ b/test/liberty_write_escaped_names.lib @@ -0,0 +1,111 @@ +library (liberty_write_escaped_names) { + comment : ""; + delay_model : table_lookup; + simulation : false; + capacitive_load_unit (1,pF); + leakage_power_unit : 1pW; + current_unit : "1A"; + pulling_resistance_unit : "1kohm"; + time_unit : "1ns"; + voltage_unit : "1v"; + library_features(report_delay_calculation); + + input_threshold_pct_rise : 50; + input_threshold_pct_fall : 50; + output_threshold_pct_rise : 50; + output_threshold_pct_fall : 50; + slew_lower_threshold_pct_rise : 30; + slew_lower_threshold_pct_fall : 30; + slew_upper_threshold_pct_rise : 70; + slew_upper_threshold_pct_fall : 70; + slew_derate_from_library : 1.0; + + + nom_process : 1.0; + nom_temperature : 85.0; + nom_voltage : 0.75; + + type ("$vol_ts_new") { + base_type : array; + data_type : bit; + bit_width : 2; + bit_from : 1; + bit_to : 0; + } + + type ("div/u_div/QInv") { + base_type : array; + data_type : bit; + bit_width : 2; + bit_from : 1; + bit_to : 0; + } + + cell ("my_buf") { + pin("u_sub/data[0]") { + direction : input; + capacitance : 1.0000; + } + bus("div/u_div/QInv") { + bus_type : div/u_div/QInv; + direction : output; + capacitance : 0.0000; + pin("div/u_div/QInv[1]") { + direction : output; + capacitance : 0.0000; + timing() { + related_pin : "u_sub/data[0]"; + timing_sense : positive_unate; + timing_type : combinational; + cell_rise(scalar) { + values("1.00000"); + } + rise_transition(scalar) { + values("1.00000"); + } + cell_fall(scalar) { + values("1.00000"); + } + fall_transition(scalar) { + values("1.00000"); + } + } + } + pin("div/u_div/QInv[0]") { + direction : output; + capacitance : 0.0000; + timing() { + related_pin : "u_sub/data[0]"; + timing_sense : positive_unate; + timing_type : combinational; + cell_rise(scalar) { + values("1.00000"); + } + rise_transition(scalar) { + values("1.00000"); + } + cell_fall(scalar) { + values("1.00000"); + } + fall_transition(scalar) { + values("1.00000"); + } + } + } + } + bus("$vol_ts_new") { + bus_type : $vol_ts_new; + direction : output; + capacitance : 0.0000; + pin("$vol_ts_new[1]") { + direction : output; + capacitance : 0.0404; + } + pin("$vol_ts_new[0]") { + direction : output; + capacitance : 0.0411; + } + } + } + +} diff --git a/test/liberty_write_escaped_names.ok b/test/liberty_write_escaped_names.ok new file mode 100644 index 00000000..6f26583f --- /dev/null +++ b/test/liberty_write_escaped_names.ok @@ -0,0 +1,110 @@ +library (liberty_write_escaped_names) { + comment : ""; + delay_model : table_lookup; + simulation : false; + capacitive_load_unit (1,pF); + leakage_power_unit : 1pW; + current_unit : "1A"; + pulling_resistance_unit : "1kohm"; + time_unit : "1ns"; + voltage_unit : "1v"; + library_features(report_delay_calculation); + + input_threshold_pct_rise : 50; + input_threshold_pct_fall : 50; + output_threshold_pct_rise : 50; + output_threshold_pct_fall : 50; + slew_lower_threshold_pct_rise : 30; + slew_lower_threshold_pct_fall : 30; + slew_upper_threshold_pct_rise : 70; + slew_upper_threshold_pct_fall : 70; + slew_derate_from_library : 1.0; + + + nom_process : 1.0; + nom_temperature : 85.0; + nom_voltage : 0.75; + + type ("$vol_ts_new") { + base_type : array; + data_type : bit; + bit_width : 2; + bit_from : 1; + bit_to : 0; + } + type ("div/u_div/QInv") { + base_type : array; + data_type : bit; + bit_width : 2; + bit_from : 1; + bit_to : 0; + } + + cell ("my_buf") { + pin("u_sub/data[0]") { + direction : input; + capacitance : 1.0000; + } + bus("div/u_div/QInv") { + bus_type : "div/u_div/QInv"; + direction : output; + capacitance : 0.0000; + pin("div/u_div/QInv[1]") { + direction : output; + capacitance : 0.0000; + timing() { + related_pin : "u_sub/data[0]"; + timing_sense : positive_unate; + timing_type : combinational; + cell_rise(scalar) { + values("1.00000"); + } + rise_transition(scalar) { + values("1.00000"); + } + cell_fall(scalar) { + values("1.00000"); + } + fall_transition(scalar) { + values("1.00000"); + } + } + } + pin("div/u_div/QInv[0]") { + direction : output; + capacitance : 0.0000; + timing() { + related_pin : "u_sub/data[0]"; + timing_sense : positive_unate; + timing_type : combinational; + cell_rise(scalar) { + values("1.00000"); + } + rise_transition(scalar) { + values("1.00000"); + } + cell_fall(scalar) { + values("1.00000"); + } + fall_transition(scalar) { + values("1.00000"); + } + } + } + } + bus("$vol_ts_new") { + bus_type : "$vol_ts_new"; + direction : output; + capacitance : 0.0000; + pin("$vol_ts_new[1]") { + direction : output; + capacitance : 0.0404; + } + pin("$vol_ts_new[0]") { + direction : output; + capacitance : 0.0411; + } + } + } + +} diff --git a/test/liberty_write_escaped_names.tcl b/test/liberty_write_escaped_names.tcl new file mode 100644 index 00000000..660d0f07 --- /dev/null +++ b/test/liberty_write_escaped_names.tcl @@ -0,0 +1,3 @@ +# Verify write_liberty round-trips pin names containing / and [] +read_liberty liberty_write_escaped_names.lib +sta::write_liberty [get_libs liberty_write_escaped_names] results/liberty_write_escaped_names.log diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index fcb2c291..46f72212 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -156,6 +156,7 @@ record_public_tests { liberty_ccsn liberty_float_as_str liberty_latch3 + liberty_write_escaped_names make_concrete_parasitics_leak package_require path_group_names