Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions include/mockturtle/io/genlib_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,33 @@
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;
std::string expression;
uint32_t num_vars;
kitty::dynamic_truth_table function;
double area;
double delay;
std::vector<pin> pins;
}; /* gate */

/*! \brief lorina callbacks for GENLIB files.
Expand All @@ -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<double> delay ) const override
virtual void on_gate( std::string const& name, std::string const& expression, double area, std::vector<lorina::pin_spec> const& ps ) const override
{
uint32_t num_vars{0};
for ( const auto& c : expression )
Expand All @@ -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<pin> pp;
for ( const auto& p : ps )
{
pp.emplace_back( pin{p.name,
phase_type( static_cast<uint8_t>( 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:
Expand Down
100 changes: 79 additions & 21 deletions lib/lorina/lorina/genlib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,39 @@
namespace lorina
{

enum class phase_type : uint8_t
{
INV = 0,
NONINV = 1,
UNKNOWN = 2,
};

// PIN <pin-name> <phase> <input-load> <max-load> <rise-block-delay> <rise-fanout-delay> <fall-block-delay> <fall-fanout-delay>
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.
*/
class genlib_reader
{
public:
virtual void on_gate( std::string const& name, std::string const& expression, double area, std::optional<double> delay ) const
virtual void on_gate( std::string const& name, std::string const& expression, double area, std::vector<pin_spec> const& pins ) const
{
(void)name;
(void)expression;
(void)area;
(void)delay;
(void)pins;
}
}; /* genlib_reader */

Expand Down Expand Up @@ -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 <name> <area> <expression>;`)`",
line ) );
if ( diag )
diag->report( diagnostic_level::error, fmt::format( "line `{}` has unexpected structure (expected `GATE <name> <area> <expression>;`)`",
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<pin_spec> 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;
}

Expand Down Expand Up @@ -232,4 +290,4 @@ inline return_code read_genlib( const std::string& filename, const genlib_reader
}
}

} /* lorina */
} /* lorina */
38 changes: 33 additions & 5 deletions test/io/genlib_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

TEST_CASE( "read genlib file", "[genlib_reader]" )
{
using mockturtle::phase_type;

std::vector<mockturtle::gate> gates;

std::string const file{
Expand All @@ -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 );
}