2019-12-28 07:07:46 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2012 Clifford Wolf < clifford @ clifford . at >
* 2019 Eddie Hung < eddie @ fpgeh . com >
*
* 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 .
*
* 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/register.h"
2019-12-30 18:36:33 -06:00
# include "kernel/sigtools.h"
2019-12-30 20:00:49 -06:00
# include "kernel/utils.h"
2020-01-03 17:38:18 -06:00
# include "kernel/celltypes.h"
2019-12-28 07:07:46 -06:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2020-01-06 17:52:59 -06:00
int map_autoidx ;
inline std : : string remap_name ( RTLIL : : IdString abc9_name )
{
return stringf ( " $abc$%d$%s " , map_autoidx , abc9_name . c_str ( ) + 1 ) ;
}
2020-01-10 13:45:41 -06:00
void check ( RTLIL : : Design * design )
{
dict < IdString , IdString > box_lookup ;
for ( auto m : design - > modules ( ) ) {
2020-01-14 17:05:49 -06:00
if ( m - > name . begins_with ( " $paramod " ) )
continue ;
2020-01-10 16:49:52 -06:00
auto flop = m - > get_bool_attribute ( ID ( abc9_flop ) ) ;
2020-01-10 13:45:41 -06:00
auto it = m - > attributes . find ( ID ( abc9_box_id ) ) ;
2020-01-14 17:05:49 -06:00
if ( ! flop ) {
if ( it = = m - > attributes . end ( ) )
continue ;
auto id = it - > second . as_int ( ) ;
auto r = box_lookup . insert ( std : : make_pair ( stringf ( " $__boxid%d " , id ) , m - > name ) ) ;
if ( ! r . second )
log_error ( " Module '%s' has the same abc9_box_id = %d value as '%s'. \n " ,
log_id ( m ) , id , log_id ( r . first - > second ) ) ;
2020-01-10 16:49:52 -06:00
}
2020-01-10 13:45:41 -06:00
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in , carry_out ;
for ( const auto & port_name : m - > ports ) {
auto w = m - > wire ( port_name ) ;
log_assert ( w ) ;
if ( w - > get_bool_attribute ( " \\ abc9_carry " ) ) {
if ( w - > port_input ) {
if ( carry_in ! = IdString ( ) )
2020-01-10 16:49:52 -06:00
log_error ( " Module '%s' contains more than one (* abc9_carry *) input port. \n " , log_id ( m ) ) ;
2020-01-10 13:45:41 -06:00
carry_in = port_name ;
}
if ( w - > port_output ) {
if ( carry_out ! = IdString ( ) )
2020-01-10 16:49:52 -06:00
log_error ( " Module '%s' contains more than one (* abc9_carry *) output port. \n " , log_id ( m ) ) ;
2020-01-10 13:45:41 -06:00
carry_out = port_name ;
}
}
}
if ( carry_in ! = IdString ( ) & & carry_out = = IdString ( ) )
2020-01-10 16:49:52 -06:00
log_error ( " Module '%s' contains an (* abc9_carry *) input port but no output port. \n " , log_id ( m ) ) ;
2020-01-10 13:45:41 -06:00
if ( carry_in = = IdString ( ) & & carry_out ! = IdString ( ) )
2020-01-10 16:49:52 -06:00
log_error ( " Module '%s' contains an (* abc9_carry *) output port but no input port. \n " , log_id ( m ) ) ;
if ( flop ) {
int num_outputs = 0 ;
for ( auto port_name : m - > ports ) {
auto wire = m - > wire ( port_name ) ;
if ( wire - > port_output ) num_outputs + + ;
}
if ( num_outputs ! = 1 )
2020-01-14 18:33:41 -06:00
log_error ( " Module '%s' with (* abc9_flop *) has %d outputs (expect 1). \n " , log_id ( m ) , num_outputs ) ;
2020-01-10 16:49:52 -06:00
}
2020-01-10 13:45:41 -06:00
}
}
2020-01-14 01:42:27 -06:00
void mark_scc ( RTLIL : : Module * module )
2019-12-28 07:07:46 -06:00
{
// For every unique SCC found, (arbitrarily) find the first
// cell in the component, and convert all wires driven by
// its output ports into a new PO, and drive its previous
// sinks with a new PI
pool < RTLIL : : Const > ids_seen ;
2020-01-11 10:42:58 -06:00
for ( auto cell : module - > cells ( ) ) {
2019-12-28 07:07:46 -06:00
auto it = cell - > attributes . find ( ID ( abc9_scc_id ) ) ;
if ( it = = cell - > attributes . end ( ) )
continue ;
2020-01-14 01:42:27 -06:00
auto id = it - > second ;
auto r = ids_seen . insert ( id ) ;
2019-12-28 07:07:46 -06:00
cell - > attributes . erase ( it ) ;
if ( ! r . second )
continue ;
for ( auto & c : cell - > connections_ ) {
if ( c . second . is_fully_const ( ) ) continue ;
if ( cell - > output ( c . first ) ) {
SigBit b = c . second . as_bit ( ) ;
Wire * w = b . wire ;
2020-01-13 23:45:27 -06:00
w - > set_bool_attribute ( ID : : keep ) ;
2020-01-14 01:42:27 -06:00
w - > attributes [ ID ( abc9_scc_id ) ] = id . as_int ( ) ;
2019-12-28 07:07:46 -06:00
}
}
}
module - > fixup_ports ( ) ;
}
2019-12-30 20:00:49 -06:00
void prep_dff ( RTLIL : : Module * module )
{
2019-12-30 18:36:33 -06:00
auto design = module - > design ;
log_assert ( design ) ;
SigMap assign_map ( module ) ;
typedef SigSpec clkdomain_t ;
dict < clkdomain_t , int > clk_to_mergeability ;
2020-01-11 10:42:58 -06:00
for ( auto cell : module - > cells ( ) ) {
2020-01-04 11:17:01 -06:00
if ( cell - > type ! = " $__ABC9_FF_ " )
continue ;
2019-12-30 18:36:33 -06:00
2020-01-04 11:17:01 -06:00
Wire * abc9_clock_wire = module - > wire ( stringf ( " %s.clock " , cell - > name . c_str ( ) ) ) ;
if ( abc9_clock_wire = = NULL )
log_error ( " '%s.clock' is not a wire present in module '%s'. \n " , cell - > name . c_str ( ) , log_id ( module ) ) ;
SigSpec abc9_clock = assign_map ( abc9_clock_wire ) ;
clkdomain_t key ( abc9_clock ) ;
auto r = clk_to_mergeability . insert ( std : : make_pair ( abc9_clock , clk_to_mergeability . size ( ) + 1 ) ) ;
2020-02-12 17:33:02 -06:00
auto r2 = cell - > attributes . insert ( ID ( abc9_mergeability ) ) ; ;
2020-01-04 11:17:01 -06:00
log_assert ( r2 . second ) ;
2020-02-12 17:33:02 -06:00
r2 . first - > second = r . first - > second ;
2020-01-04 11:17:01 -06:00
}
2019-12-30 21:23:54 -06:00
RTLIL : : Module * holes_module = design - > module ( stringf ( " %s$holes " , module - > name . c_str ( ) ) ) ;
2019-12-31 00:58:39 -06:00
if ( holes_module ) {
2020-01-11 19:26:25 -06:00
SigMap sigmap ( holes_module ) ;
dict < SigSpec , SigSpec > replace ;
2020-01-23 16:58:56 -06:00
for ( auto cell : holes_module - > cells ( ) . to_vector ( ) ) {
if ( ! cell - > type . in ( " $_DFF_N_ " , " $_DFF_NN0_ " , " $_DFF_NN1_ " , " $_DFF_NP0_ " , " $_DFF_NP1_ " ,
" $_DFF_P_ " , " $_DFF_PN0_ " , " $_DFF_PN1 " , " $_DFF_PP0_ " , " $_DFF_PP1_ " ) )
continue ;
SigBit D = cell - > getPort ( " \\ D " ) ;
SigBit Q = cell - > getPort ( " \\ Q " ) ;
// Emulate async control embedded inside $_DFF_* cell with mux in front of D
if ( cell - > type . in ( " $_DFF_NN0_ " , " $_DFF_PN0_ " ) )
D = holes_module - > MuxGate ( NEW_ID , State : : S0 , D , cell - > getPort ( " \\ R " ) ) ;
else if ( cell - > type . in ( " $_DFF_NN1_ " , " $_DFF_PN1_ " ) )
D = holes_module - > MuxGate ( NEW_ID , State : : S1 , D , cell - > getPort ( " \\ R " ) ) ;
else if ( cell - > type . in ( " $_DFF_NP0_ " , " $_DFF_PP0_ " ) )
D = holes_module - > MuxGate ( NEW_ID , D , State : : S0 , cell - > getPort ( " \\ R " ) ) ;
else if ( cell - > type . in ( " $_DFF_NP1_ " , " $_DFF_PP1_ " ) )
D = holes_module - > MuxGate ( NEW_ID , D , State : : S1 , cell - > getPort ( " \\ R " ) ) ;
// Remove the $_DFF_* cell from what needs to be a combinatorial box
holes_module - > remove ( cell ) ;
Wire * port ;
if ( GetSize ( Q . wire ) = = 1 )
port = holes_module - > wire ( stringf ( " $abc%s " , Q . wire - > name . c_str ( ) ) ) ;
2019-12-30 21:23:54 -06:00
else
2020-01-23 16:58:56 -06:00
port = holes_module - > wire ( stringf ( " $abc%s[%d] " , Q . wire - > name . c_str ( ) , Q . offset ) ) ;
log_assert ( port ) ;
// Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
// in order to extract just the combinatorial control logic that feeds the box
// (i.e. clock enable, synchronous reset, etc.)
replace . insert ( std : : make_pair ( Q , D ) ) ;
// Since `flatten` above would have created wires named "<cell>.Q",
// extract the pre-techmap cell name
auto pos = Q . wire - > name . str ( ) . rfind ( " . " ) ;
log_assert ( pos ! = std : : string : : npos ) ;
IdString driver = Q . wire - > name . substr ( 0 , pos ) ;
// And drive the signal that was previously driven by "DFF.Q" (typically
// used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
// wire (which itself is driven an by input port) we inserted above
Wire * currQ = holes_module - > wire ( stringf ( " %s.abc9_ff.Q " , driver . c_str ( ) ) ) ;
log_assert ( currQ ) ;
holes_module - > connect ( Q , currQ ) ;
2019-12-30 21:23:54 -06:00
}
2020-01-11 10:42:58 -06:00
for ( auto & conn : holes_module - > connections_ )
2020-01-11 19:26:25 -06:00
conn . second = replace . at ( sigmap ( conn . second ) , conn . second ) ;
2019-12-30 21:23:54 -06:00
}
2019-12-30 18:36:33 -06:00
}
2020-01-14 14:25:45 -06:00
void prep_xaiger ( RTLIL : : Module * module , bool dff )
2019-12-30 20:00:49 -06:00
{
auto design = module - > design ;
log_assert ( design ) ;
SigMap sigmap ( module ) ;
dict < SigBit , pool < IdString > > bit_drivers , bit_users ;
TopoSort < IdString , RTLIL : : sort_by_id_str > toposort ;
2020-01-14 14:25:45 -06:00
dict < IdString , std : : vector < IdString > > box_ports ;
2019-12-30 20:00:49 -06:00
2020-01-11 10:42:58 -06:00
for ( auto cell : module - > cells ( ) ) {
2020-02-14 18:08:04 -06:00
if ( cell - > type = = " $__ABC9_FF_ " )
2019-12-30 20:00:49 -06:00
continue ;
2020-01-23 20:56:06 -06:00
if ( cell - > has_keep_attr ( ) )
continue ;
2019-12-30 20:00:49 -06:00
2020-01-03 17:38:18 -06:00
auto inst_module = module - > design - > module ( cell - > type ) ;
2020-01-14 17:05:49 -06:00
bool abc9_flop = inst_module & & inst_module - > get_bool_attribute ( " \\ abc9_flop " ) ;
if ( abc9_flop & & ! dff )
continue ;
2020-01-14 14:25:45 -06:00
2020-02-11 13:38:49 -06:00
if ( ( inst_module & & inst_module - > get_bool_attribute ( " \\ abc9_box " ) ) | | abc9_flop ) {
2020-01-14 14:25:45 -06:00
auto r = box_ports . insert ( cell - > type ) ;
if ( r . second ) {
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in , carry_out ;
for ( const auto & port_name : inst_module - > ports ) {
auto w = inst_module - > wire ( port_name ) ;
log_assert ( w ) ;
if ( w - > get_bool_attribute ( " \\ abc9_carry " ) ) {
2020-01-14 15:13:15 -06:00
log_assert ( w - > port_input ! = w - > port_output ) ;
if ( w - > port_input )
2020-01-14 14:25:45 -06:00
carry_in = port_name ;
2020-01-14 15:13:15 -06:00
else if ( w - > port_output )
2020-01-14 14:25:45 -06:00
carry_out = port_name ;
}
else
r . first - > second . push_back ( port_name ) ;
}
if ( carry_in ! = IdString ( ) ) {
r . first - > second . push_back ( carry_in ) ;
r . first - > second . push_back ( carry_out ) ;
}
}
2020-01-04 11:17:01 -06:00
}
else if ( ! yosys_celltypes . cell_known ( cell - > type ) )
2020-01-03 17:38:18 -06:00
continue ;
2019-12-30 20:00:49 -06:00
2020-01-27 13:18:21 -06:00
// TODO: Speed up toposort -- we care about box ordering only
2020-01-03 17:38:18 -06:00
for ( auto conn : cell - > connections ( ) ) {
if ( cell - > input ( conn . first ) )
for ( auto bit : sigmap ( conn . second ) )
bit_users [ bit ] . insert ( cell - > name ) ;
2019-12-30 20:00:49 -06:00
2020-01-04 11:17:01 -06:00
if ( cell - > output ( conn . first ) & & ! abc9_flop )
2020-01-03 17:38:18 -06:00
for ( auto bit : sigmap ( conn . second ) )
bit_drivers [ bit ] . insert ( cell - > name ) ;
2019-12-30 20:00:49 -06:00
}
2020-01-03 17:38:18 -06:00
toposort . node ( cell - > name ) ;
2019-12-30 20:00:49 -06:00
}
2020-01-14 14:25:45 -06:00
if ( box_ports . empty ( ) )
2019-12-30 20:00:49 -06:00
return ;
for ( auto & it : bit_users )
if ( bit_drivers . count ( it . first ) )
for ( auto driver_cell : bit_drivers . at ( it . first ) )
for ( auto user_cell : it . second )
toposort . edge ( driver_cell , user_cell ) ;
2020-01-11 10:42:58 -06:00
if ( ys_debug ( 1 ) )
toposort . analyze_loops = true ;
2019-12-30 20:00:49 -06:00
bool no_loops YS_ATTRIBUTE ( unused ) = toposort . sort ( ) ;
2020-01-11 10:42:58 -06:00
if ( ys_debug ( 1 ) ) {
unsigned i = 0 ;
for ( auto & it : toposort . loops ) {
log ( " loop %d \n " , i + + ) ;
for ( auto cell_name : it ) {
auto cell = module - > cell ( cell_name ) ;
log_assert ( cell ) ;
log ( " \t %s (%s @ %s) \n " , log_id ( cell ) , log_id ( cell - > type ) , cell - > get_src_attribute ( ) . c_str ( ) ) ;
}
2019-12-30 20:00:49 -06:00
}
}
2020-01-11 10:42:58 -06:00
2019-12-30 20:00:49 -06:00
log_assert ( no_loops ) ;
2020-01-14 14:25:45 -06:00
RTLIL : : Module * holes_module = design - > addModule ( stringf ( " %s$holes " , module - > name . c_str ( ) ) ) ;
log_assert ( holes_module ) ;
holes_module - > set_bool_attribute ( " \\ abc9_holes " ) ;
dict < IdString , Cell * > cell_cache ;
int port_id = 1 , box_count = 0 ;
2019-12-30 20:00:49 -06:00
for ( auto cell_name : toposort . sorted ) {
RTLIL : : Cell * cell = module - > cell ( cell_name ) ;
log_assert ( cell ) ;
RTLIL : : Module * box_module = design - > module ( cell - > type ) ;
2020-02-11 13:38:49 -06:00
if ( ! box_module | | ( ! box_module - > get_bool_attribute ( " \\ abc9_box " ) & & ! box_module - > get_bool_attribute ( " \\ abc9_flop " ) ) )
2019-12-30 20:00:49 -06:00
continue ;
2020-01-06 15:34:45 -06:00
2020-01-14 14:25:45 -06:00
cell - > attributes [ " \\ abc9_box_seq " ] = box_count + + ;
2019-12-30 20:00:49 -06:00
2020-01-14 17:05:49 -06:00
IdString derived_type = box_module - > derive ( design , cell - > parameters ) ;
box_module = design - > module ( derived_type ) ;
2019-12-30 20:00:49 -06:00
2020-01-14 17:05:49 -06:00
auto r = cell_cache . insert ( derived_type ) ;
2020-01-11 19:26:25 -06:00
auto & holes_cell = r . first - > second ;
if ( r . second ) {
if ( box_module - > has_processes ( ) )
Pass : : call_on_module ( design , box_module , " proc " ) ;
2019-12-30 20:00:49 -06:00
2020-01-11 19:26:25 -06:00
if ( box_module - > get_bool_attribute ( " \\ whitebox " ) ) {
2020-01-14 17:05:49 -06:00
holes_cell = holes_module - > addCell ( cell - > name , derived_type ) ;
2020-01-11 19:26:25 -06:00
2020-01-12 17:19:41 -06:00
if ( box_module - > has_processes ( ) )
Pass : : call_on_module ( design , box_module , " proc " ) ;
2020-01-11 19:26:25 -06:00
int box_inputs = 0 ;
for ( auto port_name : box_ports . at ( cell - > type ) ) {
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
log_assert ( w ) ;
log_assert ( ! w - > port_input | | ! w - > port_output ) ;
auto & conn = holes_cell - > connections_ [ port_name ] ;
if ( w - > port_input ) {
for ( int i = 0 ; i < GetSize ( w ) ; i + + ) {
box_inputs + + ;
RTLIL : : Wire * holes_wire = holes_module - > wire ( stringf ( " \\ i%d " , box_inputs ) ) ;
if ( ! holes_wire ) {
holes_wire = holes_module - > addWire ( stringf ( " \\ i%d " , box_inputs ) ) ;
holes_wire - > port_input = true ;
holes_wire - > port_id = port_id + + ;
holes_module - > ports . push_back ( holes_wire - > name ) ;
}
conn . append ( holes_wire ) ;
}
}
else if ( w - > port_output )
2020-01-14 17:05:49 -06:00
conn = holes_module - > addWire ( stringf ( " %s.%s " , derived_type . c_str ( ) , log_id ( port_name ) ) , GetSize ( w ) ) ;
2020-01-11 19:26:25 -06:00
}
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.abc9_ff.Q" that is used below
2020-02-14 18:08:04 -06:00
if ( box_module - > get_bool_attribute ( " \\ abc9_flop " ) ) {
2019-12-30 20:00:49 -06:00
box_inputs + + ;
2020-01-11 19:26:25 -06:00
Wire * holes_wire = holes_module - > wire ( stringf ( " \\ i%d " , box_inputs ) ) ;
2019-12-30 20:00:49 -06:00
if ( ! holes_wire ) {
holes_wire = holes_module - > addWire ( stringf ( " \\ i%d " , box_inputs ) ) ;
holes_wire - > port_input = true ;
holes_wire - > port_id = port_id + + ;
holes_module - > ports . push_back ( holes_wire - > name ) ;
}
2020-01-11 19:26:25 -06:00
Wire * Q = holes_module - > addWire ( stringf ( " %s.abc9_ff.Q " , cell - > name . c_str ( ) ) ) ;
holes_module - > connect ( Q , holes_wire ) ;
2019-12-30 20:00:49 -06:00
}
}
2020-01-11 19:26:25 -06:00
else // box_module is a blackbox
log_assert ( holes_cell = = nullptr ) ;
2019-12-30 20:00:49 -06:00
}
2020-01-11 19:26:25 -06:00
for ( auto port_name : box_ports . at ( cell - > type ) ) {
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
log_assert ( w ) ;
if ( ! w - > port_output )
continue ;
Wire * holes_wire = holes_module - > addWire ( stringf ( " $abc%s.%s " , cell - > name . c_str ( ) , log_id ( port_name ) ) , GetSize ( w ) ) ;
holes_wire - > port_output = true ;
holes_wire - > port_id = port_id + + ;
holes_module - > ports . push_back ( holes_wire - > name ) ;
if ( holes_cell ) // whitebox
holes_module - > connect ( holes_wire , holes_cell - > getPort ( port_name ) ) ;
else // blackbox
holes_module - > connect ( holes_wire , Const ( State : : S0 , GetSize ( w ) ) ) ;
2019-12-30 20:00:49 -06:00
}
}
}
2020-02-13 13:15:59 -06:00
void prep_delays ( RTLIL : : Design * design , bool dff_mode )
2020-01-10 13:45:41 -06:00
{
2020-02-12 17:25:30 -06:00
// Derive and collect all Yosys blackbox modules that are not combinatorial abc9 boxes
// (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
pool < Module * > blackboxes ;
pool < Module * > flops ;
2020-01-14 17:05:49 -06:00
std : : vector < Cell * > cells ;
2020-01-10 13:45:41 -06:00
for ( auto module : design - > selected_modules ( ) ) {
if ( module - > processes . size ( ) > 0 ) {
log ( " Skipping module %s as it contains processes. \n " , log_id ( module ) ) ;
continue ;
}
for ( auto cell : module - > cells ( ) ) {
if ( cell - > type . in ( ID ( $ _AND_ ) , ID ( $ _NOT_ ) , ID ( $ __ABC9_FF_ ) , ID ( $ __ABC9_DELAY ) ) )
continue ;
RTLIL : : Module * inst_module = module - > design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
if ( ! inst_module - > get_blackbox_attribute ( ) )
continue ;
2020-02-11 13:38:49 -06:00
if ( inst_module - > attributes . count ( ID ( abc9_box ) ) )
2020-01-10 13:45:41 -06:00
continue ;
2020-02-12 17:25:30 -06:00
IdString blackboxes_type = inst_module - > derive ( design , cell - > parameters ) ;
inst_module = design - > module ( blackboxes_type ) ;
2020-02-11 16:22:43 -06:00
log_assert ( inst_module ) ;
2020-02-12 17:25:30 -06:00
blackboxes . insert ( inst_module ) ;
2020-02-13 13:15:59 -06:00
if ( dff_mode & & inst_module - > get_bool_attribute ( ID ( abc9_flop ) ) ) {
2020-02-12 17:25:30 -06:00
flops . insert ( inst_module ) ;
continue ; // do not add $__ABC9_DELAY boxes to flops
// as delays will be captured in the flop box
}
2020-02-11 16:22:43 -06:00
2020-01-14 17:05:49 -06:00
cells . emplace_back ( cell ) ;
2020-01-10 13:45:41 -06:00
}
2020-02-11 16:22:43 -06:00
}
2020-01-10 13:45:41 -06:00
2020-02-11 16:22:43 -06:00
// Transform all $specify3 and $specrule to abc9_{arrival,required} attributes
dict < SigBit , int > arrivals , requireds ;
pool < Wire * > ports ;
std : : stringstream ss ;
2020-02-12 17:25:30 -06:00
for ( auto module : blackboxes ) {
2020-02-11 16:22:43 -06:00
arrivals . clear ( ) ;
requireds . clear ( ) ;
for ( auto cell : module - > cells ( ) ) {
if ( cell - > type = = ID ( $ specify3 ) ) {
auto src = cell - > getPort ( ID ( SRC ) ) ;
auto dst = cell - > getPort ( ID ( DST ) ) ;
for ( const auto & c : src . chunks ( ) )
if ( ! c . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
for ( const auto & c : dst . chunks ( ) )
if ( ! c . wire - > port_output )
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module output. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
int rise_max = cell - > getParam ( ID ( T_RISE_MAX ) ) . as_int ( ) ;
int fall_max = cell - > getParam ( ID ( T_FALL_MAX ) ) . as_int ( ) ;
int max = std : : max ( rise_max , fall_max ) ;
2020-02-13 11:48:48 -06:00
if ( max < 0 )
2020-02-11 16:22:43 -06:00
log_warning ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring. \n " , log_id ( module ) , log_id ( cell ) ) ;
2020-02-13 11:48:48 -06:00
if ( max < = 0 ) {
log_debug ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring. \n " , log_id ( module ) , log_id ( cell ) ) ;
2020-02-11 16:22:43 -06:00
continue ;
2020-01-10 13:45:41 -06:00
}
2020-02-12 17:25:30 -06:00
for ( const auto & d : dst )
2020-02-11 16:22:43 -06:00
arrivals [ d ] = std : : max ( arrivals [ d ] , max ) ;
}
else if ( cell - > type = = ID ( $ specrule ) ) {
auto type = cell - > getParam ( ID ( TYPE ) ) . decode_string ( ) ;
if ( type ! = " $setup " & & type ! = " $setuphold " )
2020-01-14 17:20:04 -06:00
continue ;
2020-02-11 16:22:43 -06:00
auto src = cell - > getPort ( ID ( SRC ) ) ;
auto dst = cell - > getPort ( ID ( DST ) ) ;
for ( const auto & c : src . chunks ( ) )
if ( ! c . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
for ( const auto & c : dst . chunks ( ) )
if ( ! c . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
2020-02-13 11:48:48 -06:00
int setup = cell - > getParam ( ID ( T_LIMIT_MAX ) ) . as_int ( ) ;
if ( setup < 0 )
log_warning ( " Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring. \n " , log_id ( module ) , log_id ( cell ) ) ;
if ( setup < = 0 ) {
log_debug ( " Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring. \n " , log_id ( module ) , log_id ( cell ) ) ;
2020-02-11 16:22:43 -06:00
continue ;
}
for ( const auto & s : src )
requireds [ s ] = std : : max ( requireds [ s ] , setup ) ;
}
}
2020-01-10 13:45:41 -06:00
2020-02-11 16:22:43 -06:00
if ( arrivals . empty ( ) & & requireds . empty ( ) )
continue ;
ports . clear ( ) ;
2020-02-13 13:15:59 -06:00
for ( const auto & i : arrivals )
2020-02-11 16:22:43 -06:00
ports . insert ( i . first . wire ) ;
for ( auto wire : ports ) {
log_assert ( wire - > port_output ) ;
ss . str ( " " ) ;
if ( GetSize ( wire ) = = 1 )
wire - > attributes [ ID ( abc9_arrival ) ] = arrivals . at ( SigBit ( wire , 0 ) ) ;
else {
bool first = true ;
for ( auto b : SigSpec ( wire ) ) {
if ( first )
first = false ;
else
ss < < " " ;
auto it = arrivals . find ( b ) ;
if ( it = = arrivals . end ( ) )
ss < < " 0 " ;
else
ss < < it - > second ;
2020-01-10 13:45:41 -06:00
}
2020-02-11 16:22:43 -06:00
wire - > attributes [ ID ( abc9_arrival ) ] = ss . str ( ) ;
2020-01-10 13:45:41 -06:00
}
}
2020-01-10 16:49:52 -06:00
2020-02-11 16:22:43 -06:00
ports . clear ( ) ;
for ( const auto & i : requireds )
ports . insert ( i . first . wire ) ;
for ( auto wire : ports ) {
log_assert ( wire - > port_input ) ;
ss . str ( " " ) ;
if ( GetSize ( wire ) = = 1 )
wire - > attributes [ ID ( abc9_required ) ] = requireds . at ( SigBit ( wire , 0 ) ) ;
else {
bool first = true ;
for ( auto b : SigSpec ( wire ) ) {
if ( first )
first = false ;
else
ss < < " " ;
auto it = requireds . find ( b ) ;
if ( it = = requireds . end ( ) )
ss < < " 0 " ;
else
ss < < it - > second ;
}
wire - > attributes [ ID ( abc9_required ) ] = ss . str ( ) ;
}
2020-01-10 16:49:52 -06:00
}
2020-02-11 16:22:43 -06:00
}
2020-01-10 16:49:52 -06:00
2020-02-11 16:22:43 -06:00
// Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
// with (* abc9_required *) attributes
dict < IdString , dict < IdString , std : : vector < int > > > requireds_cache ;
for ( auto cell : cells ) {
auto module = cell - > module ;
RTLIL : : Module * inst_module = module - > design - > module ( cell - > type ) ;
log_assert ( inst_module ) ;
IdString derived_type = inst_module - > derive ( design , cell - > parameters ) ;
inst_module = design - > module ( derived_type ) ;
log_assert ( inst_module ) ;
2020-02-13 13:15:59 -06:00
auto & cell_requireds = requireds_cache [ derived_type ] ;
2020-02-11 16:22:43 -06:00
for ( auto & conn : cell - > connections_ ) {
auto port_wire = inst_module - > wire ( conn . first ) ;
if ( ! port_wire - > port_input )
continue ;
2020-01-14 17:05:49 -06:00
2020-02-11 16:22:43 -06:00
auto r = cell_requireds . insert ( conn . first ) ;
auto & requireds = r . first - > second ;
if ( r . second ) {
auto it = port_wire - > attributes . find ( " \\ abc9_required " ) ;
if ( it = = port_wire - > attributes . end ( ) )
continue ;
if ( it - > second . flags = = 0 ) {
int delay = it - > second . as_int ( ) ;
requireds . emplace_back ( delay ) ;
}
else
for ( const auto & tok : split_tokens ( it - > second . decode_string ( ) ) ) {
int delay = atoi ( tok . c_str ( ) ) ;
requireds . push_back ( delay ) ;
}
}
2020-02-11 13:38:49 -06:00
2020-02-11 16:22:43 -06:00
if ( requireds . empty ( ) )
2020-02-11 13:38:49 -06:00
continue ;
2020-02-11 16:22:43 -06:00
SigSpec O = module - > addWire ( NEW_ID , GetSize ( conn . second ) ) ;
auto it = requireds . begin ( ) ;
for ( int i = 0 ; i < GetSize ( conn . second ) ; + + i ) {
# ifndef NDEBUG
if ( ys_debug ( 1 ) ) {
static std : : set < std : : pair < IdString , IdString > > seen ;
2020-02-13 13:15:59 -06:00
if ( seen . emplace ( derived_type , conn . first ) . second ) log ( " %s.%s abc9_required = %d \n " , log_id ( cell - > type ) , log_id ( conn . first ) , requireds [ i ] ) ;
2020-02-11 16:22:43 -06:00
}
# endif
auto box = module - > addCell ( NEW_ID , ID ( $ __ABC9_DELAY ) ) ;
box - > setPort ( ID ( I ) , conn . second [ i ] ) ;
box - > setPort ( ID ( O ) , O [ i ] ) ;
box - > setParam ( ID ( DELAY ) , * it ) ;
if ( requireds . size ( ) > 1 )
it + + ;
conn . second [ i ] = O [ i ] ;
}
2020-01-10 16:49:52 -06:00
}
}
2020-01-10 13:45:41 -06:00
}
2020-02-11 10:34:13 -06:00
void prep_lut ( RTLIL : : Design * design , int maxlut )
{
2020-02-13 11:54:40 -06:00
std : : vector < std : : tuple < int , IdString , int , std : : vector < int > > > table ;
2020-02-11 10:34:13 -06:00
for ( auto module : design - > modules ( ) ) {
auto it = module - > attributes . find ( ID ( abc9_lut ) ) ;
if ( it = = module - > attributes . end ( ) )
continue ;
SigBit o ;
std : : vector < int > specify ;
for ( auto cell : module - > cells ( ) ) {
if ( cell - > type ! = ID ( $ specify2 ) )
continue ;
log_assert ( cell - > getParam ( ID ( SRC_WIDTH ) ) = = 1 ) ;
log_assert ( cell - > getParam ( ID ( DST_WIDTH ) ) = = 1 ) ;
2020-02-11 11:18:08 -06:00
SigBit s = cell - > getPort ( ID ( SRC ) ) ;
2020-02-11 10:34:13 -06:00
SigBit d = cell - > getPort ( ID ( DST ) ) ;
2020-02-11 11:18:08 -06:00
log_assert ( s . wire - > port_input ) ;
log_assert ( d . wire - > port_output ) ;
2020-02-11 10:34:13 -06:00
if ( o = = SigBit ( ) )
o = d ;
else
log_assert ( o = = d ) ;
2020-02-13 11:48:48 -06:00
// TODO: Don't assume that each specify entry with the destination 'o'
// describes a unique LUT input
2020-02-11 10:34:13 -06:00
int rise_max = cell - > getParam ( ID ( T_RISE_MAX ) ) . as_int ( ) ;
int fall_max = cell - > getParam ( ID ( T_FALL_MAX ) ) . as_int ( ) ;
2020-02-11 16:22:43 -06:00
int max = std : : max ( rise_max , fall_max ) ;
if ( max < 0 )
log_error ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0. \n " , log_id ( module ) , log_id ( cell ) ) ;
specify . push_back ( max ) ;
2020-02-11 10:34:13 -06:00
}
if ( maxlut & & GetSize ( specify ) > maxlut )
continue ;
2020-02-13 12:30:29 -06:00
// ABC requires non-decreasing LUT input delays
std : : sort ( specify . begin ( ) , specify . end ( ) ) ;
2020-02-13 11:54:40 -06:00
table . emplace_back ( GetSize ( specify ) , module - > name , it - > second . as_int ( ) , std : : move ( specify ) ) ;
2020-02-11 10:34:13 -06:00
}
2020-02-13 11:48:48 -06:00
// ABC requires ascending size
2020-02-11 10:34:13 -06:00
std : : sort ( table . begin ( ) , table . end ( ) ) ;
2020-02-13 11:48:48 -06:00
std : : stringstream ss ;
const auto & first = table . front ( ) ;
// If the first entry does not start from a 1-input LUT,
// (as ABC requires) crop the first entry to do so
for ( int i = 1 ; i < std : : get < 0 > ( first ) ; i + + ) {
ss < < " # $__ABC9_LUT " < < i < < std : : endl ;
2020-02-13 11:54:40 -06:00
ss < < i < < " " < < std : : get < 2 > ( first ) ;
2020-02-13 11:48:48 -06:00
for ( int j = 0 ; j < i ; j + + )
2020-02-13 11:54:40 -06:00
ss < < " " < < std : : get < 3 > ( first ) [ j ] ;
2020-02-13 11:48:48 -06:00
ss < < std : : endl ;
}
for ( const auto & i : table ) {
ss < < " # " < < log_id ( std : : get < 1 > ( i ) ) < < std : : endl ;
2020-02-13 11:54:40 -06:00
ss < < std : : get < 0 > ( i ) < < " " < < std : : get < 2 > ( i ) ;
for ( const auto & j : std : : get < 3 > ( i ) )
2020-02-13 11:48:48 -06:00
ss < < " " < < j ;
ss < < std : : endl ;
}
2020-02-11 10:34:13 -06:00
design - > scratchpad_set_string ( " abc9_ops.lut_library " , ss . str ( ) ) ;
}
void write_lut ( RTLIL : : Module * module , const std : : string & dst ) {
std : : ofstream ofs ( dst ) ;
log_assert ( ofs . is_open ( ) ) ;
ofs < < module - > design - > scratchpad_get_string ( " abc9_ops.lut_library " ) ;
ofs . close ( ) ;
}
2020-02-13 13:15:59 -06:00
void prep_box ( RTLIL : : Design * design , bool dff_mode )
2020-02-11 10:54:13 -06:00
{
std : : stringstream ss ;
2020-02-11 16:22:43 -06:00
int abc9_box_id = 1 ;
dict < IdString , std : : vector < IdString > > box_ports ;
2020-02-11 13:38:49 -06:00
for ( auto module : design - > modules ( ) ) {
2020-02-13 13:15:59 -06:00
auto abc9_flop = module - > get_bool_attribute ( ID ( abc9_flop ) ) ;
if ( abc9_flop ) {
if ( dff_mode ) {
int num_inputs = 0 , num_outputs = 0 ;
for ( auto port_name : module - > ports ) {
auto wire = module - > wire ( port_name ) ;
log_assert ( GetSize ( wire ) = = 1 ) ;
if ( wire - > port_input ) num_inputs + + ;
if ( wire - > port_output ) num_outputs + + ;
}
log_assert ( num_outputs = = 1 ) ;
2020-02-11 16:22:43 -06:00
2020-02-13 13:15:59 -06:00
auto r = module - > attributes . insert ( ID ( abc9_box_id ) ) ;
if ( r . second )
r . first - > second = abc9_box_id + + ;
2020-02-11 16:22:43 -06:00
2020-02-13 13:15:59 -06:00
ss < < log_id ( module ) < < " " < < r . first - > second . as_int ( ) ;
ss < < " " < < ( module - > get_bool_attribute ( ID : : whitebox ) ? " 1 " : " 0 " ) ;
ss < < " " < < num_inputs + 1 < < " " < < num_outputs < < std : : endl ;
2020-02-11 16:22:43 -06:00
2020-02-13 13:15:59 -06:00
ss < < " # " ;
bool first = true ;
for ( auto port_name : module - > ports ) {
auto wire = module - > wire ( port_name ) ;
if ( ! wire - > port_input )
continue ;
if ( first )
first = false ;
else
ss < < " " ;
ss < < log_id ( wire ) ;
}
ss < < " abc9_ff.Q " < < std : : endl ;
2020-02-11 16:22:43 -06:00
2020-02-13 13:15:59 -06:00
first = true ;
for ( auto port_name : module - > ports ) {
auto wire = module - > wire ( port_name ) ;
if ( ! wire - > port_input )
continue ;
if ( first )
first = false ;
else
ss < < " " ;
ss < < wire - > attributes . at ( " \\ abc9_required " , 0 ) . as_int ( ) ;
}
// Last input is 'abc9_ff.Q'
ss < < " 0 " < < std : : endl < < std : : endl ;
continue ;
2020-02-11 16:22:43 -06:00
}
}
2020-02-13 13:15:59 -06:00
else {
if ( ! module - > attributes . erase ( ID ( abc9_box ) ) )
continue ;
}
2020-02-11 13:38:49 -06:00
log_assert ( ! module - > attributes . count ( ID ( abc9_box_id ) ) ) ;
dict < std : : pair < SigBit , SigBit > , std : : string > table ;
std : : vector < SigBit > inputs ;
std : : vector < SigBit > outputs ;
2020-02-11 16:22:43 -06:00
auto r = box_ports . insert ( module - > name ) ;
if ( r . second ) {
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in , carry_out ;
for ( const auto & port_name : module - > ports ) {
auto w = module - > wire ( port_name ) ;
log_assert ( w ) ;
if ( w - > get_bool_attribute ( " \\ abc9_carry " ) ) {
log_assert ( w - > port_input ! = w - > port_output ) ;
if ( w - > port_input )
carry_in = port_name ;
else if ( w - > port_output )
carry_out = port_name ;
}
else
r . first - > second . push_back ( port_name ) ;
}
if ( carry_in ! = IdString ( ) ) {
r . first - > second . push_back ( carry_in ) ;
r . first - > second . push_back ( carry_out ) ;
}
}
for ( auto port_name : r . first - > second ) {
2020-02-11 13:38:49 -06:00
auto wire = module - > wire ( port_name ) ;
if ( wire - > port_input )
for ( int i = 0 ; i < GetSize ( wire ) ; i + + )
inputs . emplace_back ( wire , i ) ;
if ( wire - > port_output )
for ( int i = 0 ; i < GetSize ( wire ) ; i + + )
outputs . emplace_back ( wire , i ) ;
}
for ( auto cell : module - > cells ( ) ) {
if ( cell - > type ! = ID ( $ specify2 ) )
continue ;
auto src = cell - > getPort ( ID ( SRC ) ) ;
auto dst = cell - > getPort ( ID ( DST ) ) ;
for ( const auto & c : src . chunks ( ) )
if ( ! c . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
for ( const auto & c : dst . chunks ( ) )
if ( ! c . wire - > port_output )
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module output. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
int rise_max = cell - > getParam ( ID ( T_RISE_MAX ) ) . as_int ( ) ;
int fall_max = cell - > getParam ( ID ( T_FALL_MAX ) ) . as_int ( ) ;
int max = std : : max ( rise_max , fall_max ) ;
2020-02-11 16:22:43 -06:00
if ( max < 0 )
log_error ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0. \n " , log_id ( module ) , log_id ( cell ) ) ;
if ( cell - > getParam ( ID ( FULL ) ) . as_bool ( ) ) {
for ( auto s : src )
for ( auto d : dst ) {
auto r = table . insert ( std : : make_pair ( s , d ) ) ;
log_assert ( r . second ) ;
r . first - > second = std : : to_string ( max ) ;
}
}
else {
log_assert ( GetSize ( src ) = = GetSize ( dst ) ) ;
for ( auto i = 0 ; i < GetSize ( src ) ; i + + ) {
auto r = table . insert ( std : : make_pair ( src [ i ] , dst [ i ] ) ) ;
2020-02-13 12:30:29 -06:00
if ( ! r . second )
log_error ( " Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'. \n " , log_id ( module ) , log_signal ( src [ i ] ) , log_signal ( dst [ i ] ) ) ;
2020-02-11 13:38:49 -06:00
log_assert ( r . second ) ;
r . first - > second = std : : to_string ( max ) ;
}
2020-02-11 16:22:43 -06:00
}
2020-02-11 13:38:49 -06:00
}
2020-02-11 16:22:43 -06:00
auto r2 = module - > attributes . insert ( ID ( abc9_box_id ) ) ;
log_assert ( r2 . second ) ;
2020-02-11 13:38:49 -06:00
ss < < log_id ( module ) < < " " < < abc9_box_id ;
2020-02-11 16:22:43 -06:00
r2 . first - > second = abc9_box_id + + ;
2020-02-11 13:38:49 -06:00
ss < < " " < < ( module - > get_bool_attribute ( ID : : whitebox ) ? " 1 " : " 0 " ) ;
ss < < " " < < GetSize ( inputs ) < < " " < < GetSize ( outputs ) < < std : : endl ;
bool first = true ;
ss < < " # " ;
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
if ( GetSize ( i . wire ) = = 1 )
ss < < log_id ( i . wire ) ;
else
ss < < log_id ( i . wire ) < < " [ " < < i . offset < < " ] " ;
}
ss < < std : : endl ;
for ( const auto & o : outputs ) {
first = true ;
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
ss < < table . at ( std : : make_pair ( i , o ) , " - " ) ;
}
ss < < " # " ;
if ( GetSize ( o . wire ) = = 1 )
ss < < log_id ( o . wire ) ;
else
ss < < log_id ( o . wire ) < < " [ " < < o . offset < < " ] " ;
ss < < std : : endl ;
2020-01-10 13:45:41 -06:00
2020-02-11 13:38:49 -06:00
}
ss < < std : : endl ;
2020-01-10 13:45:41 -06:00
}
2020-02-11 16:22:43 -06:00
// ABC expects at least one box
if ( ss . tellp ( ) = = 0 )
ss < < " (dummy) 1 0 0 0 " ;
2020-02-11 10:54:13 -06:00
design - > scratchpad_set_string ( " abc9_ops.box_library " , ss . str ( ) ) ;
}
2020-01-10 13:45:41 -06:00
2020-02-11 10:54:13 -06:00
void write_box ( RTLIL : : Module * module , const std : : string & dst ) {
std : : ofstream ofs ( dst ) ;
log_assert ( ofs . is_open ( ) ) ;
ofs < < module - > design - > scratchpad_get_string ( " abc9_ops.box_library " ) ;
2020-01-10 13:45:41 -06:00
ofs . close ( ) ;
}
2020-01-06 17:52:59 -06:00
void reintegrate ( RTLIL : : Module * module )
{
auto design = module - > design ;
log_assert ( design ) ;
map_autoidx = autoidx + + ;
RTLIL : : Module * mapped_mod = design - > module ( stringf ( " %s$abc9 " , module - > name . c_str ( ) ) ) ;
if ( mapped_mod = = NULL )
log_error ( " ABC output file does not contain a module `%s$abc'. \n " , log_id ( module ) ) ;
for ( auto w : mapped_mod - > wires ( ) )
module - > addWire ( remap_name ( w - > name ) , GetSize ( w ) ) ;
2020-01-07 11:48:57 -06:00
dict < IdString , std : : vector < IdString > > box_ports ;
for ( auto m : design - > modules ( ) ) {
2020-01-24 00:45:34 -06:00
if ( ! m - > attributes . count ( ID ( abc9_box_id ) ) )
2020-01-07 11:48:57 -06:00
continue ;
2020-01-24 00:45:34 -06:00
auto r = box_ports . insert ( m - > name ) ;
2020-01-27 14:29:28 -06:00
if ( ! r . second )
continue ;
2020-01-07 11:48:57 -06:00
2020-01-27 14:29:28 -06:00
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in , carry_out ;
for ( const auto & port_name : m - > ports ) {
auto w = m - > wire ( port_name ) ;
log_assert ( w ) ;
if ( w - > get_bool_attribute ( " \\ abc9_carry " ) ) {
log_assert ( w - > port_input ! = w - > port_output ) ;
if ( w - > port_input )
carry_in = port_name ;
else if ( w - > port_output )
carry_out = port_name ;
2020-01-07 11:48:57 -06:00
}
2020-01-27 14:29:28 -06:00
else
r . first - > second . push_back ( port_name ) ;
}
if ( carry_in ! = IdString ( ) ) {
r . first - > second . push_back ( carry_in ) ;
r . first - > second . push_back ( carry_out ) ;
2020-01-07 11:48:57 -06:00
}
}
2020-01-09 13:21:03 -06:00
std : : vector < Cell * > boxes ;
for ( auto cell : module - > cells ( ) . to_vector ( ) ) {
2020-01-13 21:21:11 -06:00
if ( cell - > has_keep_attr ( ) )
continue ;
2020-01-14 17:05:49 -06:00
if ( cell - > type . in ( ID ( $ _AND_ ) , ID ( $ _NOT_ ) , ID ( $ __ABC9_FF_ ) ) )
2020-01-09 13:21:03 -06:00
module - > remove ( cell ) ;
else if ( cell - > attributes . erase ( " \\ abc9_box_seq " ) )
boxes . emplace_back ( cell ) ;
}
2020-01-06 17:52:59 -06:00
dict < SigBit , pool < IdString > > bit_drivers , bit_users ;
TopoSort < IdString , RTLIL : : sort_by_id_str > toposort ;
dict < RTLIL : : Cell * , RTLIL : : Cell * > not2drivers ;
dict < SigBit , std : : vector < RTLIL : : Cell * > > bit2sinks ;
std : : map < IdString , int > cell_stats ;
for ( auto mapped_cell : mapped_mod - > cells ( ) )
{
2020-01-27 13:18:21 -06:00
// TODO: Speed up toposort -- we care about NOT ordering only
2020-01-06 17:52:59 -06:00
toposort . node ( mapped_cell - > name ) ;
if ( mapped_cell - > type = = ID ( $ _NOT_ ) ) {
RTLIL : : SigBit a_bit = mapped_cell - > getPort ( ID : : A ) ;
RTLIL : : SigBit y_bit = mapped_cell - > getPort ( ID : : Y ) ;
bit_users [ a_bit ] . insert ( mapped_cell - > name ) ;
2020-01-14 01:33:37 -06:00
// Ignore inouts for topo ordering
if ( y_bit . wire & & ! ( y_bit . wire - > port_input & & y_bit . wire - > port_output ) )
bit_drivers [ y_bit ] . insert ( mapped_cell - > name ) ;
2020-01-06 17:52:59 -06:00
if ( ! a_bit . wire ) {
mapped_cell - > setPort ( ID : : Y , module - > addWire ( NEW_ID ) ) ;
RTLIL : : Wire * wire = module - > wire ( remap_name ( y_bit . wire - > name ) ) ;
log_assert ( wire ) ;
module - > connect ( RTLIL : : SigBit ( wire , y_bit . offset ) , State : : S1 ) ;
}
else {
RTLIL : : Cell * driver_lut = nullptr ;
// ABC can return NOT gates that drive POs
if ( ! a_bit . wire - > port_input ) {
// If it's not a NOT gate that that comes from a PI directly,
// find the driver LUT and clone that to guarantee that we won't
// increase the max logic depth
// (TODO: Optimise by not cloning unless will increase depth)
RTLIL : : IdString driver_name ;
if ( GetSize ( a_bit . wire ) = = 1 )
2020-01-14 13:46:56 -06:00
driver_name = stringf ( " $lut%s " , a_bit . wire - > name . c_str ( ) ) ;
2020-01-06 17:52:59 -06:00
else
2020-01-14 13:46:56 -06:00
driver_name = stringf ( " $lut%s[%d] " , a_bit . wire - > name . c_str ( ) , a_bit . offset ) ;
2020-01-06 17:52:59 -06:00
driver_lut = mapped_mod - > cell ( driver_name ) ;
}
if ( ! driver_lut ) {
// If a driver couldn't be found (could be from PI or box CI)
// then implement using a LUT
2020-01-14 13:46:56 -06:00
RTLIL : : Cell * cell = module - > addLut ( remap_name ( stringf ( " $lut%s " , mapped_cell - > name . c_str ( ) ) ) ,
2020-01-06 17:52:59 -06:00
RTLIL : : SigBit ( module - > wires_ . at ( remap_name ( a_bit . wire - > name ) ) , a_bit . offset ) ,
RTLIL : : SigBit ( module - > wires_ . at ( remap_name ( y_bit . wire - > name ) ) , y_bit . offset ) ,
RTLIL : : Const : : from_string ( " 01 " ) ) ;
bit2sinks [ cell - > getPort ( ID : : A ) ] . push_back ( cell ) ;
cell_stats [ ID ( $ lut ) ] + + ;
}
else
not2drivers [ mapped_cell ] = driver_lut ;
}
continue ;
}
if ( mapped_cell - > type . in ( ID ( $ lut ) , ID ( $ __ABC9_FF_ ) ) ) {
2020-01-09 13:21:03 -06:00
RTLIL : : Cell * cell = module - > addCell ( remap_name ( mapped_cell - > name ) , mapped_cell - > type ) ;
cell - > parameters = mapped_cell - > parameters ;
cell - > attributes = mapped_cell - > attributes ;
for ( auto & mapped_conn : mapped_cell - > connections ( ) ) {
RTLIL : : SigSpec newsig ;
for ( auto c : mapped_conn . second . chunks ( ) ) {
if ( c . width = = 0 )
continue ;
//log_assert(c.width == 1);
if ( c . wire )
c . wire = module - > wires_ . at ( remap_name ( c . wire - > name ) ) ;
newsig . append ( c ) ;
}
cell - > setPort ( mapped_conn . first , newsig ) ;
if ( cell - > input ( mapped_conn . first ) ) {
for ( auto i : newsig )
bit2sinks [ i ] . push_back ( cell ) ;
for ( auto i : mapped_conn . second )
bit_users [ i ] . insert ( mapped_cell - > name ) ;
}
if ( cell - > output ( mapped_conn . first ) )
for ( auto i : mapped_conn . second )
2020-01-13 23:45:27 -06:00
// Ignore inouts for topo ordering
if ( i . wire & & ! ( i . wire - > port_input & & i . wire - > port_output ) )
bit_drivers [ i ] . insert ( mapped_cell - > name ) ;
2020-01-09 13:21:03 -06:00
}
2020-01-06 17:52:59 -06:00
}
else {
2020-01-09 13:21:03 -06:00
RTLIL : : Cell * existing_cell = module - > cell ( mapped_cell - > name ) ;
2020-01-14 16:06:02 -06:00
if ( ! existing_cell )
log_error ( " Cannot find existing box cell with name '%s' in original design. \n " , log_id ( mapped_cell ) ) ;
2020-01-14 17:05:49 -06:00
2020-01-27 14:29:28 -06:00
if ( existing_cell - > type = = ID ( $ __ABC9_DELAY ) ) {
2020-01-14 17:05:49 -06:00
SigBit I = mapped_cell - > getPort ( ID ( i ) ) ;
SigBit O = mapped_cell - > getPort ( ID ( o ) ) ;
if ( I . wire )
I . wire = module - > wires_ . at ( remap_name ( I . wire - > name ) ) ;
log_assert ( O . wire ) ;
O . wire = module - > wires_ . at ( remap_name ( O . wire - > name ) ) ;
module - > connect ( O , I ) ;
continue ;
}
2020-01-09 13:21:03 -06:00
2020-01-24 00:45:34 -06:00
RTLIL : : Module * box_module = design - > module ( existing_cell - > type ) ;
2020-01-27 14:29:28 -06:00
IdString derived_type = box_module - > derive ( design , existing_cell - > parameters ) ;
RTLIL : : Module * derived_module = design - > module ( derived_type ) ;
log_assert ( derived_module ) ;
log_assert ( mapped_cell - > type = = stringf ( " $__boxid%d " , derived_module - > attributes . at ( " \\ abc9_box_id " ) . as_int ( ) ) ) ;
2020-01-24 00:45:34 -06:00
mapped_cell - > type = existing_cell - > type ;
2020-01-09 13:21:03 -06:00
RTLIL : : Cell * cell = module - > addCell ( remap_name ( mapped_cell - > name ) , mapped_cell - > type ) ;
cell - > parameters = existing_cell - > parameters ;
cell - > attributes = existing_cell - > attributes ;
module - > swap_names ( cell , existing_cell ) ;
2020-01-06 17:52:59 -06:00
2020-01-24 00:45:34 -06:00
auto jt = mapped_cell - > connections_ . find ( " \\ i " ) ;
log_assert ( jt ! = mapped_cell - > connections_ . end ( ) ) ;
SigSpec inputs = std : : move ( jt - > second ) ;
mapped_cell - > connections_ . erase ( jt ) ;
jt = mapped_cell - > connections_ . find ( " \\ o " ) ;
log_assert ( jt ! = mapped_cell - > connections_ . end ( ) ) ;
SigSpec outputs = std : : move ( jt - > second ) ;
mapped_cell - > connections_ . erase ( jt ) ;
2020-01-07 11:48:57 -06:00
auto abc9_flop = box_module - > attributes . count ( " \\ abc9_flop " ) ;
if ( ! abc9_flop ) {
for ( const auto & i : inputs )
bit_users [ i ] . insert ( mapped_cell - > name ) ;
for ( const auto & i : outputs )
2020-01-14 01:33:37 -06:00
// Ignore inouts for topo ordering
if ( i . wire & & ! ( i . wire - > port_input & & i . wire - > port_output ) )
bit_drivers [ i ] . insert ( mapped_cell - > name ) ;
2020-01-07 11:32:58 -06:00
}
2020-01-07 11:48:57 -06:00
int input_count = 0 , output_count = 0 ;
2020-02-05 16:46:48 -06:00
for ( const auto & port_name : box_ports . at ( derived_type ) ) {
2020-01-07 11:48:57 -06:00
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
log_assert ( w ) ;
SigSpec sig ;
if ( w - > port_input ) {
sig = inputs . extract ( input_count , GetSize ( w ) ) ;
input_count + = GetSize ( w ) ;
}
if ( w - > port_output ) {
sig = outputs . extract ( output_count , GetSize ( w ) ) ;
output_count + = GetSize ( w ) ;
}
SigSpec newsig ;
for ( auto c : sig . chunks ( ) ) {
if ( c . width = = 0 )
continue ;
//log_assert(c.width == 1);
if ( c . wire )
c . wire = module - > wires_ . at ( remap_name ( c . wire - > name ) ) ;
newsig . append ( c ) ;
}
cell - > setPort ( port_name , newsig ) ;
2020-01-07 11:32:58 -06:00
2020-01-07 11:48:57 -06:00
if ( w - > port_input & & ! abc9_flop )
for ( const auto & i : newsig )
bit2sinks [ i ] . push_back ( cell ) ;
}
}
2020-01-06 17:52:59 -06:00
2020-01-09 13:21:03 -06:00
cell_stats [ mapped_cell - > type ] + + ;
2020-01-06 17:52:59 -06:00
}
2020-01-09 13:21:03 -06:00
for ( auto cell : boxes )
module - > remove ( cell ) ;
2020-01-06 17:52:59 -06:00
// Copy connections (and rename) from mapped_mod to module
for ( auto conn : mapped_mod - > connections ( ) ) {
if ( ! conn . first . is_fully_const ( ) ) {
auto chunks = conn . first . chunks ( ) ;
for ( auto & c : chunks )
c . wire = module - > wires_ . at ( remap_name ( c . wire - > name ) ) ;
conn . first = std : : move ( chunks ) ;
}
if ( ! conn . second . is_fully_const ( ) ) {
auto chunks = conn . second . chunks ( ) ;
for ( auto & c : chunks )
if ( c . wire )
c . wire = module - > wires_ . at ( remap_name ( c . wire - > name ) ) ;
conn . second = std : : move ( chunks ) ;
}
module - > connect ( conn ) ;
}
for ( auto & it : cell_stats )
log ( " ABC RESULTS: %15s cells: %8d \n " , it . first . c_str ( ) , it . second ) ;
int in_wires = 0 , out_wires = 0 ;
// Stitch in mapped_mod's inputs/outputs into module
for ( auto port : mapped_mod - > ports ) {
2020-01-14 01:42:27 -06:00
RTLIL : : Wire * mapped_wire = mapped_mod - > wire ( port ) ;
2020-01-06 17:52:59 -06:00
RTLIL : : Wire * wire = module - > wire ( port ) ;
log_assert ( wire ) ;
2020-01-14 01:42:27 -06:00
if ( wire - > attributes . erase ( ID ( abc9_scc_id ) ) ) {
auto r YS_ATTRIBUTE ( unused ) = wire - > attributes . erase ( ID : : keep ) ;
log_assert ( r ) ;
}
2020-01-06 17:52:59 -06:00
RTLIL : : Wire * remap_wire = module - > wire ( remap_name ( port ) ) ;
2020-01-07 11:32:58 -06:00
RTLIL : : SigSpec signal ( wire , 0 , GetSize ( remap_wire ) ) ;
2020-01-06 17:52:59 -06:00
log_assert ( GetSize ( signal ) > = GetSize ( remap_wire ) ) ;
RTLIL : : SigSig conn ;
2020-01-14 01:42:27 -06:00
if ( mapped_wire - > port_output ) {
2020-01-06 17:52:59 -06:00
conn . first = signal ;
conn . second = remap_wire ;
out_wires + + ;
module - > connect ( conn ) ;
}
2020-01-14 01:42:27 -06:00
else if ( mapped_wire - > port_input ) {
2020-01-06 17:52:59 -06:00
conn . first = remap_wire ;
conn . second = signal ;
in_wires + + ;
module - > connect ( conn ) ;
}
}
2020-01-27 13:18:21 -06:00
// ABC9 will return $_NOT_ gates in its mapping (since they are
// treated as being "free"), in particular driving primary
// outputs (real primary outputs, or cells treated as blackboxes)
// or driving box inputs.
// Instead of just mapping those $_NOT_ gates into 2-input $lut-s
// at an area and delay cost, see if it is possible to push
// this $_NOT_ into the driving LUT, or into all sink LUTs.
// When this is not possible, (i.e. this signal drives two primary
// outputs, only one of which is complemented) and when the driver
// is a LUT, then clone the LUT so that it can be inverted without
// increasing depth/delay.
2020-01-06 17:52:59 -06:00
for ( auto & it : bit_users )
if ( bit_drivers . count ( it . first ) )
for ( auto driver_cell : bit_drivers . at ( it . first ) )
for ( auto user_cell : it . second )
toposort . edge ( driver_cell , user_cell ) ;
bool no_loops YS_ATTRIBUTE ( unused ) = toposort . sort ( ) ;
log_assert ( no_loops ) ;
for ( auto ii = toposort . sorted . rbegin ( ) ; ii ! = toposort . sorted . rend ( ) ; ii + + ) {
RTLIL : : Cell * not_cell = mapped_mod - > cell ( * ii ) ;
log_assert ( not_cell ) ;
if ( not_cell - > type ! = ID ( $ _NOT_ ) )
continue ;
auto it = not2drivers . find ( not_cell ) ;
if ( it = = not2drivers . end ( ) )
continue ;
RTLIL : : Cell * driver_lut = it - > second ;
RTLIL : : SigBit a_bit = not_cell - > getPort ( ID : : A ) ;
RTLIL : : SigBit y_bit = not_cell - > getPort ( ID : : Y ) ;
RTLIL : : Const driver_mask ;
a_bit . wire = module - > wires_ . at ( remap_name ( a_bit . wire - > name ) ) ;
y_bit . wire = module - > wires_ . at ( remap_name ( y_bit . wire - > name ) ) ;
auto jt = bit2sinks . find ( a_bit ) ;
if ( jt = = bit2sinks . end ( ) )
goto clone_lut ;
for ( auto sink_cell : jt - > second )
if ( sink_cell - > type ! = ID ( $ lut ) )
goto clone_lut ;
// Push downstream LUTs past inverter
for ( auto sink_cell : jt - > second ) {
SigSpec A = sink_cell - > getPort ( ID : : A ) ;
RTLIL : : Const mask = sink_cell - > getParam ( ID ( LUT ) ) ;
int index = 0 ;
for ( ; index < GetSize ( A ) ; index + + )
if ( A [ index ] = = a_bit )
break ;
log_assert ( index < GetSize ( A ) ) ;
int i = 0 ;
while ( i < GetSize ( mask ) ) {
for ( int j = 0 ; j < ( 1 < < index ) ; j + + )
std : : swap ( mask [ i + j ] , mask [ i + j + ( 1 < < index ) ] ) ;
i + = 1 < < ( index + 1 ) ;
}
A [ index ] = y_bit ;
sink_cell - > setPort ( ID : : A , A ) ;
sink_cell - > setParam ( ID ( LUT ) , mask ) ;
}
// Since we have rewritten all sinks (which we know
// to be only LUTs) to be after the inverter, we can
// go ahead and clone the LUT with the expectation
// that the original driving LUT will become dangling
// and get cleaned away
clone_lut :
driver_mask = driver_lut - > getParam ( ID ( LUT ) ) ;
for ( auto & b : driver_mask . bits ) {
if ( b = = RTLIL : : State : : S0 ) b = RTLIL : : State : : S1 ;
else if ( b = = RTLIL : : State : : S1 ) b = RTLIL : : State : : S0 ;
}
auto cell = module - > addLut ( NEW_ID ,
driver_lut - > getPort ( ID : : A ) ,
y_bit ,
driver_mask ) ;
for ( auto & bit : cell - > connections_ . at ( ID : : A ) ) {
bit . wire = module - > wires_ . at ( remap_name ( bit . wire - > name ) ) ;
bit2sinks [ bit ] . push_back ( cell ) ;
}
}
//log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
log ( " ABC RESULTS: input signals: %8d \n " , in_wires ) ;
log ( " ABC RESULTS: output signals: %8d \n " , out_wires ) ;
design - > remove ( mapped_mod ) ;
}
2019-12-31 00:56:19 -06:00
struct Abc9OpsPass : public Pass {
Abc9OpsPass ( ) : Pass ( " abc9_ops " , " helper functions for ABC9 " ) { }
2019-12-28 07:07:46 -06:00
void help ( ) YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " abc9_ops [options] [selection] \n " ) ;
log ( " \n " ) ;
2020-01-14 14:25:45 -06:00
log ( " This pass contains a set of supporting operations for use during ABC technology \n " ) ;
log ( " mapping, and is expected to be called in conjunction with other operations from \n " ) ;
log ( " the `abc9' script pass. Only fully-selected modules are supported. \n " ) ;
log ( " \n " ) ;
2020-01-14 15:21:58 -06:00
log ( " -check \n " ) ;
log ( " check that the design is valid, e.g. (* abc9_box_id *) values are unique, \n " ) ;
log ( " (* abc9_carry *) is only given for one input/output port, etc. \n " ) ;
log ( " \n " ) ;
log ( " -prep_delays \n " ) ;
log ( " insert `$__ABC9_DELAY' blackbox cells into the design to account for \n " ) ;
log ( " certain delays, e.g. (* abc9_required *) values. \n " ) ;
log ( " \n " ) ;
2020-01-14 14:25:45 -06:00
log ( " -mark_scc \n " ) ;
log ( " for an arbitrarily chosen cell in each unique SCC of each selected module \n " ) ;
log ( " (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all \n " ) ;
log ( " wires driven by this cell's outputs with a (* keep *) attribute in order \n " ) ;
log ( " to break the SCC. this temporary attribute will be removed on -reintegrate. \n " ) ;
log ( " \n " ) ;
log ( " -prep_xaiger \n " ) ;
log ( " prepare the design for XAIGER output. this includes computing the \n " ) ;
log ( " topological ordering of ABC9 boxes, as well as preparing the \n " ) ;
log ( " '<module-name>$holes' module that contains the logic behaviour of ABC9 \n " ) ;
log ( " whiteboxes. \n " ) ;
log ( " \n " ) ;
2020-01-14 14:40:36 -06:00
log ( " -dff \n " ) ;
2020-02-13 13:15:59 -06:00
log ( " consider flop cells (those instantiating modules marked with (* abc9_flop *)) \n " ) ;
log ( " during -prep_{delays,xaiger,box}. \n " ) ;
2020-01-14 14:40:36 -06:00
log ( " \n " ) ;
log ( " -prep_dff \n " ) ;
log ( " compute the clock domain and initial value of each flop in the design. \n " ) ;
log ( " process the '$holes' module to support clock-enable functionality. \n " ) ;
log ( " \n " ) ;
2020-02-11 10:34:13 -06:00
log ( " -prep_lut <maxlut> \n " ) ;
2020-02-11 13:38:49 -06:00
log ( " pre-compute the lut library by analysing all modules marked with \n " ) ;
log ( " (* abc9_lut=<area> *). \n " ) ;
2020-02-11 10:34:13 -06:00
log ( " \n " ) ;
log ( " -write_lut <dst> \n " ) ;
2020-02-11 10:54:13 -06:00
log ( " write the pre-computed lut library to <dst>. \n " ) ;
2020-02-11 10:34:13 -06:00
log ( " \n " ) ;
2020-02-11 13:38:49 -06:00
log ( " -prep_box \n " ) ;
log ( " pre-compute the box library by analysing all modules marked with \n " ) ;
2020-02-12 17:25:30 -06:00
log ( " (* abc9_box *). \n " ) ;
2020-02-11 10:54:13 -06:00
log ( " \n " ) ;
log ( " -write_box <dst> \n " ) ;
log ( " write the pre-computed box library to <dst>. \n " ) ;
2020-01-14 15:21:58 -06:00
log ( " \n " ) ;
2020-01-14 14:40:36 -06:00
log ( " -reintegrate \n " ) ;
log ( " for each selected module, re-intergrate the module '<module-name>$abc9' \n " ) ;
log ( " by first recovering ABC9 boxes, and then stitching in the remaining primary \n " ) ;
log ( " inputs and outputs. \n " ) ;
log ( " \n " ) ;
2019-12-28 07:07:46 -06:00
}
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) YS_OVERRIDE
{
log_header ( design , " Executing ABC9_OPS pass (helper functions for ABC9). \n " ) ;
2020-01-10 13:45:41 -06:00
bool check_mode = false ;
2020-01-14 15:21:58 -06:00
bool prep_delays_mode = false ;
2020-01-14 01:42:27 -06:00
bool mark_scc_mode = false ;
2020-01-10 13:45:41 -06:00
bool prep_dff_mode = false ;
2020-01-14 14:25:45 -06:00
bool prep_xaiger_mode = false ;
2020-02-11 10:34:13 -06:00
bool prep_lut_mode = false ;
2020-02-11 13:38:49 -06:00
bool prep_box_mode = false ;
2020-01-06 17:52:59 -06:00
bool reintegrate_mode = false ;
2020-01-04 11:17:01 -06:00
bool dff_mode = false ;
2020-02-11 10:34:13 -06:00
std : : string write_lut_dst ;
int maxlut = 0 ;
2020-02-11 13:38:49 -06:00
std : : string write_box_dst ;
2019-12-28 07:07:46 -06:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
std : : string arg = args [ argidx ] ;
2020-01-10 13:45:41 -06:00
if ( arg = = " -check " ) {
check_mode = true ;
continue ;
}
2020-01-14 01:42:27 -06:00
if ( arg = = " -mark_scc " ) {
mark_scc_mode = true ;
2019-12-28 07:07:46 -06:00
continue ;
}
2019-12-30 18:36:33 -06:00
if ( arg = = " -prep_dff " ) {
prep_dff_mode = true ;
continue ;
}
2020-01-14 14:25:45 -06:00
if ( arg = = " -prep_xaiger " ) {
prep_xaiger_mode = true ;
2019-12-30 20:00:49 -06:00
continue ;
}
2020-01-14 15:21:58 -06:00
if ( arg = = " -prep_delays " ) {
prep_delays_mode = true ;
2020-01-10 13:45:41 -06:00
continue ;
}
2020-02-11 10:34:13 -06:00
if ( arg = = " -prep_lut " & & argidx + 1 < args . size ( ) ) {
prep_lut_mode = true ;
maxlut = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2020-02-11 10:54:13 -06:00
if ( arg = = " -maxlut " & & argidx + 1 < args . size ( ) ) {
continue ;
}
2020-02-11 10:34:13 -06:00
if ( arg = = " -write_lut " & & argidx + 1 < args . size ( ) ) {
write_lut_dst = args [ + + argidx ] ;
rewrite_filename ( write_lut_dst ) ;
continue ;
}
2020-02-11 13:38:49 -06:00
if ( arg = = " -prep_box " ) {
prep_box_mode = true ;
2020-02-11 10:34:13 -06:00
continue ;
}
2020-02-11 10:54:13 -06:00
if ( arg = = " -write_box " & & argidx + 1 < args . size ( ) ) {
2020-01-10 13:45:41 -06:00
write_box_dst = args [ + + argidx ] ;
rewrite_filename ( write_box_dst ) ;
continue ;
}
2020-01-06 17:52:59 -06:00
if ( arg = = " -reintegrate " ) {
reintegrate_mode = true ;
continue ;
}
2020-01-04 11:17:01 -06:00
if ( arg = = " -dff " ) {
dff_mode = true ;
continue ;
}
2019-12-28 07:07:46 -06:00
break ;
}
extra_args ( args , argidx , design ) ;
2020-02-11 13:38:49 -06:00
if ( ! ( check_mode | | mark_scc_mode | | prep_delays_mode | | prep_xaiger_mode | | prep_dff_mode | | prep_lut_mode | | prep_box_mode | | ! write_lut_dst . empty ( ) | | ! write_box_dst . empty ( ) | | reintegrate_mode ) )
2020-02-11 10:54:13 -06:00
log_cmd_error ( " At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified. \n " ) ;
2020-01-11 10:42:58 -06:00
2020-02-13 13:15:59 -06:00
if ( dff_mode & & ! prep_delays_mode & & ! prep_xaiger_mode & & ! prep_box_mode )
log_cmd_error ( " '-dff' option is only relevant for -prep_{delay,xaiger,box}. \n " ) ;
2020-01-10 13:45:41 -06:00
if ( check_mode )
check ( design ) ;
2020-01-14 15:21:58 -06:00
if ( prep_delays_mode )
2020-02-13 13:15:59 -06:00
prep_delays ( design , dff_mode ) ;
2020-02-11 10:34:13 -06:00
if ( prep_lut_mode )
prep_lut ( design , maxlut ) ;
2020-02-11 13:38:49 -06:00
if ( prep_box_mode )
2020-02-13 13:15:59 -06:00
prep_box ( design , dff_mode ) ;
2020-01-10 13:45:41 -06:00
2019-12-28 07:07:46 -06:00
for ( auto mod : design - > selected_modules ( ) ) {
2019-12-30 21:23:54 -06:00
if ( mod - > get_bool_attribute ( " \\ abc9_holes " ) )
continue ;
2019-12-30 20:46:22 -06:00
if ( mod - > processes . size ( ) > 0 ) {
log ( " Skipping module %s as it contains processes. \n " , log_id ( mod ) ) ;
continue ;
}
2020-01-11 10:42:58 -06:00
if ( ! design - > selected_whole_module ( mod ) )
log_error ( " Can't handle partially selected module %s! \n " , log_id ( mod ) ) ;
2020-02-11 10:34:13 -06:00
if ( ! write_lut_dst . empty ( ) )
write_lut ( mod , write_lut_dst ) ;
if ( ! write_box_dst . empty ( ) )
2020-02-11 10:54:13 -06:00
write_box ( mod , write_box_dst ) ;
2020-01-14 01:42:27 -06:00
if ( mark_scc_mode )
mark_scc ( mod ) ;
2019-12-30 18:36:33 -06:00
if ( prep_dff_mode )
prep_dff ( mod ) ;
2020-01-14 14:25:45 -06:00
if ( prep_xaiger_mode )
prep_xaiger ( mod , dff_mode ) ;
2020-01-06 17:52:59 -06:00
if ( reintegrate_mode )
reintegrate ( mod ) ;
2019-12-28 07:07:46 -06:00
}
}
2019-12-31 00:56:19 -06:00
} Abc9OpsPass ;
2019-12-28 07:07:46 -06:00
PRIVATE_NAMESPACE_END