diff --git a/include/mockturtle/io/genlib_reader.hpp b/include/mockturtle/io/genlib_reader.hpp index 7332b3e2a..4cbad5567 100644 --- a/include/mockturtle/io/genlib_reader.hpp +++ b/include/mockturtle/io/genlib_reader.hpp @@ -41,6 +41,25 @@ namespace mockturtle { +enum class phase_type : uint8_t +{ + INV = 0, + NONINV = 1, + UNKNOWN = 2, +}; + +struct pin +{ + std::string name; + phase_type phase; + double input_load; + double max_load; + double rise_block_delay; + double rise_fanout_delay; + double fall_block_delay; + double fall_fanout_delay; +}; /* pin */ + struct gate { std::string name; @@ -48,7 +67,7 @@ struct gate uint32_t num_vars; kitty::dynamic_truth_table function; double area; - double delay; + std::vector pins; }; /* gate */ /*! \brief lorina callbacks for GENLIB files. @@ -70,7 +89,7 @@ class genlib_reader : public lorina::genlib_reader : gates( gates ) {} - virtual void on_gate( std::string const& name, std::string const& expression, double area, std::optional delay ) const override + virtual void on_gate( std::string const& name, std::string const& expression, double area, std::vector const& ps ) const override { uint32_t num_vars{0}; for ( const auto& c : expression ) @@ -88,8 +107,15 @@ class genlib_reader : public lorina::genlib_reader kitty::dynamic_truth_table tt{num_vars}; create_from_expression( tt, expression ); - gates.emplace_back( gate{name, expression, num_vars, tt, - area, delay ? *delay : 1.0} ); + std::vector pp; + for ( const auto& p : ps ) + { + pp.emplace_back( pin{p.name, + phase_type( static_cast( p.phase ) ), + p.input_load, p.max_load, + p.rise_block_delay, p.rise_fanout_delay, p.fall_block_delay, p.fall_fanout_delay} ); + } + gates.emplace_back( gate{name, expression, num_vars, tt, area, pp} ); } protected: diff --git a/lib/lorina/lorina/genlib.hpp b/lib/lorina/lorina/genlib.hpp index 357bf56f7..3beace451 100644 --- a/lib/lorina/lorina/genlib.hpp +++ b/lib/lorina/lorina/genlib.hpp @@ -45,6 +45,26 @@ namespace lorina { +enum class phase_type : uint8_t +{ + INV = 0, + NONINV = 1, + UNKNOWN = 2, +}; + +// PIN +struct pin_spec +{ + std::string name; + phase_type phase; + double input_load; + double max_load; + double rise_block_delay; + double rise_fanout_delay; + double fall_block_delay; + double fall_fanout_delay; +}; /* pin_spec */ + /*! \brief A reader visitor for a GENLIB format. * * Callbacks for the GENLIB format. @@ -52,12 +72,12 @@ namespace lorina class genlib_reader { public: - virtual void on_gate( std::string const& name, std::string const& expression, double area, std::optional delay ) const + virtual void on_gate( std::string const& name, std::string const& expression, double area, std::vector const& pins ) const { (void)name; (void)expression; (void)area; - (void)delay; + (void)pins; } }; /* genlib_reader */ @@ -124,50 +144,88 @@ class genlib_parser } } - if ( diag && tokens.size() < 4u ) + if ( tokens.size() < 4u ) { - diag->report( diagnostic_level::error, fmt::format( "line `{}` has unexpected structure (expected `GATE ;`)`", - line ) ); + if ( diag ) + diag->report( diagnostic_level::error, fmt::format( "line `{}` has unexpected structure (expected `GATE ;`)`", + line ) ); return false; } - if ( diag && tokens[0] != "GATE" ) + if ( tokens[0] != "GATE" ) { - diag->report( diagnostic_level::error, fmt::format( "line `{}` does not start with keyword `GATE`", - line ) ); + if ( diag ) + diag->report( diagnostic_level::error, fmt::format( "line `{}` does not start with keyword `GATE`", + line ) ); return false; } auto const beg = tokens[3].find_first_of( "=" ); auto const end = tokens[3].find_first_of( ";" ); - if ( diag && ( beg == std::string::npos || end == std::string::npos ) ) + if ( beg == std::string::npos || end == std::string::npos ) { - diag->report( diagnostic_level::error, fmt::format( "expression `{}` is not immediately terminated with `;``", - tokens[3] ) ); + if ( diag ) + diag->report( diagnostic_level::error, fmt::format( "expression `{}` is not immediately terminated with `;``", + tokens[3] ) ); return false; } std::string const& name = tokens[1]; std::string const& expression = tokens[3].substr( beg + 1, end - beg - 1 ); double const area = std::stod( tokens[2] ); - if ( tokens.size() > 4u ) + + std::vector pins; + + uint64_t i{4}; + for ( ; i+8 < tokens.size(); i += 9 ) { - /* find delay information for gate */ - double delay{0.0}; - for ( auto i = 4u; i < tokens.size(); ++i ) + /* check PIN specification */ + if ( tokens[i] != "PIN" ) { - if ( tokens[i] == "PIN" ) + if ( diag ) + diag->report( diagnostic_level::error, fmt::format( "unexpected `{}` token (expected `PIN`)", + tokens[i] ) ); + return false; + } + + std::string const& name = tokens[i+1]; + phase_type phase{phase_type::UNKNOWN}; + if ( tokens[i+2] == "INV" ) + { + phase = phase_type::INV; + } + else if ( tokens[i+2] == "NONINV" ) + { + phase = phase_type::NONINV; + } + else + { + if ( tokens[i+2] != "UNKNOWN" ) { - delay = std::stod( tokens[ i + 3 ] ); + if ( diag ) + diag->report( diagnostic_level::warning, fmt::format( "unknown PIN phase type `{}` (expected `INV`, `NONINV`, or `UNKNOWN`)", + tokens[i+1] ) ); } } - reader.on_gate( name, expression, area, delay ); + double const input_load = std::stod( tokens[i+3] ); + double const max_load = std::stod( tokens[i+4] ); + double const rise_block_delay = std::stod( tokens[i+5] ); + double const rise_fanout_delay = std::stod( tokens[i+6] ); + double const fall_block_delay = std::stod( tokens[i+7] ); + double const fall_fanout_delay = std::stod( tokens[i+8] ); + + pins.emplace_back( pin_spec{name,phase,input_load,max_load,rise_block_delay,rise_fanout_delay,fall_block_delay,fall_fanout_delay} ); } - else + + if ( i != tokens.size() ) { - reader.on_gate( name, expression, area, std::nullopt ); + if ( diag ) + diag->report( diagnostic_level::error, fmt::format( "parsing failed at token `{}`", + tokens[i] ) ); + return false; } + reader.on_gate( name, expression, area, pins ); return true; } @@ -232,4 +290,4 @@ inline return_code read_genlib( const std::string& filename, const genlib_reader } } -} /* lorina */ \ No newline at end of file +} /* lorina */ diff --git a/test/io/genlib_reader.cpp b/test/io/genlib_reader.cpp index e0aadb94a..135f9a48d 100644 --- a/test/io/genlib_reader.cpp +++ b/test/io/genlib_reader.cpp @@ -8,6 +8,8 @@ TEST_CASE( "read genlib file", "[genlib_reader]" ) { + using mockturtle::phase_type; + std::vector gates; std::string const file{ @@ -28,33 +30,59 @@ TEST_CASE( "read genlib file", "[genlib_reader]" ) CHECK( gates[0u].function._bits[0] == 0 ); CHECK( gates[0u].num_vars == 0 ); CHECK( gates[0u].area == 0.0 ); - CHECK( gates[0u].delay == 1.0 ); + CHECK( gates[0u].pins.empty() ); CHECK( gates[1u].name == "one" ); CHECK( gates[1u].expression == "1" ); CHECK( gates[1u].function._bits[0] == 1 ); CHECK( gates[1u].num_vars == 0 ); CHECK( gates[1u].area == 0.0 ); - CHECK( gates[1u].delay == 1.0 ); + CHECK( gates[1u].pins.empty() ); CHECK( gates[2u].name == "inverter" ); CHECK( gates[2u].expression == "!a" ); CHECK( gates[2u].function._bits[0] == 1 ); CHECK( gates[2u].num_vars == 1 ); CHECK( gates[2u].area == 1.0 ); - CHECK( gates[2u].delay == 1.0 ); + CHECK( gates[2u].pins.size() == 1 ); + CHECK( gates[2u].pins[0u].name == "*" ); + CHECK( gates[2u].pins[0u].phase == phase_type::INV ); + CHECK( gates[2u].pins[0u].input_load == 1.0 ); + CHECK( gates[2u].pins[0u].max_load == 999.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); CHECK( gates[3u].name == "buffer" ); CHECK( gates[3u].expression == "a" ); CHECK( gates[3u].function._bits[0] == 2 ); CHECK( gates[3u].num_vars == 1 ); CHECK( gates[3u].area == 2.0 ); - CHECK( gates[3u].delay == 1.0 ); + CHECK( gates[3u].pins.size() == 1 ); + CHECK( gates[3u].pins[0u].name == "*" ); + CHECK( gates[3u].pins[0u].phase == phase_type::NONINV ); + CHECK( gates[2u].pins[0u].phase == phase_type::INV ); + CHECK( gates[2u].pins[0u].input_load == 1.0 ); + CHECK( gates[2u].pins[0u].max_load == 999.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); CHECK( gates[4u].name == "and" ); CHECK( gates[4u].expression == "(ab)" ); CHECK( gates[4u].function._bits[0] == 8 ); CHECK( gates[4u].num_vars == 2 ); CHECK( gates[4u].area == 5.0 ); - CHECK( gates[4u].delay == 1.0 ); + CHECK( gates[4u].pins.size() == 1 ); + CHECK( gates[4u].pins[0u].name == "*" ); + CHECK( gates[4u].pins[0u].phase == phase_type::NONINV ); + CHECK( gates[2u].pins[0u].phase == phase_type::INV ); + CHECK( gates[2u].pins[0u].input_load == 1.0 ); + CHECK( gates[2u].pins[0u].max_load == 999.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_block_delay == 1.0 ); + CHECK( gates[2u].pins[0u].rise_fanout_delay == 1.0 ); }