From 36a0a907a2b60cd6201f0530f5da22d99b42e7ca Mon Sep 17 00:00:00 2001 From: "Siang-Yun (Sonia) Lee" Date: Wed, 17 Nov 2021 15:24:43 +0100 Subject: [PATCH] Several I/O-related updates (#506) * update lorina * update test * update verilog io * buffered network names * update bill * missing include --- include/mockturtle/io/verilog_reader.hpp | 68 ++- include/mockturtle/io/write_verilog.hpp | 44 +- include/mockturtle/networks/buffered.hpp | 7 + include/mockturtle/utils/name_utils.hpp | 53 ++ lib/bill/bill/sat/solver/abc/system.h | 1 - lib/bill/bill/sat/solver/maple.hpp | 3 +- lib/lorina/lorina/bench.hpp | 68 ++- lib/lorina/lorina/blif.hpp | 35 +- lib/lorina/lorina/bristol.hpp | 5 +- .../detail/call_in_topological_order.hpp | 408 ++++++++++++++ lib/lorina/lorina/detail/utils.hpp | 114 +--- lib/lorina/lorina/super.hpp | 2 +- lib/lorina/lorina/verilog.hpp | 522 ++++++++++++------ test/io/write_verilog.cpp | 22 +- 14 files changed, 992 insertions(+), 360 deletions(-) create mode 100644 lib/lorina/lorina/detail/call_in_topological_order.hpp diff --git a/include/mockturtle/io/verilog_reader.hpp b/include/mockturtle/io/verilog_reader.hpp index a0330de6b..530d2d18d 100644 --- a/include/mockturtle/io/verilog_reader.hpp +++ b/include/mockturtle/io/verilog_reader.hpp @@ -118,6 +118,10 @@ class verilog_reader : public lorina::verilog_reader { signals_[name] = ntk_.create_pi( name ); input_names_.emplace_back( name, 1u ); + if constexpr ( has_set_name_v ) + { + ntk_.set_name( signals_[name], name ); + } } else { @@ -128,6 +132,10 @@ class verilog_reader : public lorina::verilog_reader const auto sname = fmt::format( "{}[{}]", name, i ); word.push_back( ntk_.create_pi( sname ) ); signals_[sname] = word.back(); + if constexpr ( has_set_name_v ) + { + ntk_.set_name( signals_[sname], sname ); + } } registers_[name] = word; input_names_.emplace_back( name, length ); @@ -350,35 +358,37 @@ class verilog_reader : public lorina::verilog_reader add_register( args[2].second, montgomery_multiplication( ntk_, registers_[args[0].second], registers_[args[1].second], N, NN ) ); } - else + else if ( module_name == "buffer" || module_name == "inverter" ) { if constexpr( is_buffered_network_type_v ) { static_assert( has_create_buf_v, "Ntk does not implement the create_buf method" ); - - if ( module_name == "buffer" || module_name == "inverter" ) + if ( !num_args_equals( 2u ) ) + fmt::print( stderr, "[e] number of arguments of a `{}` instance is not 2\n", module_name ); + + signal fi = ntk_.get_constant( false ); + std::string lhs; + for ( auto const& arg : args ) { - if ( !num_args_equals( 2u ) ) - fmt::print( stderr, "[e] number of arguments of a `{}` instance is not 2\n", module_name ); - - signal fi; - std::string lhs; - for ( auto const& arg : args ) + if ( arg.first == ".i" ) { - if ( arg.first == ".i" ) - fi = signals_[arg.second]; - else if ( arg.first == ".o" ) - lhs = arg.second; + if ( signals_.find( arg.second ) == signals_.end() ) + fmt::print( stderr, "[w] undefined signal {} assigned 0\n", arg.second ); else - fmt::print( stderr, "[e] unknown argument {} to a `{}` instance\n", arg.first, module_name ); + fi = signals_[arg.second]; } - if ( module_name == "inverter" ) - fi = ntk_.create_not( fi ); - signals_[lhs] = ntk_.create_buf( fi ); - return; + else if ( arg.first == ".o" ) + lhs = arg.second; + else + fmt::print( stderr, "[e] unknown argument {} to a `{}` instance\n", arg.first, module_name ); } + if ( module_name == "inverter" ) + fi = ntk_.create_not( fi ); + signals_[lhs] = ntk_.create_buf( fi ); } - + } + else + { fmt::print( stderr, "[e] unknown module name {}\n", module_name ); } } @@ -391,6 +401,26 @@ class verilog_reader : public lorina::verilog_reader { ntk_.create_po( signals_[o], o ); } + + if constexpr ( has_set_output_name_v ) + { + uint32_t ctr{0u}; + for ( auto const& output_name : output_names_ ) + { + if ( output_name.second == 1u ) + { + ntk_.set_output_name( ctr++, output_name.first ); + } + else + { + for ( auto i = 0u; i < output_name.second; ++i ) + { + ntk_.set_output_name( ctr++, fmt::format( "{}[{}]", output_name.first, i ) ); + } + } + } + assert( ctr == ntk_.num_pos() ); + } } const std::string& name() const diff --git a/include/mockturtle/io/write_verilog.hpp b/include/mockturtle/io/write_verilog.hpp index bd9f01c81..f0c98c374 100644 --- a/include/mockturtle/io/write_verilog.hpp +++ b/include/mockturtle/io/write_verilog.hpp @@ -140,8 +140,26 @@ void write_verilog( Ntk const& ntk, std::ostream& os, write_verilog_params const std::vector xs, inputs; if ( ps.input_names.empty() ) { - for ( auto i = 0u; i < ntk.num_pis(); ++i ) - xs.emplace_back( fmt::format( "x{}", i ) ); + if constexpr ( has_has_name_v && has_get_name_v ) + { + ntk.foreach_pi( [&]( auto const& i, uint32_t index ){ + if ( ntk.has_name( ntk.make_signal( i ) ) ) + { + xs.emplace_back( ntk.get_name( ntk.make_signal( i ) ) ); + } + else + { + xs.emplace_back( fmt::format( "x{}", index ) ); + } + }); + } + else + { + for ( auto i = 0u; i < ntk.num_pis(); ++i ) + { + xs.emplace_back( fmt::format( "x{}", i ) ); + } + } inputs = xs; } else @@ -165,8 +183,26 @@ void write_verilog( Ntk const& ntk, std::ostream& os, write_verilog_params const std::vector ys, outputs; if ( ps.output_names.empty() ) { - for ( auto i = 0u; i < ntk.num_pos(); ++i ) - ys.emplace_back( fmt::format( "y{}", i ) ); + if constexpr ( has_has_output_name_v && has_get_output_name_v ) + { + ntk.foreach_po( [&]( auto const& o, uint32_t index ){ + if ( ntk.has_output_name( index ) ) + { + ys.emplace_back( ntk.get_output_name( index ) ); + } + else + { + ys.emplace_back( fmt::format( "y{}", index ) ); + } + }); + } + else + { + for ( auto i = 0u; i < ntk.num_pos(); ++i ) + { + ys.emplace_back( fmt::format( "y{}", i ) ); + } + } outputs = ys; } else diff --git a/include/mockturtle/networks/buffered.hpp b/include/mockturtle/networks/buffered.hpp index 15dede02e..55c105a60 100644 --- a/include/mockturtle/networks/buffered.hpp +++ b/include/mockturtle/networks/buffered.hpp @@ -35,6 +35,7 @@ #include "../traits.hpp" #include "aig.hpp" #include "mig.hpp" +#include "../views/names_view.hpp" namespace mockturtle { @@ -521,7 +522,13 @@ class buffered_mig_network : public mig_network template<> struct is_buffered_network_type : std::true_type {}; +template<> +struct is_buffered_network_type> : std::true_type {}; + template<> struct is_buffered_network_type : std::true_type {}; +template<> +struct is_buffered_network_type> : std::true_type {}; + } // namespace mockturtle diff --git a/include/mockturtle/utils/name_utils.hpp b/include/mockturtle/utils/name_utils.hpp index 4474afd01..0e5231f76 100644 --- a/include/mockturtle/utils/name_utils.hpp +++ b/include/mockturtle/utils/name_utils.hpp @@ -28,6 +28,7 @@ \brief Utility functions to restore network names after optimization. \author Marcel Walter + \author Siang-Yun Lee */ #pragma once @@ -106,4 +107,56 @@ void restore_names( const NtkSrc& ntk_src, NtkDest& ntk_dest, node_map +void restore_pio_names_by_order( const NtkSrc& ntk_src, NtkDest& ntk_dest ) +{ + static_assert( is_network_type_v, "NtkSrc is not a network type" ); + static_assert( is_network_type_v, "NtkDest is not a network type" ); + static_assert( has_has_name_v && has_get_name_v, "NtkSrc does not implement the has_name and/or get_name functions" ); + static_assert( has_has_output_name_v && has_get_output_name_v, "NtkSrc does not implement the has_output_name and/or get_output_name functions" ); + static_assert( has_set_name_v && has_set_output_name_v, "NtkDest does not implement the set_name and/or set_output_name functions" ); + + assert( ntk_src.num_pis() == ntk_dest.num_pis() ); + assert( ntk_src.num_pos() == ntk_dest.num_pos() ); + + std::vector pi_names( ntk_src.num_pis(), "" ); + ntk_src.foreach_pi( [&]( auto const& n, auto i ){ + if ( ntk_src.has_name( ntk_src.make_signal( n ) ) ) + pi_names[i] = ntk_src.get_name( ntk_src.make_signal( n ) ); + }); + ntk_dest.foreach_pi( [&]( auto const& n, auto i ){ + if ( pi_names[i] != "" ) + ntk_dest.set_name( ntk_dest.make_signal( n ), pi_names[i] ); + }); + + ntk_src.foreach_po( [&]( auto const& f, auto i ){ + if ( ntk_src.has_output_name( i ) ) + ntk_dest.set_output_name( i, ntk_src.get_output_name( i ) ); + }); +} + } // namespace mockturtle diff --git a/lib/bill/bill/sat/solver/abc/system.h b/lib/bill/bill/sat/solver/abc/system.h index e8dedf2a0..4a3bfd7d7 100644 --- a/lib/bill/bill/sat/solver/abc/system.h +++ b/lib/bill/bill/sat/solver/abc/system.h @@ -21,7 +21,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #ifndef Abc_Glucose_System_h #define Abc_Glucose_System_h - #include "IntTypes.h" ABC_NAMESPACE_CXX_HEADER_START diff --git a/lib/bill/bill/sat/solver/maple.hpp b/lib/bill/bill/sat/solver/maple.hpp index 1fe75a7f8..0572f2a0a 100644 --- a/lib/bill/bill/sat/solver/maple.hpp +++ b/lib/bill/bill/sat/solver/maple.hpp @@ -1438,7 +1438,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA #define Minisat_System_h - //------------------------------------------------------------------------------------------------- namespace Maple { @@ -4578,7 +4577,7 @@ static void SIGALRM_switch(int signum) { switch_mode = true; } // NOTE: assumptions passed in member-variable 'assumptions'. inline lbool Solver::solve_() { - std::signal(SIGALRM, SIGALRM_switch); + ::signal(SIGALRM, SIGALRM_switch); alarm(2500); model.clear(); diff --git a/lib/lorina/lorina/bench.hpp b/lib/lorina/lorina/bench.hpp index 544c0a2cf..7236e7d75 100644 --- a/lib/lorina/lorina/bench.hpp +++ b/lib/lorina/lorina/bench.hpp @@ -177,23 +177,46 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); { return_code result = return_code::success; - const auto dispatch_function = [&]( std::vector inputs, std::string output, std::string type ) - { - if ( type == "" ) - { - reader.on_assign( inputs.front(), output ); - } - else if ( type == "DFF" ) - { - reader.on_dff( inputs.front(), output ); - } - else - { - reader.on_gate( inputs, output, type ); - } - }; - - detail::call_in_topological_order, std::string, std::string> on_action( dispatch_function ); + /* Function signature */ + using GateFn = detail::Func< + std::vector, + std::string, + std::string + >; + + /* Parameter maps */ + using GateParamMap = detail::ParamPackMap< + /* Key */ + std::string, + /* Params */ + std::vector, + std::string, + std::string + >; + + constexpr static const int GATE_FN{0}; + + using ParamMaps = detail::ParamPackMapN; + using PackedFns = detail::FuncPackN; + + detail::call_in_topological_order + on_action( PackedFns( GateFn( [&]( std::vector inputs, + std::string output, + std::string type ) + { + if ( type == "" ) + { + reader.on_assign( inputs.front(), output ); + } + else if ( type == "DFF" ) + { + reader.on_dff( inputs.front(), output ); + } + else + { + reader.on_gate( inputs, output, type ); + } + } ) ) ); on_action.declare_known( "vdd" ); on_action.declare_known( "gnd" ); @@ -226,7 +249,7 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); const auto type = detail::trim_copy( m[2] ); const auto args = detail::trim_copy( m[3] ); const auto inputs = detail::split( args, "," ); - on_action.call_deferred( inputs, output, inputs, output, type ); + on_action.call_deferred( inputs, { output }, std::make_tuple( inputs, output, type ) ); return true; } @@ -237,7 +260,7 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); const auto arg = detail::trim_copy( m[2] ); reader.on_dff_input( output ); on_action.declare_known( output ); - on_action.call_deferred( { arg }, output, { arg }, output, "DFF" ); + on_action.call_deferred( { arg }, { output }, std::make_tuple( std::vector{ arg }, output, "DFF" ) ); return true; } @@ -248,7 +271,7 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); const auto type = detail::trim_copy( m[2] ); const auto args = detail::trim_copy( m[3] ); const auto inputs = detail::split( args, "," ); - on_action.call_deferred( inputs, output, inputs, output, type ); + on_action.call_deferred( inputs, { output }, std::make_tuple( inputs, output, type ) ); return true; } @@ -257,7 +280,7 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); { const auto output = detail::trim_copy( m[1] ); const auto input = detail::trim_copy( m[2] ); - on_action.call_deferred( { input }, output, { input }, output, "" ); + on_action.call_deferred( { input }, { output }, std::make_tuple( std::vector{ input }, output, "" ) ); return true; } @@ -273,7 +296,10 @@ static std::regex gate_asgn( R"((.*)\s+=\s+(.*))" ); /* check dangling objects */ const auto& deps = on_action.unresolved_dependencies(); if ( deps.size() > 0 ) + { result = return_code::parse_error; + } + for ( const auto& r : deps ) { if ( diag ) diff --git a/lib/lorina/lorina/blif.hpp b/lib/lorina/lorina/blif.hpp index 628d66378..be4969547 100644 --- a/lib/lorina/lorina/blif.hpp +++ b/lib/lorina/lorina/blif.hpp @@ -278,7 +278,32 @@ static std::regex end( R"(.end)" ); { return_code result = return_code::success; - const auto dispatch_function = [&]( std::vector inputs, std::string output, std::vector> tt ) + /* Function signature */ + using GateFn = detail::Func< + std::vector, + std::string, + std::vector> + >; + + /* Parameter maps */ + using GateParamMap = detail::ParamPackMap< + /* Key */ + std::string, + /* Params */ + std::vector, + std::string, + std::vector> + >; + + constexpr static const int GATE_FN{0}; + + using ParamMaps = detail::ParamPackMapN; + using PackedFns = detail::FuncPackN; + + detail::call_in_topological_order + on_action( PackedFns( GateFn( [&]( std::vector inputs, + std::string output, + std::vector> tt ) { /* ignore latches */ if ( output == "" ) @@ -288,9 +313,7 @@ static std::regex end( R"(.end)" ); } reader.on_gate( inputs, output, tt ); - }; - - detail::call_in_topological_order, std::string, std::vector>> on_action( dispatch_function ); + } ) ) ); std::smatch m; detail::foreach_line_in_file_escape( in, [&]( std::string line ) { @@ -328,7 +351,7 @@ static std::regex end( R"(.end)" ); return false; } ); - on_action.call_deferred( args, output, args, output, tt ); + on_action.call_deferred( args, { output }, std::tuple( args, output, tt ) ); if ( in.eof() ) { @@ -394,7 +417,7 @@ static std::regex end( R"(.end)" ); on_action.declare_known( output ); reader.on_latch( input, output, type, control, init_value ); - on_action.compute_dependencies( output ); + on_action.compute_dependencies( { output } ); return true; } diff --git a/lib/lorina/lorina/bristol.hpp b/lib/lorina/lorina/bristol.hpp index c35798d47..f53a6b42c 100644 --- a/lib/lorina/lorina/bristol.hpp +++ b/lib/lorina/lorina/bristol.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include namespace lorina @@ -178,7 +179,7 @@ class bristol_parser * \param diag An optional diagnostic engine with callback methods for parse errors * \return Success if parsing has been successful, or parse error if parsing has failed */ -[[nodiscard]] inline return_code read_bristol( std::istream& is, bristol_reader const& reader, diagnostic_engine* diag = nullptr ) +[[nodiscard]] inline return_code read_bristol( std::istream& is, const bristol_reader& reader, diagnostic_engine* diag = nullptr ) { (void)diag; return bristol_parser( is, reader ).run(); @@ -194,7 +195,7 @@ class bristol_parser * \param diag An optional diagnostic engine with callback methods for parse errors * \return Success if parsing has been successful, or parse error if parsing has failed */ -[[nodiscard]] inline return_code read_bristol( std::string const& filename, bristol_reader const& reader, diagnostic_engine* diag = nullptr ) +[[nodiscard]] inline return_code read_bristol( const std::string& filename, const bristol_reader& reader, diagnostic_engine* diag = nullptr ) { std::ifstream in( filename, std::ifstream::in ); if ( !in.is_open() ) diff --git a/lib/lorina/lorina/detail/call_in_topological_order.hpp b/lib/lorina/lorina/detail/call_in_topological_order.hpp new file mode 100644 index 000000000..cdf7645e9 --- /dev/null +++ b/lib/lorina/lorina/detail/call_in_topological_order.hpp @@ -0,0 +1,408 @@ +/* lorina: C++ parsing library + * Copyright (C) 2018-2021 EPFL + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/*! \cond PRIVATE */ + +#pragma once + +#include + +namespace lorina +{ + +namespace detail +{ + +/* std::apply in C++14 taken from https://stackoverflow.com/a/36656413 */ +template +auto apply( Function f, Tuple t, std::index_sequence ) +{ + return f( std::get(t)... ); +} + +template +auto apply( Function f, Tuple t ) +{ + static constexpr auto size = std::tuple_size::value; + return apply( f, t, std::make_index_sequence{} ); +} + +/* \brief Parameter pack + * + * A pack of parameters of different types + * + * Example: + * using PackedParams = ParamPack; + * + * PackedParams params; + * params.set( 10, "a", 10.5f ); + */ +template +class ParamPack +{ +public: + using Tuple = std::tuple; + +public: + explicit ParamPack() {} + + explicit ParamPack( Args... params ) + : params_( std::make_tuple( params... ) ) + {} + + explicit ParamPack( const std::tuple& tup ) + : params_( tup ) + {} + + void set( Args... params ) + { + params_ = std::make_tuple( params... ); + } + + auto get() const + { + return params_; + } + +private: + std::tuple params_; +}; // ParamPack + +/* \brief Multple parameter packs + * + * A vector of N parameter packs + * + * Example: + * using PackedParamsA = ParamPack; + * using PackedParamsB = ParamPack; + * + * PackedParamsA params_a( 10, "a", 4 ); + * PackedParamsB params_b( 2.0, 3 ); + * ParamPackN + * params( params_a, params_b ); + */ +template +class ParamPackN +{ +public: + explicit ParamPackN() + {} + + explicit ParamPackN( ParamPacks... packs ) + : packs_( std::make_tuple( packs... ) ) + {} + + template + void set( typename std::tuple_element>::type const& pack ) + { + static_assert( I < sizeof...( ParamPacks ) ); + std::get( packs_ ) = pack; + } + + template + auto get() const + { + static_assert( I < sizeof...( ParamPacks ) ); + return std::get( packs_ ); + } + +private: + std::tuple packs_; +}; // ParamPackN + +/* \brief Parameter pack map + * + * A map from a KeyType to a parameter pack + * + * Example: + * ParamPackMap param_map; + * param_map["a"] = ParamPack( 10, "a", 10 ); + * param_map["b"] = ParamPack( 10, "b", 10 ); + */ +template +class ParamPackMap +{ +public: + using ValueType = typename detail::ParamPack::Tuple; + +public: + explicit ParamPackMap() {} + + auto& operator[]( const KeyType& key ) + { + return map_[key]; + } + + const auto& operator[]( const KeyType& key ) const + { + return map_[key]; + } + + void insert( const KeyType& key, const std::tuple& tup ) + { + map_[key] = ParamPack( tup ); + } + + void insert( const KeyType& key, Args... args ) + { + map_[key] = ParamPack( std::make_tuple( args... ) ); + } + +private: + std::unordered_map> map_; +}; + +/* \brief Multiple parameter pack maps + * + * A vector of N parameter pack maps + * + * Example: + * using StringToStringMap = ParamPackMap; + * using StringToIntMap = ParamPackMap; + * + * ParamPackMapN maps; + * maps.get<0>()["a"] = ParamPack( std::string{"a"} ); + * maps.get<1>()["b"] = ParamPack( 10 ); + */ +template +class ParamPackMapN +{ +public: + explicit ParamPackMapN() {} + + template + auto& get() + { + static_assert( I < sizeof...( ParamMaps ) ); + return std::get( maps_ ); + } + + template + auto& get() const + { + static_assert( I < sizeof...( ParamMaps ) ); + return std::get( maps_ ); + } + +private: + std::tuple maps_; +}; + +/* \brief A callable function + * + * Example: + * Func f; + * f( std::tuple( 10, "a" ) ); + * f( std::tuple( 12, "b" ) ); + */ +template +class Func +{ +public: + using Tuple = std::tuple; + +public: + Func( std::function fn ) + : fn_( fn ) + {} + + void operator()( Tuple const& tup ) + { + detail::apply( fn_, tup ); + } + +private: + std::function fn_; +}; // FuncPack + +/* \brief Multiple packed functions + * + * A vector of N packed functions + * + * Example: + * using Fn_A = Func; + * using Fn_B = Func; + * + * FuncPackN functions( + * Fn_A( []( int a, std::string b ){ std::cout << a << ' ' << b << std::endl; } ), + * Fn_B( []( double a, int b ){ std::cout << a << ' ' << b << std::endl; } ) + * ); + * + * functions.apply<0>( std::tuple( 10, "foo" ) ); + * functions.apply<0>( std::tuple( 12, "bar" ) ); + * functions.apply<1>( std::tuple( 3.41, 0 ) ); + * functions.apply<1>( std::tuple( 2.58, 1 ) ); + */ +template +class FuncPackN +{ +public: + explicit FuncPackN( std::tuple fns ) + : fns_( fns ) + {} + + explicit FuncPackN( Fns... fns ) + : fns_( std::make_tuple( fns... ) ) + {} + + template + void apply( typename std::tuple_element>::type::Tuple const& tup ) + { + std::get( fns_ )( tup ); + } + +private: + std::tuple fns_; +}; // FuncPackN + +template +struct call_in_topological_order; + +template +struct call_in_topological_order, ParamPackMapN> +{ +public: + using dependency_type = std::pair; + +public: + explicit call_in_topological_order( FuncPackN fns ) + : fns_( fns ) + {} + + void declare_known( const std::string& name ) + { + known_.emplace( name ); + } + + template + void call_deferred( const std::vector& inputs, + const std::vector& outputs, + const typename std::tuple_element>::type::ValueType& tup ) + { + /* do we have all inputs */ + std::unordered_set unknown; + for ( const auto& input : inputs ) + { + if ( known_.find( input ) != std::end( known_ ) ) + continue; + + const auto it = waits_for_.find( input ); + if ( it == std::end( waits_for_ ) || !it->second.empty() ) + { + unknown.insert( input ); + } + } + + /* store the parameters */ + for ( const auto& output : outputs ) + { + param_maps_.template get()[output] = ParamPack( tup ); + } + + if ( !unknown.empty() ) + { + /* defer computation */ + for ( const auto& input : unknown ) + { + for ( const auto& output : outputs ) + { + triggers_[input].insert( output ); + waits_for_[output].insert( input ); + } + } + return; + } + + /* trigger dependency computation */ + for ( const auto& output : outputs ) + { + compute_dependencies( output ); + } + } + + template + void compute_dependencies( const std::string& output ) + { + /* init empty, makes sure nothing is waiting for this output */ + waits_for_[output]; + + std::stack computed; + computed.push( output ); + + while ( !computed.empty() ) + { + auto const next = computed.top(); + computed.pop(); + + // C++17: std::apply( f, _stored_params[next] ); + // detail::apply( f_, stored_params_[next] ); + + fns_.template apply( param_maps_.template get()[next].get() ); + + /* activate all the triggers */ + for ( const auto& other : triggers_[next] ) + { + waits_for_[other].erase( next ); + if ( waits_for_[other].empty() ) + { + computed.push( other ); + } + } + triggers_[next].clear(); + } + } + + std::vector unresolved_dependencies() + { + std::vector deps; + for ( const auto& item : waits_for_ ) + { + auto const& key = item.first; + auto const& wait_list = item.second; + + if ( wait_list.empty() ) + continue; + + /* collect all keys that are still waiting for an item */ + for ( const auto& entry : wait_list ) + { + deps.emplace_back( key, entry ); + } + } + return deps; + } + +private: + FuncPackN fns_; + ParamPackMapN param_maps_; + + std::unordered_set known_; + std::unordered_map> waits_for_; + std::unordered_map> triggers_; +}; // call_in_topological_order + +} // namespace detail + +} // namespace lorina diff --git a/lib/lorina/lorina/detail/utils.hpp b/lib/lorina/lorina/detail/utils.hpp index 6876bd052..15e9b7ad4 100644 --- a/lib/lorina/lorina/detail/utils.hpp +++ b/lib/lorina/lorina/detail/utils.hpp @@ -50,6 +50,8 @@ #include #endif +#include "call_in_topological_order.hpp" + namespace lorina { @@ -100,118 +102,6 @@ inline std::istream& getline( std::istream& is, std::string& t ) } } -/* std::apply in C++14 taken from https://stackoverflow.com/a/36656413 */ -template -auto apply(Function f, Tuple t, std::index_sequence) -{ - return f(std::get(t) ...); -} - -template -auto apply(Function f, Tuple t) -{ - static constexpr auto size = std::tuple_size::value; - return apply(f, t, std::make_index_sequence{}); -} - -template -class call_in_topological_order -{ -public: - explicit call_in_topological_order( std::function f ) - : f( f ) - { - } - - void declare_known( const std::string& known ) - { - _known.emplace( known ); - } - - void call_deferred( const std::vector& inputs, const std::string& output, Args... params ) - { - /* do we have all inputs */ - std::unordered_set unknown; - for ( const auto& input : inputs ) - { - if ( _known.find( input ) != _known.end() ) - continue; - - auto it = _waits_for.find( input ); - if ( it == _waits_for.end() || !it->second.empty() ) - { - unknown.insert( input ); - } - } - - std::tuple args = std::make_tuple( params... ); - _stored_params.emplace( output, args ); - - if ( !unknown.empty() ) - { - /* defer computation */ - for ( const auto& input : unknown ) - { - _triggers[input].insert( output ); - _waits_for[output].insert( input ); - } - return; - } - - /* trigger dependency computation */ - compute_dependencies( output ); - } - - void compute_dependencies( const std::string& output ) - { - /* init empty, makes sure nothing is waiting for this output */ - _waits_for[output]; - std::stack computed; - computed.push( output ); - while ( !computed.empty() ) - { - auto next = computed.top(); - computed.pop(); - - // C++17: std::apply( f, _stored_params[next] ); - detail::apply( f, _stored_params[next] ); - - for ( const auto& other : _triggers[next] ) - { - _waits_for[other].erase( next ); - if ( _waits_for[other].empty() ) - { - computed.push( other ); - } - } - _triggers[next].clear(); - } - } - - std::vector> unresolved_dependencies() - { - std::vector> deps; - for ( const auto& w : _waits_for ) - { - if ( !w.second.empty() ) - { - for ( const auto& v : w.second ) - { - deps.push_back( std::make_pair( w.first, v ) ); - } - } - } - return deps; - } - -private: - std::unordered_set _known; - std::unordered_map> _triggers; - std::unordered_map> _waits_for; - std::function f; - std::unordered_map> _stored_params; -}; /* call_in_topological_order */ - template inline std::string join( const T& t, const std::string& sep ) { diff --git a/lib/lorina/lorina/super.hpp b/lib/lorina/lorina/super.hpp index 7bb46717f..7cd0f44ed 100644 --- a/lib/lorina/lorina/super.hpp +++ b/lib/lorina/lorina/super.hpp @@ -96,7 +96,7 @@ class super_parser detail::trim( line ); /* skip comments and empty lines */ - if ( line[0] == '#' || line.empty() ) + if ( line[0] == '#' || line[0] == '\0' || line.empty() ) { continue; } diff --git a/lib/lorina/lorina/verilog.hpp b/lib/lorina/lorina/verilog.hpp index 5212a2d44..c9cd92ec9 100644 --- a/lib/lorina/lorina/verilog.hpp +++ b/lib/lorina/lorina/verilog.hpp @@ -35,9 +35,9 @@ #pragma once #include "common.hpp" -#include "diagnostics.hpp" -#include "detail/utils.hpp" #include "detail/tokenizer.hpp" +#include "detail/utils.hpp" +#include "diagnostics.hpp" #include "verilog_regex.hpp" #include #include @@ -128,7 +128,7 @@ class verilog_reader * signal in inst_name. */ virtual void on_module_instantiation( std::string const& module_name, std::vector const& params, std::string const& inst_name, - std::vector> const& args ) const + std::vector> const& args ) const { (void)module_name; (void)params; @@ -323,7 +323,8 @@ class verilog_pretty_printer : public verilog_reader void on_inputs( const std::vector& inputs, std::string const& size = "" ) const override { - if ( inputs.size() == 0 ) return; + if ( inputs.size() == 0 ) + return; _os << "input "; if ( size != "" ) _os << "[" << size << "] "; @@ -339,7 +340,8 @@ class verilog_pretty_printer : public verilog_reader void on_outputs( const std::vector& outputs, std::string const& size = "" ) const override { - if ( outputs.size() == 0 ) return; + if ( outputs.size() == 0 ) + return; _os << "output "; if ( size != "" ) _os << "[" << size << "] "; @@ -355,7 +357,8 @@ class verilog_pretty_printer : public verilog_reader void on_wires( const std::vector& wires, std::string const& size = "" ) const override { - if ( wires.size() == 0 ) return; + if ( wires.size() == 0 ) + return; _os << "wire "; if ( size != "" ) _os << "[" << size << "] "; @@ -377,11 +380,11 @@ class verilog_pretty_printer : public verilog_reader void on_assign( const std::string& lhs, const std::pair& rhs ) const override { const std::string param = rhs.second ? fmt::format( "~{}", rhs.first ) : rhs.first; - _os << fmt::format("assign {} = {} ;\n", lhs, param ); + _os << fmt::format( "assign {} = {} ;\n", lhs, param ); } virtual void on_module_instantiation( std::string const& module_name, std::vector const& params, std::string const& inst_name, - std::vector> const& args ) const override + std::vector> const& args ) const override { _os << module_name << " "; if ( params.size() > 0u ) @@ -412,42 +415,42 @@ class verilog_pretty_printer : public verilog_reader { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = {} & {} ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = {} & {} ;\n", lhs, p1, p2 ); } void on_nand( const std::string& lhs, const std::pair& op1, const std::pair& op2 ) const override { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = ~({} & {}) ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = ~({} & {}) ;\n", lhs, p1, p2 ); } void on_or( const std::string& lhs, const std::pair& op1, const std::pair& op2 ) const override { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = {} | {} ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = {} | {} ;\n", lhs, p1, p2 ); } void on_nor( const std::string& lhs, const std::pair& op1, const std::pair& op2 ) const override { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = ~({} | {}) ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = ~({} | {}) ;\n", lhs, p1, p2 ); } void on_xor( const std::string& lhs, const std::pair& op1, const std::pair& op2 ) const override { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = {} ^ {} ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = {} ^ {} ;\n", lhs, p1, p2 ); } void on_xnor( const std::string& lhs, const std::pair& op1, const std::pair& op2 ) const override { const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; - _os << fmt::format("assign {} = ~({} ^ {}) ;\n", lhs, p1, p2 ); + _os << fmt::format( "assign {} = ~({} ^ {}) ;\n", lhs, p1, p2 ); } void on_and3( const std::string& lhs, const std::pair& op1, const std::pair& op2, const std::pair& op3 ) const override @@ -455,7 +458,7 @@ class verilog_pretty_printer : public verilog_reader const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; const std::string p3 = op3.second ? fmt::format( "~{}", op3.first ) : op3.first; - _os << fmt::format("assign {} = {} & {} & {} ;\n", lhs, p1, p2, p3 ); + _os << fmt::format( "assign {} = {} & {} & {} ;\n", lhs, p1, p2, p3 ); } void on_or3( const std::string& lhs, const std::pair& op1, const std::pair& op2, const std::pair& op3 ) const override @@ -463,7 +466,7 @@ class verilog_pretty_printer : public verilog_reader const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; const std::string p3 = op3.second ? fmt::format( "~{}", op3.first ) : op3.first; - _os << fmt::format("assign {} = {} | {} | {} ;\n", lhs, p1, p2, p3 ); + _os << fmt::format( "assign {} = {} | {} | {} ;\n", lhs, p1, p2, p3 ); } void on_xor3( const std::string& lhs, const std::pair& op1, const std::pair& op2, const std::pair& op3 ) const override @@ -471,7 +474,7 @@ class verilog_pretty_printer : public verilog_reader const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; const std::string p3 = op3.second ? fmt::format( "~{}", op3.first ) : op3.first; - _os << fmt::format("assign {} = {} ^ {} ^ {} ;\n", lhs, p1, p2, p3 ); + _os << fmt::format( "assign {} = {} ^ {} ^ {} ;\n", lhs, p1, p2, p3 ); } void on_maj3( const std::string& lhs, const std::pair& op1, const std::pair& op2, const std::pair& op3 ) const override @@ -479,12 +482,13 @@ class verilog_pretty_printer : public verilog_reader const std::string p1 = op1.second ? fmt::format( "~{}", op1.first ) : op1.first; const std::string p2 = op2.second ? fmt::format( "~{}", op2.first ) : op2.first; const std::string p3 = op3.second ? fmt::format( "~{}", op3.first ) : op3.first; - _os << fmt::format("assign {0} = ( {1} & {2} ) | ( {1} & {3} ) | ( {2} & {3} ) ;\n", lhs, p1, p2, p3 ); + _os << fmt::format( "assign {0} = ( {1} & {2} ) | ( {1} & {3} ) | ( {2} & {3} ) ;\n", lhs, p1, p2, p3 ); } void on_endmodule() const override { - _os << "endmodule\n" << std::endl; + _os << "endmodule\n" + << std::endl; } void on_comment( const std::string& comment ) const override @@ -493,8 +497,7 @@ class verilog_pretty_printer : public verilog_reader } std::ostream& _os; /*!< Output stream */ -}; /* verilog_pretty_printer */ - +}; /* verilog_pretty_printer */ /*! \brief A writer for a simplistic VERILOG format. * @@ -509,8 +512,9 @@ class verilog_writer * \param os Output stream */ explicit verilog_writer( std::ostream& os ) - : _os( os ) - {} + : _os( os ) + { + } /*! \brief Callback method for writing begin of a module declaration. * @@ -542,7 +546,7 @@ class verilog_writer */ virtual void on_input( uint32_t width, std::string const& name ) const { - _os << fmt::format( " input [{}:0] {} ;\n", width - 1 , name ); + _os << fmt::format( " input [{}:0] {} ;\n", width - 1, name ); } /*! \brief Callback method for writing multiple single 1-bit input. @@ -580,7 +584,7 @@ class verilog_writer */ virtual void on_output( uint32_t width, std::string const& name ) const { - _os << fmt::format( " output [{}:0] {} ;\n", width - 1 , name ); + _os << fmt::format( " output [{}:0] {} ;\n", width - 1, name ); } /*! \brief Callback method for writing multiple single 1-bit output. @@ -618,7 +622,7 @@ class verilog_writer */ virtual void on_wire( uint32_t width, std::string const& name ) const { - _os << fmt::format( " wire [{}:0] {} ;\n", width - 1 , name ); + _os << fmt::format( " wire [{}:0] {} ;\n", width - 1, name ); } /*! \brief Callback method for writing multiple single 1-bit wire. @@ -654,7 +658,7 @@ class verilog_writer * \param args List of arguments (first: I/O pin name, second: wire name) */ virtual void on_module_instantiation( std::string const& module_name, std::vector const& params, std::string const& inst_name, - std::vector> const& args ) const + std::vector> const& args ) const { _os << fmt::format( " {} ", module_name ); if ( params.size() > 0u ) @@ -666,10 +670,10 @@ class verilog_writer if ( i + 1 < params.size() ) _os << ", "; } - _os << ")"; + _os << ") "; } - _os << fmt::format( " {}( ", inst_name ); + _os << fmt::format( "{}( ", inst_name ); for ( auto i = 0u; i < args.size(); ++i ) { _os << fmt::format( ".{} ({})", args.at( i ).first, args.at( i ).second ); @@ -685,7 +689,7 @@ class verilog_writer * \param ins List of input signals * \param op Operator */ - virtual void on_assign( std::string const& out, std::vector> const& ins, std::string const& op ) const + virtual void on_assign( std::string const& out, std::vector> const& ins, std::string const& op ) const { std::string args; @@ -705,7 +709,7 @@ class verilog_writer * \param out Output signal * \param ins List of three input signals */ - virtual void on_assign_maj3( std::string const& out, std::vector> const& ins ) const + virtual void on_assign_maj3( std::string const& out, std::vector> const& ins ) const { assert( ins.size() == 3u ); _os << fmt::format( " assign {0} = ( {1}{2} & {3}{4} ) | ( {1}{2} & {5}{6} ) | ( {3}{4} & {5}{6} ) ;\n", @@ -729,7 +733,7 @@ class verilog_writer * \param out Output signal * \param in An input signal */ - virtual void on_assign_po( std::string const& out, std::pair const& in ) const + virtual void on_assign_po( std::string const& out, std::pair const& in ) const { _os << fmt::format( " assign {} = {}{} ;\n", out, @@ -738,7 +742,7 @@ class verilog_writer protected: std::ostream& _os; /*!< Output stream */ -}; /* verilog_writer */ +}; /* verilog_writer */ /*! \brief Simple parser for VERILOG format. * @@ -761,71 +765,86 @@ class verilog_parser * \param reader A verilog reader * \param diag A diagnostic engine */ - verilog_parser( std::istream& in, const verilog_reader& reader, diagnostic_engine* diag = nullptr ) + verilog_parser( std::istream& in, + const verilog_reader& reader, + diagnostic_engine* diag = nullptr ) : tok( in ) , reader( reader ) , diag( diag ) - , on_action([&]( std::vector> inputs, std::string output, std::string type ){ - if ( type == "assign" ) - { - assert( inputs.size() == 1u ); - reader.on_assign( output, inputs[0] ); - } - else if ( type == "and2" ) - { - assert( inputs.size() == 2u ); - reader.on_and( output, inputs[0], inputs[1] ); - } - else if ( type == "nand2" ) - { - assert( inputs.size() == 2u ); - reader.on_nand( output, inputs[0], inputs[1] ); - } - else if ( type == "or2" ) - { - assert( inputs.size() == 2u ); - reader.on_or( output, inputs[0], inputs[1] ); - } - else if ( type == "nor2" ) - { - assert( inputs.size() == 2u ); - reader.on_nor( output, inputs[0], inputs[1] ); - } - else if ( type == "xor2" ) - { - assert( inputs.size() == 2u ); - reader.on_xor( output, inputs[0], inputs[1] ); - } - else if ( type == "xnor2" ) - { - assert( inputs.size() == 2u ); - reader.on_xnor( output, inputs[0], inputs[1] ); - } - else if ( type == "and3" ) - { - assert( inputs.size() == 3u ); - reader.on_and3( output, inputs[0], inputs[1], inputs[2] ); - } - else if ( type == "or3" ) - { - assert( inputs.size() == 3u ); - reader.on_or3( output, inputs[0], inputs[1], inputs[2] ); - } - else if ( type == "xor3" ) - { - assert( inputs.size() == 3u ); - reader.on_xor3( output, inputs[0], inputs[1], inputs[2] ); - } - else if ( type == "maj3" ) - { - assert( inputs.size() == 3u ); - reader.on_maj3( output, inputs[0], inputs[1], inputs[2] ); - } - else - { - assert( false ); - } - }) + , on_action( PackedFns( GateFn( [&]( const std::vector>& inputs, + const std::string output, + const std::string type ) + { + if ( type == "assign" ) + { + assert( inputs.size() == 1u ); + reader.on_assign( output, inputs[0] ); + } + else if ( type == "and2" ) + { + assert( inputs.size() == 2u ); + reader.on_and( output, inputs[0], inputs[1] ); + } + else if ( type == "nand2" ) + { + assert( inputs.size() == 2u ); + reader.on_nand( output, inputs[0], inputs[1] ); + } + else if ( type == "or2" ) + { + assert( inputs.size() == 2u ); + reader.on_or( output, inputs[0], inputs[1] ); + } + else if ( type == "nor2" ) + { + assert( inputs.size() == 2u ); + reader.on_nor( output, inputs[0], inputs[1] ); + } + else if ( type == "xor2" ) + { + assert( inputs.size() == 2u ); + reader.on_xor( output, inputs[0], inputs[1] ); + } + else if ( type == "xnor2" ) + { + assert( inputs.size() == 2u ); + reader.on_xnor( output, inputs[0], inputs[1] ); + } + else if ( type == "and3" ) + { + assert( inputs.size() == 3u ); + reader.on_and3( output, inputs[0], inputs[1], inputs[2] ); + } + else if ( type == "or3" ) + { + assert( inputs.size() == 3u ); + reader.on_or3( output, inputs[0], inputs[1], inputs[2] ); + } + else if ( type == "xor3" ) + { + assert( inputs.size() == 3u ); + reader.on_xor3( output, inputs[0], inputs[1], inputs[2] ); + } + else if ( type == "maj3" ) + { + assert( inputs.size() == 3u ); + reader.on_maj3( output, inputs[0], inputs[1], inputs[2] ); + } + else + { + assert( false && "unknown gate function" ); + std::cerr << "unknown gate function" << std::endl; + std::abort(); + } + } ), + ModuleInstFn( [&]( const std::string module_name, + const std::vector& params, + const std::string instance_name, + const std::vector>& pin_to_pin ) + { + reader.on_module_instantiation( module_name, params, instance_name, pin_to_pin ); + } ) + ) ) { on_action.declare_known( "0" ); on_action.declare_known( "1" ); @@ -860,7 +879,7 @@ class verilog_parser reader.on_comment( token ); } /* keep parsing if token is empty or if in the middle or at the end of a comment */ - } while ( (token == "" && result == detail::tokenizer_return_code::valid) || + } while ( ( token == "" && result == detail::tokenizer_return_code::valid ) || tok.get_comment_mode() || result == detail::tokenizer_return_code::comment ); @@ -875,18 +894,21 @@ class verilog_parser bool parse_signal_name() { valid = get_token( token ); // name - if ( !valid || token == "[" ) return false; + if ( !valid || token == "[" ) + return false; auto const name = token; valid = get_token( token ); if ( token == "[" ) { valid = get_token( token ); // size - if ( !valid ) return false; + if ( !valid ) + return false; auto const size = token; valid = get_token( token ); // size - if ( !valid && token != "]" ) return false; + if ( !valid && token != "]" ) + return false; token = name + "[" + size + "]"; return true; @@ -930,7 +952,8 @@ class verilog_parser do { valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; if ( token == "input" ) { @@ -1001,7 +1024,8 @@ class verilog_parser } valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; } else { @@ -1016,7 +1040,8 @@ class verilog_parser } valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; } } @@ -1031,8 +1056,8 @@ class verilog_parser if ( diag ) { diag->report( diag_id::WRN_UNRESOLVED_DEPENDENCY ) - .add_argument( r.first ) - .add_argument( r.second ); + .add_argument( r.first ) + .add_argument( r.second ); } } @@ -1054,15 +1079,18 @@ class verilog_parser bool parse_module_header() { - if ( token != "module" ) return false; + if ( token != "module" ) + return false; valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; module_name = token; valid = get_token( token ); - if ( !valid || token != "(" ) return false; + if ( !valid || token != "(" ) + return false; std::vector inouts; do @@ -1072,11 +1100,13 @@ class verilog_parser inouts.emplace_back( token ); valid = get_token( token ); // , or ) - if ( !valid || (token != "," && token != ")") ) return false; + if ( !valid || ( token != "," && token != ")" ) ) + return false; } while ( valid && token != ")" ); valid = get_token( token ); - if ( !valid || token != ";" ) return false; + if ( !valid || token != ";" ) + return false; /* callback */ reader.on_module_header( module_name, inouts ); @@ -1087,7 +1117,8 @@ class verilog_parser bool parse_inputs() { std::vector inputs; - if ( token != "input" ) return false; + if ( token != "input" ) + return false; std::string size = ""; if ( !parse_signal_name() && token == "[" ) @@ -1095,7 +1126,8 @@ class verilog_parser do { valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; if ( token != "]" ) size += token; @@ -1110,7 +1142,8 @@ class verilog_parser { valid = get_token( token ); - if ( !valid || (token != "," && token != ";") ) return false; + if ( !valid || ( token != "," && token != ";" ) ) + return false; if ( token == ";" ) break; @@ -1126,15 +1159,21 @@ class verilog_parser modules[module_name].inputs = inputs; for ( const auto& i : inputs ) + { on_action.declare_known( i ); + } if ( std::smatch m; std::regex_match( size, m, verilog_regex::const_size_range ) ) { const auto a = std::stoul( m[1].str() ); const auto b = std::stoul( m[2].str() ); for ( auto j = std::min( a, b ); j <= std::max( a, b ); ++j ) + { for ( const auto& i : inputs ) + { on_action.declare_known( fmt::format( "{}[{}]", i, j ) ); + } + } } return true; @@ -1143,7 +1182,8 @@ class verilog_parser bool parse_outputs() { std::vector outputs; - if ( token != "output" ) return false; + if ( token != "output" ) + return false; std::string size = ""; if ( !parse_signal_name() && token == "[" ) @@ -1151,7 +1191,8 @@ class verilog_parser do { valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; if ( token != "]" ) size += token; @@ -1166,7 +1207,8 @@ class verilog_parser { valid = get_token( token ); - if ( !valid || (token != "," && token != ";") ) return false; + if ( !valid || ( token != "," && token != ";" ) ) + return false; if ( token == ";" ) break; @@ -1187,7 +1229,8 @@ class verilog_parser bool parse_wires() { std::vector wires; - if ( token != "wire" ) return false; + if ( token != "wire" ) + return false; std::string size = ""; if ( !parse_signal_name() && token == "[" ) @@ -1195,7 +1238,8 @@ class verilog_parser do { valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; if ( token != "]" ) size += token; @@ -1210,7 +1254,8 @@ class verilog_parser { valid = get_token( token ); - if ( !valid || (token != "," && token != ";") ) return false; + if ( !valid || ( token != "," && token != ";" ) ) + return false; if ( token == ";" ) break; @@ -1229,21 +1274,26 @@ class verilog_parser bool parse_parameter() { - if ( token != "parameter" ) return false; + if ( token != "parameter" ) + return false; valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; auto const name = token; valid = get_token( token ); - if ( !valid || (token != "=" ) ) return false; + if ( !valid || ( token != "=" ) ) + return false; valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; auto const value = token; valid = get_token( token ); - if ( !valid || (token != ";") ) return false; + if ( !valid || ( token != ";" ) ) + return false; /* callback */ reader.on_parameter( name, value ); @@ -1253,14 +1303,16 @@ class verilog_parser bool parse_assign() { - if ( token != "assign" ) return false; + if ( token != "assign" ) + return false; if ( !parse_signal_name() ) return false; const std::string lhs = token; valid = get_token( token ); - if ( !valid || token != "=" ) return false; + if ( !valid || token != "=" ) + return false; /* expression */ bool success = parse_rhs_expression( lhs ); @@ -1269,12 +1321,13 @@ class verilog_parser if ( diag ) { diag->report( diag_id::ERR_VERILOG_ASSIGNMENT_RHS ) - .add_argument( lhs ); + .add_argument( lhs ); } return false; } - if ( token != ";" ) return false; + if ( token != ";" ) + return false; return true; } @@ -1289,7 +1342,7 @@ class verilog_parser if ( diag ) { diag->report( diag_id::ERR_VERILOG_MODULE_INSTANTIATION_UNDECLARED_MODULE ) - .add_argument( module_name ); + .add_argument( module_name ); } return false; } @@ -1298,41 +1351,49 @@ class verilog_parser auto const& info = modules[module_name]; valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; std::vector params; if ( token == "#" ) { - valid = get_token( token ); // ( - if ( !valid || token != "(" ) return false; + valid = get_token( token ); // ( + if ( !valid || token != "(" ) + return false; do { valid = get_token( token ); // param - if ( !valid ) return false; + if ( !valid ) + return false; params.emplace_back( token ); valid = get_token( token ); // , - if ( !valid ) return false; + if ( !valid ) + return false; } while ( valid && token == "," ); - if ( !valid || token != ")" ) return false; + if ( !valid || token != ")" ) + return false; valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; } std::string const inst_name = token; // name of instantiation valid = get_token( token ); - if ( !valid || token != "(" ) return false; + if ( !valid || token != "(" ) + return false; - std::vector> args; + std::vector> args; do { valid = get_token( token ); - if ( !valid ) return false; // refers to signal + if ( !valid ) + return false; // refers to signal std::string const arg0{token}; /* check if a signal with this name exists in the module declaration */ @@ -1342,40 +1403,67 @@ class verilog_parser if ( diag ) { diag->report( diag_id::ERR_VERILOG_MODULE_INSTANTIATION_UNDECLARED_PIN ) - .add_argument( arg0.substr( 1, arg0.size() ) ) - .add_argument( module_name ); + .add_argument( arg0.substr( 1, arg0.size() ) ) + .add_argument( module_name ); } success = false; } valid = get_token( token ); - if ( !valid || token != "(" ) return false; // ( + if ( !valid || token != "(" ) + return false; // ( valid = get_token( token ); - if ( !valid ) return false; // signal name + if ( !valid ) + return false; // signal name auto const arg1 = token; valid = get_token( token ); - if ( !valid || token != ")" ) return false; // ) + if ( !valid || token != ")" ) + return false; // ) valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; args.emplace_back( std::make_pair( arg0, arg1 ) ); - if ( std::find( std::begin( info.outputs ), std::end( info.outputs ), arg0 ) == std::end( info.outputs ) ) - { - on_action.declare_known( arg1 ); - } } while ( token == "," ); - if ( !valid || token != ")" ) return false; + if ( !valid || token != ")" ) + return false; valid = get_token( token ); - if ( !valid || token != ";" ) return false; + if ( !valid || token != ";" ) + return false; + + std::vector inputs; + for ( const auto& input : modules[module_name].inputs ) + { + for ( const auto& a : args ) + { + if ( a.first.substr( 1, a.first.length() - 1 ) == input ) + { + inputs.emplace_back( a.second ); + } + } + } + + std::vector outputs; + for ( const auto& output : modules[module_name].outputs ) + { + for ( const auto& a : args ) + { + if ( a.first.substr( 1, a.first.length() - 1 ) == output ) + { + outputs.emplace_back( a.second ); + } + } + } /* callback */ - reader.on_module_instantiation( module_name, params, inst_name, args ); + on_action.call_deferred( inputs, outputs, + std::make_tuple( module_name, params, inst_name, args ) ); return success; } @@ -1386,9 +1474,11 @@ class verilog_parser do { valid = get_token( token ); - if ( !valid ) return false; + if ( !valid ) + return false; - if ( token == ";" || token == "assign" || token == "endmodule" ) break; + if ( token == ";" || token == "assign" || token == "endmodule" ) + break; s.append( token ); } while ( token != ";" && token != "assign" && token != "endmodule" ); @@ -1396,26 +1486,38 @@ class verilog_parser if ( std::regex_match( s, sm, verilog_regex::immediate_assign ) ) { assert( sm.size() == 3u ); - on_action.call_deferred( { sm[2] }, lhs, {{sm[2], sm[1] == "~"}}, lhs, "assign" ); + std::vector> args{{sm[2], sm[1] == "~"}}; + + on_action.call_deferred( /* dependencies */ { sm[2] }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "assign" ) + ); } else if ( std::regex_match( s, sm, verilog_regex::binary_expression ) ) { assert( sm.size() == 6u ); - std::pair arg0 = {sm[2], sm[1] == "~"}; - std::pair arg1 = {sm[5], sm[4] == "~"}; + std::pair arg0 = {sm[2], sm[1] == "~"}; + std::pair arg1 = {sm[5], sm[4] == "~"}; + std::vector> args{arg0, arg1}; + auto op = sm[3]; if ( op == "&" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "and2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "and2" ) + ); } else if ( op == "|" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "or2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "or2" ) + ); } else if ( op == "^" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "xor2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "xor2" ) + ); } else { @@ -1425,20 +1527,28 @@ class verilog_parser else if ( std::regex_match( s, sm, verilog_regex::negated_binary_expression ) ) { assert( sm.size() == 6u ); - std::pair arg0 = {sm[2], sm[1] == "~"}; - std::pair arg1 = {sm[5], sm[4] == "~"}; + std::pair arg0 = {sm[2], sm[1] == "~"}; + std::pair arg1 = {sm[5], sm[4] == "~"}; + std::vector> args{arg0, arg1}; + auto op = sm[3]; if ( op == "&" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "nand2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "nand2" ) + ); } else if ( op == "|" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "nor2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "nor2" ) + ); } else if ( op == "^" ) { - on_action.call_deferred( { arg0.first, arg1.first }, lhs, {arg0, arg1}, lhs, "xnor2" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "xnor2" ) + ); } else { @@ -1448,9 +1558,11 @@ class verilog_parser else if ( std::regex_match( s, sm, verilog_regex::ternary_expression ) ) { assert( sm.size() == 9u ); - std::pair arg0 = {sm[2], sm[1] == "~"}; - std::pair arg1 = {sm[5], sm[4] == "~"}; - std::pair arg2 = {sm[8], sm[7] == "~"}; + std::pair arg0 = {sm[2], sm[1] == "~"}; + std::pair arg1 = {sm[5], sm[4] == "~"}; + std::pair arg2 = {sm[8], sm[7] == "~"}; + std::vector> args{arg0, arg1, arg2}; + auto op = sm[3]; if ( sm[6] != op ) { @@ -1459,15 +1571,21 @@ class verilog_parser if ( op == "&" ) { - on_action.call_deferred( { arg0.first, arg1.first, arg2.first }, lhs, {arg0, arg1, arg2}, lhs, "and3" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first, arg2.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "and3" ) + ); } else if ( op == "|" ) { - on_action.call_deferred( { arg0.first, arg1.first, arg2.first }, lhs, {arg0, arg1, arg2}, lhs, "or3" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first, arg2.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "or3" ) + ); } else if ( op == "^" ) { - on_action.call_deferred( { arg0.first, arg1.first, arg2.first }, lhs, {arg0, arg1, arg2}, lhs, "xor3" ); + on_action.call_deferred( /* dependencies */ { arg0.first, arg1.first, arg2.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "xor3" ) + ); } else { @@ -1477,21 +1595,24 @@ class verilog_parser else if ( std::regex_match( s, sm, verilog_regex::maj3_expression ) ) { assert( sm.size() == 13u ); - std::pair a0 = {sm[2], sm[1] == "~"}; - std::pair b0 = {sm[4], sm[3] == "~"}; - std::pair a1 = {sm[6], sm[5] == "~"}; - std::pair c0 = {sm[8], sm[7] == "~"}; - std::pair b1 = {sm[10], sm[9] == "~"}; - std::pair c1 = {sm[12], sm[11] == "~"}; - - if ( a0 != a1 || b0 != b1 || c0 != c1 ) return false; + std::pair a0 = {sm[2], sm[1] == "~"}; + std::pair b0 = {sm[4], sm[3] == "~"}; + std::pair a1 = {sm[6], sm[5] == "~"}; + std::pair c0 = {sm[8], sm[7] == "~"}; + std::pair b1 = {sm[10], sm[9] == "~"}; + std::pair c1 = {sm[12], sm[11] == "~"}; + + if ( a0 != a1 || b0 != b1 || c0 != c1 ) + return false; - std::vector> args; + std::vector> args; args.push_back( a0 ); args.push_back( b0 ); args.push_back( c0 ); - on_action.call_deferred( { a0.first, b0.first, c0.first }, lhs, args, lhs, "maj3" ); + on_action.call_deferred( /* dependencies */ { a0.first, b0.first, c0.first }, { lhs }, + /* gate-function params */ std::make_tuple( args, lhs, "maj3" ) + ); } else { @@ -1501,6 +1622,45 @@ class verilog_parser return true; } +private: + /* Function signatures */ + using GateFn = detail::Func< + std::vector>, + std::string, + std::string + >; + using ModuleInstFn = detail::Func< + std::string, + std::vector, + std::string, + std::vector> + >; + + /* Parameter maps */ + using GateParamMap = detail::ParamPackMap< + /* Key */ + std::string, + /* Params */ + std::vector>, + std::string, + std::string + >; + using ModuleInstParamMap = detail::ParamPackMap< + /* Key */ + std::string, + /* Param */ + std::string, + std::vector, + std::string, + std::vector> + >; + + constexpr static const int GATE_FN{0}; + constexpr static const int MODULE_INST_FN{1}; + + using ParamMaps = detail::ParamPackMapN; + using PackedFns = detail::FuncPackN; + private: detail::tokenizer tok; const verilog_reader& reader; @@ -1512,7 +1672,7 @@ class verilog_parser bool valid = false; - detail::call_in_topological_order>, std::string, std::string> on_action; + detail::call_in_topological_order on_action; std::unordered_map modules; }; /* verilog_parser */ diff --git a/test/io/write_verilog.cpp b/test/io/write_verilog.cpp index efbe79247..961f36d32 100644 --- a/test/io/write_verilog.cpp +++ b/test/io/write_verilog.cpp @@ -164,10 +164,10 @@ TEST_CASE( "write buffered AIG into Verilog file", "[write_verilog]" ) " input x0 , x1 ;\n" " output y0 ;\n" " wire n3 , n4 , n5 , n6 ;\n" - " buffer buf_n3( .i (x0), .o (n3) );\n" - " buffer buf_n4( .i (n3), .o (n4) );\n" + " buffer buf_n3( .i (x0), .o (n3) );\n" + " buffer buf_n4( .i (n3), .o (n4) );\n" " assign n5 = ~x1 & ~n4 ;\n" - " inverter inv_n6( .i (n5), .o (n6) );\n" + " inverter inv_n6( .i (n5), .o (n6) );\n" " assign y0 = n6 ;\n" "endmodule\n" ); } @@ -217,10 +217,10 @@ TEST_CASE( "write mapped network into Verilog file", "[write_verilog]" ) CHECK( out.str() == "module top( x0 , x1 , x2 , y0 , y1 , y2 , y3 );\n" " input x0 , x1 , x2 ;\n" " output y0 , y1 , y2 , y3 ;\n" - " zero g0( .O (y0) );\n" - " buf g1( .a (x0), .O (y1) );\n" - " nand2 g2( .a (x1), .b (x2), .O (y2) );\n" - " inv2 g3( .a (y2), .O (y3) );\n" + " zero g0( .O (y0) );\n" + " buf g1( .a (x0), .O (y1) );\n" + " nand2 g2( .a (x1), .b (x2), .O (y2) );\n" + " inv2 g3( .a (y2), .O (y3) );\n" "endmodule\n" ); } @@ -271,9 +271,9 @@ TEST_CASE( "write mapped network with multiple driven POs and register names int " input [0:0] ref ;\n" " input [1:0] data ;\n" " output [3:0] y ;\n" - " buf g0( .a (ref[0]), .Y (y[0]) );\n" - " nand2 g1( .a (data[0]), .b (data[1]), .Y (y[1]) );\n" - " nand2 g2( .a (data[0]), .b (data[1]), .Y (y[2]) );\n" - " inv2 g3( .a (y[1]), .Y (y[3]) );\n" + " buf g0( .a (ref[0]), .Y (y[0]) );\n" + " nand2 g1( .a (data[0]), .b (data[1]), .Y (y[1]) );\n" + " nand2 g2( .a (data[0]), .b (data[1]), .Y (y[2]) );\n" + " inv2 g3( .a (y[1]), .Y (y[3]) );\n" "endmodule\n" ); }