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
163 changes: 96 additions & 67 deletions include/mockturtle/io/verilog_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ template<typename Ntk>
class verilog_reader : public lorina::verilog_reader
{
public:
explicit verilog_reader( Ntk& ntk ) : _ntk( ntk )
explicit verilog_reader( Ntk& ntk ) : ntk_( ntk )
{
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
static_assert( has_create_pi_v<Ntk>, "Ntk does not implement the create_pi function" );
Expand All @@ -89,18 +89,16 @@ class verilog_reader : public lorina::verilog_reader
static_assert( has_create_xor_v<Ntk>, "Ntk does not implement the create_xor function" );
static_assert( has_create_maj_v<Ntk>, "Ntk does not implement the create_maj function" );

signals["0"] = _ntk.get_constant( false );
signals["1"] = _ntk.get_constant( true );
signals["1'b0"] = _ntk.get_constant( false );
signals["1'b1"] = _ntk.get_constant( true );
signals_["0"] = ntk_.get_constant( false );
signals_["1"] = ntk_.get_constant( true );
signals_["1'b0"] = ntk_.get_constant( false );
signals_["1'b1"] = ntk_.get_constant( true );
}

~verilog_reader()
void on_module_header( const std::string& module_name, const std::vector<std::string>& inouts ) const override
{
for ( auto const& o : outputs )
{
_ntk.create_po( signals[o], o );
}
(void)inouts;
name_ = module_name;
}

void on_inputs( const std::vector<std::string>& names, std::string const& size = "" ) const override
Expand All @@ -110,18 +108,21 @@ class verilog_reader : public lorina::verilog_reader
{
if ( size.empty() )
{
signals[name] = _ntk.create_pi( name );
signals_[name] = ntk_.create_pi( name );
input_names_.emplace_back( name, 1u );
}
else
{
std::vector<signal<Ntk>> word;
for ( auto i = 0u; i < parse_size( size ); ++i )
const auto length = parse_size( size );
for ( auto i = 0u; i < length; ++i )
{
const auto sname = fmt::format( "{}[{}]", name, i );
word.push_back( _ntk.create_pi( sname ) );
signals[sname] = word.back();
word.push_back( ntk_.create_pi( sname ) );
signals_[sname] = word.back();
}
registers[name] = word;
registers_[name] = word;
input_names_.emplace_back( name, length );
}
}
}
Expand All @@ -133,100 +134,102 @@ class verilog_reader : public lorina::verilog_reader
{
if ( size.empty() )
{
outputs.emplace_back( name );
outputs_.emplace_back( name );
output_names_.emplace_back( name, 1u );
}
else
{
// TODO store bundles
for ( auto i = 0u; i < parse_size( size ); ++i )
const auto length = parse_size( size );
for ( auto i = 0u; i < length; ++i )
{
outputs.emplace_back( fmt::format( "{}[{}]", name, i ) );
outputs_.emplace_back( fmt::format( "{}[{}]", name, i ) );
}
output_names_.emplace_back( name, length );
}
}
}

void on_assign( const std::string& lhs, const std::pair<std::string, bool>& rhs ) const override
{
if ( signals.find( rhs.first ) == signals.end() )
if ( signals_.find( rhs.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", rhs.first ) << std::endl;

auto r = signals[rhs.first];
signals[lhs] = rhs.second ? _ntk.create_not( r ) : r;
auto r = signals_[rhs.first];
signals_[lhs] = rhs.second ? ntk_.create_not( r ) : r;
}

void on_and( const std::string& lhs, const std::pair<std::string, bool>& op1, const std::pair<std::string, bool>& op2 ) const override
{
if ( signals.find( op1.first ) == signals.end() )
if ( signals_.find( op1.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op1.first ) << std::endl;
if ( signals.find( op2.first ) == signals.end() )
if ( signals_.find( op2.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op2.first ) << std::endl;

auto a = signals[op1.first];
auto b = signals[op2.first];
signals[lhs] = _ntk.create_and( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b );
auto a = signals_[op1.first];
auto b = signals_[op2.first];
signals_[lhs] = ntk_.create_and( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b );
}

void on_or( const std::string& lhs, const std::pair<std::string, bool>& op1, const std::pair<std::string, bool>& op2 ) const override
{
if ( signals.find( op1.first ) == signals.end() )
if ( signals_.find( op1.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op1.first ) << std::endl;
if ( signals.find( op2.first ) == signals.end() )
if ( signals_.find( op2.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op2.first ) << std::endl;

auto a = signals[op1.first];
auto b = signals[op2.first];
signals[lhs] = _ntk.create_or( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b );
auto a = signals_[op1.first];
auto b = signals_[op2.first];
signals_[lhs] = ntk_.create_or( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b );
}

void on_xor( const std::string& lhs, const std::pair<std::string, bool>& op1, const std::pair<std::string, bool>& op2 ) const override
{
if ( signals.find( op1.first ) == signals.end() )
if ( signals_.find( op1.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op1.first ) << std::endl;
if ( signals.find( op2.first ) == signals.end() )
if ( signals_.find( op2.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op2.first ) << std::endl;

auto a = signals[op1.first];
auto b = signals[op2.first];
signals[lhs] = _ntk.create_xor( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b );
auto a = signals_[op1.first];
auto b = signals_[op2.first];
signals_[lhs] = ntk_.create_xor( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b );
}

void on_xor3( const std::string& lhs, const std::pair<std::string, bool>& op1, const std::pair<std::string, bool>& op2, const std::pair<std::string, bool>& op3 ) const override
{
if ( signals.find( op1.first ) == signals.end() )
if ( signals_.find( op1.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op1.first ) << std::endl;
if ( signals.find( op2.first ) == signals.end() )
if ( signals_.find( op2.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op2.first ) << std::endl;
if ( signals.find( op3.first ) == signals.end() )
if ( signals_.find( op3.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op3.first ) << std::endl;

auto a = signals[op1.first];
auto b = signals[op2.first];
auto c = signals[op3.first];
auto a = signals_[op1.first];
auto b = signals_[op2.first];
auto c = signals_[op3.first];

if constexpr ( has_create_xor3_v<Ntk> )
{
signals[lhs] = _ntk.create_xor3( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b, op3.second ? _ntk.create_not( c ) : c );
signals_[lhs] = ntk_.create_xor3( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b, op3.second ? ntk_.create_not( c ) : c );
}
else
{
signals[lhs] = _ntk.create_xor( _ntk.create_xor( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b ), op3.second ? _ntk.create_not( c ) : c );
signals_[lhs] = ntk_.create_xor( ntk_.create_xor( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b ), op3.second ? ntk_.create_not( c ) : c );
}
}

void on_maj3( const std::string& lhs, const std::pair<std::string, bool>& op1, const std::pair<std::string, bool>& op2, const std::pair<std::string, bool>& op3 ) const override
{
if ( signals.find( op1.first ) == signals.end() )
if ( signals_.find( op1.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op1.first ) << std::endl;
if ( signals.find( op2.first ) == signals.end() )
if ( signals_.find( op2.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op2.first ) << std::endl;
if ( signals.find( op3.first ) == signals.end() )
if ( signals_.find( op3.first ) == signals_.end() )
std::cerr << fmt::format( "[w] undefined signal {} assigned 0", op3.first ) << std::endl;

auto a = signals[op1.first];
auto b = signals[op2.first];
auto c = signals[op3.first];
signals[lhs] = _ntk.create_maj( op1.second ? _ntk.create_not( a ) : a, op2.second ? _ntk.create_not( b ) : b, op3.second ? _ntk.create_not( c ) : c );
auto a = signals_[op1.first];
auto b = signals_[op2.first];
auto c = signals_[op3.first];
signals_[lhs] = ntk_.create_maj( op1.second ? ntk_.create_not( a ) : a, op2.second ? ntk_.create_not( b ) : b, op3.second ? ntk_.create_not( c ) : c );
}

void on_module_instantiation( std::string const& module_name, std::vector<std::string> const& params, std::string const& inst_name,
Expand Down Expand Up @@ -255,7 +258,7 @@ class verilog_reader : public lorina::verilog_reader
};

const auto register_exists = [&]( std::string const& name ) {
if ( registers.find( name ) == registers.end() )
if ( registers_.find( name ) == registers_.end() )
{
std::cerr << fmt::format( "[e] register {} does not exist\n", name );
return false;
Expand All @@ -264,7 +267,7 @@ class verilog_reader : public lorina::verilog_reader
};

const auto register_has_size = [&]( std::string const& name, uint32_t size ) {
if ( !register_exists( name ) || registers[name].size() != size )
if ( !register_exists( name ) || registers_[name].size() != size )
{
std::cerr << fmt::format( "[e] register {} must have size {}\n", name, size );
return false;
Expand All @@ -275,9 +278,9 @@ class verilog_reader : public lorina::verilog_reader
const auto add_register = [&]( std::string const& name, std::vector<signal<Ntk>> const& fs ) {
for ( auto i = 0u; i < fs.size(); ++i )
{
signals[fmt::format( "{}[{}]", name, i) ] = fs[i];
signals_[fmt::format( "{}[{}]", name, i) ] = fs[i];
}
registers[name] = fs;
registers_[name] = fs;
};

if ( module_name == "ripple_carry_adder" )
Expand All @@ -288,10 +291,10 @@ class verilog_reader : public lorina::verilog_reader
if ( !register_has_size( args[0].second, bitwidth ) ) return;
if ( !register_has_size( args[1].second, bitwidth ) ) return;

auto a_copy = registers[args[0].second];
const auto& b = registers[args[1].second];
auto carry = _ntk.get_constant( false );
carry_ripple_adder_inplace( _ntk, a_copy, b, carry );
auto a_copy = registers_[args[0].second];
const auto& b = registers_[args[1].second];
auto carry = ntk_.get_constant( false );
carry_ripple_adder_inplace( ntk_, a_copy, b, carry );
a_copy.push_back( carry );
add_register( args[2].second, a_copy );
}
Expand All @@ -309,14 +312,37 @@ class verilog_reader : public lorina::verilog_reader
N.resize( bitwidth );
NN.resize( bitwidth );

add_register( args[2].second, montgomery_multiplication( _ntk, registers[args[0].second], registers[args[1].second], N, NN ) );
add_register( args[2].second, montgomery_multiplication( ntk_, registers_[args[0].second], registers_[args[1].second], N, NN ) );
}
else
{
std::cout << fmt::format( "[e] unknown module name {}\n", module_name );
}
}

void on_endmodule() const override
{
for ( auto const& o : outputs_ )
{
ntk_.create_po( signals_[o], o );
}
}

const std::string& name() const
{
return name_;
}

const std::vector<std::pair<std::string, uint32_t>> input_names()
{
return input_names_;
}

const std::vector<std::pair<std::string, uint32_t>> output_names()
{
return output_names_;
}

private:
std::vector<bool> parse_value( const std::string& value ) const
{
Expand Down Expand Up @@ -356,19 +382,22 @@ class verilog_reader : public lorina::verilog_reader

if ( auto const l = size.size(); l > 2 && size[l - 2] == ':' && size[l - 1] == '0' )
{
return parse_small_value( size.substr( 0u, l - 2 ) ) + 1u;
return static_cast<uint32_t>( parse_small_value( size.substr( 0u, l - 2 ) ) + 1u );
}

assert( false );
return 0u;
}

private:
Ntk& _ntk;

mutable std::map<std::string, signal<Ntk>> signals;
mutable std::map<std::string, std::vector<signal<Ntk>>> registers;
mutable std::vector<std::string> outputs;
Ntk& ntk_;

mutable std::map<std::string, signal<Ntk>> signals_;
mutable std::map<std::string, std::vector<signal<Ntk>>> registers_;
mutable std::vector<std::string> outputs_;
mutable std::string name_;
mutable std::vector<std::pair<std::string, uint32_t>> input_names_;
mutable std::vector<std::pair<std::string, uint32_t>> output_names_;

std::regex hex_string{"(\\d+)'h([0-9a-fA-F]+)"};
};
Expand Down
8 changes: 7 additions & 1 deletion test/io/verilog_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,18 @@ TEST_CASE( "read a VERILOG file to create large Montgomery multiplier", "[verilo
"endmodule\n"};

std::istringstream in( file );
const auto result = lorina::read_verilog( in, verilog_reader( xag ) );
verilog_reader reader( xag );
const auto result = lorina::read_verilog( in, reader );
xag = cleanup_dangling( xag );

/* structural checks */
CHECK( result == lorina::return_code::success );
CHECK( xag.num_pis() == 768u );
CHECK( xag.num_pos() == 384u );
CHECK( xag.num_gates() == 909459u );

/* name checks */
CHECK( reader.name() == "top" );
CHECK( reader.input_names() == std::vector<std::pair<std::string, uint32_t>>{{{"a", 384}, {"b", 384}}} );
CHECK( reader.output_names() == std::vector<std::pair<std::string, uint32_t>>{{{"c", 384}}} );
}