2015-01-19 08:08:44 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2015-07-02 04:14:30 -05:00
*
2015-01-19 08:08:44 -06:00
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
2015-07-02 04:14:30 -05:00
*
2015-01-19 08:08:44 -06:00
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
*/
# include "kernel/yosys.h"
# include "kernel/satgen.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct EquivSimpleWorker
{
Module * module ;
2015-02-01 15:41:03 -06:00
const vector < Cell * > & equiv_cells ;
2015-01-19 08:08:44 -06:00
Cell * equiv_cell ;
SigMap & sigmap ;
dict < SigBit , Cell * > & bit2driver ;
2015-02-21 05:15:41 -06:00
ezSatPtr ez ;
2015-01-19 08:08:44 -06:00
SatGen satgen ;
2015-01-21 17:59:58 -06:00
int max_seq ;
2017-04-28 11:54:53 -05:00
bool short_cones ;
2015-01-22 06:40:26 -06:00
bool verbose ;
2015-01-19 08:08:44 -06:00
2015-02-01 15:41:03 -06:00
pool < pair < Cell * , int > > imported_cells_cache ;
2017-04-28 11:54:53 -05:00
EquivSimpleWorker ( const vector < Cell * > & equiv_cells , SigMap & sigmap , dict < SigBit , Cell * > & bit2driver , int max_seq , bool short_cones , bool verbose , bool model_undef ) :
2015-02-01 15:41:03 -06:00
module ( equiv_cells . front ( ) - > module ) , equiv_cells ( equiv_cells ) , equiv_cell ( nullptr ) ,
2017-04-28 11:54:53 -05:00
sigmap ( sigmap ) , bit2driver ( bit2driver ) , satgen ( ez . get ( ) , & sigmap ) , max_seq ( max_seq ) , short_cones ( short_cones ) , verbose ( verbose )
2015-01-19 08:08:44 -06:00
{
2015-01-31 06:06:41 -06:00
satgen . model_undef = model_undef ;
2015-01-19 08:08:44 -06:00
}
2015-01-31 06:06:41 -06:00
bool find_input_cone ( pool < SigBit > & next_seed , pool < Cell * > & cells_cone , pool < SigBit > & bits_cone , const pool < Cell * > & cells_stop , const pool < SigBit > & bits_stop , pool < SigBit > * input_bits , Cell * cell )
2015-01-19 08:08:44 -06:00
{
if ( cells_cone . count ( cell ) )
2015-01-31 06:06:41 -06:00
return false ;
2015-01-19 08:08:44 -06:00
cells_cone . insert ( cell ) ;
if ( cells_stop . count ( cell ) )
2015-01-31 06:06:41 -06:00
return true ;
2015-01-19 08:08:44 -06:00
for ( auto & conn : cell - > connections ( ) )
if ( yosys_celltypes . cell_input ( cell - > type , conn . first ) )
2015-01-21 17:59:58 -06:00
for ( auto bit : sigmap ( conn . second ) ) {
2020-04-02 11:51:32 -05:00
if ( cell - > type . in ( ID ( $ dff ) , ID ( $ _DFF_P_ ) , ID ( $ _DFF_N_ ) , ID ( $ ff ) , ID ( $ _FF_ ) ) ) {
if ( ! conn . first . in ( ID : : CLK , ID : : C ) )
2015-01-21 17:59:58 -06:00
next_seed . insert ( bit ) ;
} else
2015-01-31 06:06:41 -06:00
find_input_cone ( next_seed , cells_cone , bits_cone , cells_stop , bits_stop , input_bits , bit ) ;
2015-01-21 17:59:58 -06:00
}
2015-01-31 06:06:41 -06:00
return false ;
2015-01-19 08:08:44 -06:00
}
2015-01-31 06:06:41 -06:00
void find_input_cone ( pool < SigBit > & next_seed , pool < Cell * > & cells_cone , pool < SigBit > & bits_cone , const pool < Cell * > & cells_stop , const pool < SigBit > & bits_stop , pool < SigBit > * input_bits , SigBit bit )
2015-01-19 08:08:44 -06:00
{
if ( bits_cone . count ( bit ) )
return ;
bits_cone . insert ( bit ) ;
2015-01-31 06:06:41 -06:00
if ( bits_stop . count ( bit ) ) {
if ( input_bits ! = nullptr ) input_bits - > insert ( bit ) ;
2015-01-19 08:08:44 -06:00
return ;
2015-01-31 06:06:41 -06:00
}
2015-01-19 08:08:44 -06:00
if ( ! bit2driver . count ( bit ) )
return ;
2015-01-31 06:06:41 -06:00
if ( find_input_cone ( next_seed , cells_cone , bits_cone , cells_stop , bits_stop , input_bits , bit2driver . at ( bit ) ) )
if ( input_bits ! = nullptr ) input_bits - > insert ( bit ) ;
2015-01-19 08:08:44 -06:00
}
2015-02-01 15:41:03 -06:00
bool run_cell ( )
2015-01-19 08:08:44 -06:00
{
2020-03-12 14:57:01 -05:00
SigBit bit_a = sigmap ( equiv_cell - > getPort ( ID : : A ) ) . as_bit ( ) ;
SigBit bit_b = sigmap ( equiv_cell - > getPort ( ID : : B ) ) . as_bit ( ) ;
2015-02-21 05:15:41 -06:00
int ez_context = ez - > frozen_literal ( ) ;
2015-01-19 08:08:44 -06:00
2015-01-31 06:06:41 -06:00
if ( satgen . model_undef )
{
int ez_a = satgen . importSigBit ( bit_a , max_seq + 1 ) ;
int ez_b = satgen . importDefSigBit ( bit_b , max_seq + 1 ) ;
int ez_undef_a = satgen . importUndefSigBit ( bit_a , max_seq + 1 ) ;
2015-02-21 05:15:41 -06:00
ez - > assume ( ez - > XOR ( ez_a , ez_b ) , ez_context ) ;
ez - > assume ( ez - > NOT ( ez_undef_a ) , ez_context ) ;
2015-01-31 06:06:41 -06:00
}
else
{
int ez_a = satgen . importSigBit ( bit_a , max_seq + 1 ) ;
int ez_b = satgen . importSigBit ( bit_b , max_seq + 1 ) ;
2015-02-21 05:15:41 -06:00
ez - > assume ( ez - > XOR ( ez_a , ez_b ) , ez_context ) ;
2015-01-31 06:06:41 -06:00
}
2015-01-21 17:59:58 -06:00
pool < SigBit > seed_a = { bit_a } ;
pool < SigBit > seed_b = { bit_b } ;
2015-01-22 06:40:26 -06:00
if ( verbose ) {
log ( " Trying to prove $equiv cell %s: \n " , log_id ( equiv_cell ) ) ;
2020-03-12 14:57:01 -05:00
log ( " A = %s, B = %s, Y = %s \n " , log_signal ( bit_a ) , log_signal ( bit_b ) , log_signal ( equiv_cell - > getPort ( ID : : Y ) ) ) ;
2015-01-22 06:40:26 -06:00
} else {
2020-03-12 14:57:01 -05:00
log ( " Trying to prove $equiv for %s: " , log_signal ( equiv_cell - > getPort ( ID : : Y ) ) ) ;
2015-01-22 06:40:26 -06:00
}
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
int step = max_seq ;
while ( 1 )
{
pool < Cell * > no_stop_cells ;
pool < SigBit > no_stop_bits ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
pool < Cell * > full_cells_cone_a , full_cells_cone_b ;
pool < SigBit > full_bits_cone_a , full_bits_cone_b ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
pool < SigBit > next_seed_a , next_seed_b ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
for ( auto bit_a : seed_a )
2015-01-31 06:06:41 -06:00
find_input_cone ( next_seed_a , full_cells_cone_a , full_bits_cone_a , no_stop_cells , no_stop_bits , nullptr , bit_a ) ;
2015-01-21 17:59:58 -06:00
next_seed_a . clear ( ) ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
for ( auto bit_b : seed_b )
2015-01-31 06:06:41 -06:00
find_input_cone ( next_seed_b , full_cells_cone_b , full_bits_cone_b , no_stop_cells , no_stop_bits , nullptr , bit_b ) ;
2015-01-21 17:59:58 -06:00
next_seed_b . clear ( ) ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
pool < Cell * > short_cells_cone_a , short_cells_cone_b ;
pool < SigBit > short_bits_cone_a , short_bits_cone_b ;
2015-01-31 06:06:41 -06:00
pool < SigBit > input_bits ;
2015-01-19 08:08:44 -06:00
2017-04-28 11:54:53 -05:00
if ( short_cones )
{
for ( auto bit_a : seed_a )
find_input_cone ( next_seed_a , short_cells_cone_a , short_bits_cone_a , full_cells_cone_b , full_bits_cone_b , & input_bits , bit_a ) ;
next_seed_a . swap ( seed_a ) ;
2015-01-21 17:59:58 -06:00
2017-04-28 11:54:53 -05:00
for ( auto bit_b : seed_b )
find_input_cone ( next_seed_b , short_cells_cone_b , short_bits_cone_b , full_cells_cone_a , full_bits_cone_a , & input_bits , bit_b ) ;
next_seed_b . swap ( seed_b ) ;
}
else
{
short_cells_cone_a = full_cells_cone_a ;
short_bits_cone_a = full_bits_cone_a ;
next_seed_a . swap ( seed_a ) ;
short_cells_cone_b = full_cells_cone_b ;
short_bits_cone_b = full_bits_cone_b ;
next_seed_b . swap ( seed_b ) ;
}
2015-01-21 17:59:58 -06:00
pool < Cell * > problem_cells ;
problem_cells . insert ( short_cells_cone_a . begin ( ) , short_cells_cone_a . end ( ) ) ;
problem_cells . insert ( short_cells_cone_b . begin ( ) , short_cells_cone_b . end ( ) ) ;
2015-01-22 06:40:26 -06:00
if ( verbose )
2017-04-28 11:54:53 -05:00
{
2015-01-22 06:40:26 -06:00
log ( " Adding %d new cells to the problem (%d A, %d B, %d shared). \n " ,
GetSize ( problem_cells ) , GetSize ( short_cells_cone_a ) , GetSize ( short_cells_cone_b ) ,
( GetSize ( short_cells_cone_a ) + GetSize ( short_cells_cone_b ) ) - GetSize ( problem_cells ) ) ;
2017-04-28 11:54:53 -05:00
#if 0
for ( auto cell : short_cells_cone_a )
log ( " A-side cell: %s \n " , log_id ( cell ) ) ;
for ( auto cell : short_cells_cone_b )
log ( " B-side cell: %s \n " , log_id ( cell ) ) ;
# endif
}
2015-01-21 17:59:58 -06:00
2015-02-01 15:41:03 -06:00
for ( auto cell : problem_cells ) {
auto key = pair < Cell * , int > ( cell , step + 1 ) ;
2021-03-29 21:00:45 -05:00
if ( ! imported_cells_cache . count ( key ) & & ! satgen . importCell ( cell , step + 1 ) ) {
if ( RTLIL : : builtin_ff_cell_types ( ) . count ( cell - > type ) )
log_cmd_error ( " No SAT model available for async FF cell %s (%s). Consider running `async2sync` or `clk2fflogic` first. \n " , log_id ( cell ) , log_id ( cell - > type ) ) ;
else
log_cmd_error ( " No SAT model available for cell %s (%s). \n " , log_id ( cell ) , log_id ( cell - > type ) ) ;
}
2015-02-01 15:41:03 -06:00
imported_cells_cache . insert ( key ) ;
}
2015-01-21 17:59:58 -06:00
2015-01-31 06:06:41 -06:00
if ( satgen . model_undef ) {
for ( auto bit : input_bits )
2015-02-21 05:15:41 -06:00
ez - > assume ( ez - > NOT ( satgen . importUndefSigBit ( bit , step + 1 ) ) ) ;
2015-01-31 06:06:41 -06:00
}
2015-01-22 06:40:26 -06:00
if ( verbose )
2015-02-21 05:15:41 -06:00
log ( " Problem size at t=%d: %d literals, %d clauses \n " , step , ez - > numCnfVariables ( ) , ez - > numCnfClauses ( ) ) ;
2015-01-21 17:59:58 -06:00
2015-02-21 05:15:41 -06:00
if ( ! ez - > solve ( ez_context ) ) {
2015-01-22 06:40:26 -06:00
log ( verbose ? " Proved equivalence! Marking $equiv cell as proven. \n " : " success! \n " ) ;
2020-03-12 14:57:01 -05:00
equiv_cell - > setPort ( ID : : B , equiv_cell - > getPort ( ID : : A ) ) ;
2015-02-21 05:15:41 -06:00
ez - > assume ( ez - > NOT ( ez_context ) ) ;
2015-01-21 17:59:58 -06:00
return true ;
}
2015-01-19 08:08:44 -06:00
2015-01-22 06:40:26 -06:00
if ( verbose )
log ( " Failed to prove equivalence with sequence length %d. \n " , max_seq - step ) ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
if ( - - step < 0 ) {
2015-01-22 06:40:26 -06:00
if ( verbose )
log ( " Reached sequence limit. \n " ) ;
2015-01-21 17:59:58 -06:00
break ;
}
if ( seed_a . empty ( ) & & seed_b . empty ( ) ) {
2015-01-22 06:40:26 -06:00
if ( verbose )
log ( " No nets to continue in previous time step. \n " ) ;
2015-01-21 17:59:58 -06:00
break ;
}
if ( seed_a . empty ( ) ) {
2015-01-22 06:40:26 -06:00
if ( verbose )
log ( " No nets on A-side to continue in previous time step. \n " ) ;
2015-01-21 17:59:58 -06:00
break ;
}
if ( seed_b . empty ( ) ) {
2015-01-22 06:40:26 -06:00
if ( verbose )
log ( " No nets on B-side to continue in previous time step. \n " ) ;
2015-01-21 17:59:58 -06:00
break ;
}
2015-01-22 06:40:26 -06:00
if ( verbose ) {
#if 0
log ( " Continuing analysis in previous time step with the following nets: \n " ) ;
for ( auto bit : seed_a )
log ( " A: %s \n " , log_signal ( bit ) ) ;
for ( auto bit : seed_b )
log ( " B: %s \n " , log_signal ( bit ) ) ;
# else
log ( " Continuing analysis in previous time step with %d A- and %d B-nets. \n " , GetSize ( seed_a ) , GetSize ( seed_b ) ) ;
# endif
}
2015-01-19 08:08:44 -06:00
}
2015-01-22 06:40:26 -06:00
if ( ! verbose )
log ( " failed. \n " ) ;
2015-02-01 15:41:03 -06:00
2015-02-21 05:15:41 -06:00
ez - > assume ( ez - > NOT ( ez_context ) ) ;
2015-01-19 08:08:44 -06:00
return false ;
}
2015-02-01 15:41:03 -06:00
int run ( )
{
if ( GetSize ( equiv_cells ) > 1 ) {
SigSpec sig ;
for ( auto c : equiv_cells )
2020-03-12 14:57:01 -05:00
sig . append ( sigmap ( c - > getPort ( ID : : Y ) ) ) ;
2015-02-01 15:41:03 -06:00
log ( " Grouping SAT models for %s: \n " , log_signal ( sig ) ) ;
}
int counter = 0 ;
for ( auto c : equiv_cells ) {
equiv_cell = c ;
if ( run_cell ( ) )
counter + + ;
}
return counter ;
}
2015-01-19 08:08:44 -06:00
} ;
struct EquivSimplePass : public Pass {
EquivSimplePass ( ) : Pass ( " equiv_simple " , " try proving simple $equiv instances " ) { }
2020-06-18 18:34:52 -05:00
void help ( ) override
2015-01-19 08:08:44 -06:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " equiv_simple [options] [selection] \n " ) ;
log ( " \n " ) ;
log ( " This command tries to prove $equiv cells using a simple direct SAT approach. \n " ) ;
log ( " \n " ) ;
2015-01-22 06:40:26 -06:00
log ( " -v \n " ) ;
log ( " verbose output \n " ) ;
log ( " \n " ) ;
2015-01-31 06:06:41 -06:00
log ( " -undef \n " ) ;
log ( " enable modelling of undef states \n " ) ;
log ( " \n " ) ;
2017-04-28 11:54:53 -05:00
log ( " -short \n " ) ;
log ( " create shorter input cones that stop at shared nodes. This yields \n " ) ;
log ( " simpler SAT problems but sometimes fails to prove equivalence. \n " ) ;
log ( " \n " ) ;
2015-02-01 15:41:03 -06:00
log ( " -nogroup \n " ) ;
log ( " disabling grouping of $equiv cells by output wire \n " ) ;
log ( " \n " ) ;
2015-01-21 17:59:58 -06:00
log ( " -seq <N> \n " ) ;
log ( " the max. number of time steps to be considered (default = 1) \n " ) ;
log ( " \n " ) ;
2015-01-19 08:08:44 -06:00
}
2020-06-18 18:34:52 -05:00
void execute ( std : : vector < std : : string > args , Design * design ) override
2015-01-19 08:08:44 -06:00
{
2017-04-28 11:54:53 -05:00
bool verbose = false , short_cones = false , model_undef = false , nogroup = false ;
2015-01-19 08:08:44 -06:00
int success_counter = 0 ;
2015-01-21 17:59:58 -06:00
int max_seq = 1 ;
2015-01-19 08:08:44 -06:00
2016-04-21 16:28:37 -05:00
log_header ( design , " Executing EQUIV_SIMPLE pass. \n " ) ;
2015-01-19 08:08:44 -06:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
2015-01-22 06:40:26 -06:00
if ( args [ argidx ] = = " -v " ) {
verbose = true ;
continue ;
}
2017-04-28 11:54:53 -05:00
if ( args [ argidx ] = = " -short " ) {
short_cones = true ;
continue ;
}
2015-01-31 06:06:41 -06:00
if ( args [ argidx ] = = " -undef " ) {
model_undef = true ;
continue ;
}
2015-02-01 15:41:03 -06:00
if ( args [ argidx ] = = " -nogroup " ) {
nogroup = true ;
continue ;
}
2015-01-21 17:59:58 -06:00
if ( args [ argidx ] = = " -seq " & & argidx + 1 < args . size ( ) ) {
max_seq = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2015-01-19 08:08:44 -06:00
break ;
}
extra_args ( args , argidx , design ) ;
CellTypes ct ;
ct . setup_internals ( ) ;
ct . setup_stdcells ( ) ;
for ( auto module : design - > selected_modules ( ) )
{
2015-02-01 15:41:03 -06:00
SigMap sigmap ( module ) ;
dict < SigBit , Cell * > bit2driver ;
dict < SigBit , dict < SigBit , Cell * > > unproven_equiv_cells ;
int unproven_cells_counter = 0 ;
2015-01-19 08:08:44 -06:00
for ( auto cell : module - > selected_cells ( ) )
2020-04-02 11:51:32 -05:00
if ( cell - > type = = ID ( $ equiv ) & & cell - > getPort ( ID : : A ) ! = cell - > getPort ( ID : : B ) ) {
2020-03-12 14:57:01 -05:00
auto bit = sigmap ( cell - > getPort ( ID : : Y ) . as_bit ( ) ) ;
2015-02-01 15:41:03 -06:00
auto bit_group = bit ;
if ( ! nogroup & & bit_group . wire )
bit_group . offset = 0 ;
unproven_equiv_cells [ bit_group ] [ bit ] = cell ;
unproven_cells_counter + + ;
}
2015-01-19 08:08:44 -06:00
if ( unproven_equiv_cells . empty ( ) )
continue ;
2015-02-01 15:41:03 -06:00
log ( " Found %d unproven $equiv cells (%d groups) in %s: \n " ,
unproven_cells_counter , GetSize ( unproven_equiv_cells ) , log_id ( module ) ) ;
2015-01-19 08:08:44 -06:00
2015-01-21 17:59:58 -06:00
for ( auto cell : module - > cells ( ) ) {
2020-04-02 11:51:32 -05:00
if ( ! ct . cell_known ( cell - > type ) & & ! cell - > type . in ( ID ( $ dff ) , ID ( $ _DFF_P_ ) , ID ( $ _DFF_N_ ) , ID ( $ ff ) , ID ( $ _FF_ ) ) )
2015-01-19 08:08:44 -06:00
continue ;
for ( auto & conn : cell - > connections ( ) )
2015-01-21 17:59:58 -06:00
if ( yosys_celltypes . cell_output ( cell - > type , conn . first ) )
2015-01-19 08:08:44 -06:00
for ( auto bit : sigmap ( conn . second ) )
bit2driver [ bit ] = cell ;
}
2015-02-01 15:41:03 -06:00
unproven_equiv_cells . sort ( ) ;
for ( auto it : unproven_equiv_cells )
{
it . second . sort ( ) ;
vector < Cell * > cells ;
for ( auto it2 : it . second )
cells . push_back ( it2 . second ) ;
2017-04-28 11:54:53 -05:00
EquivSimpleWorker worker ( cells , sigmap , bit2driver , max_seq , short_cones , verbose , model_undef ) ;
2015-02-01 15:41:03 -06:00
success_counter + = worker . run ( ) ;
2015-01-19 08:08:44 -06:00
}
}
2015-01-21 17:59:58 -06:00
log ( " Proved %d previously unproven $equiv cells. \n " , success_counter ) ;
2015-01-19 08:08:44 -06:00
}
} EquivSimplePass ;
PRIVATE_NAMESPACE_END