2019-12-28 07:07:46 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2019-12-28 07:07:46 -06:00
* 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"
2020-02-14 13:11:34 -06:00
# include "kernel/timinginfo.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-04-21 14:22:39 -05:00
void check ( RTLIL : : Design * design , bool dff_mode )
2020-01-10 13:45:41 -06:00
{
dict < IdString , IdString > box_lookup ;
for ( auto m : design - > modules ( ) ) {
2020-04-02 11:51:32 -05:00
auto flop = m - > get_bool_attribute ( ID : : abc9_flop ) ;
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 ) ;
2020-04-02 11:51:32 -05:00
if ( w - > get_bool_attribute ( ID : : abc9_carry ) ) {
2020-01-10 13:45:41 -06:00
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-04-21 14:22:39 -05:00
if ( dff_mode ) {
2020-05-13 20:02:05 -05:00
static pool < IdString > unsupported {
2020-04-21 14:22:39 -05:00
ID ( $ adff ) , ID ( $ dlatch ) , ID ( $ dlatchsr ) , ID ( $ sr ) ,
ID ( $ _DFF_NN0_ ) , ID ( $ _DFF_NN1_ ) , ID ( $ _DFF_NP0_ ) , ID ( $ _DFF_NP1_ ) ,
ID ( $ _DFF_PN0_ ) , ID ( $ _DFF_PN1_ ) , ID ( $ _DFF_PP0_ ) , ID ( $ _DFF_PP1_ ) ,
ID ( $ _DLATCH_N_ ) , ID ( $ _DLATCH_P_ ) ,
ID ( $ _DLATCHSR_NNN_ ) , ID ( $ _DLATCHSR_NNP_ ) , ID ( $ _DLATCHSR_NPN_ ) , ID ( $ _DLATCHSR_NPP_ ) ,
ID ( $ _DLATCHSR_PNN_ ) , ID ( $ _DLATCHSR_PNP_ ) , ID ( $ _DLATCHSR_PPN_ ) , ID ( $ _DLATCHSR_PPP_ ) ,
ID ( $ _SR_NN_ ) , ID ( $ _SR_NP_ ) , ID ( $ _SR_PN_ ) , ID ( $ _SR_PP_ )
} ;
pool < IdString > processed ;
for ( auto module : design - > selected_modules ( ) )
for ( auto cell : module - > cells ( ) ) {
auto inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
2020-05-13 23:56:06 -05:00
IdString derived_type ;
Module * derived_module ;
if ( cell - > parameters . empty ( ) ) {
derived_type = cell - > type ;
derived_module = inst_module ;
}
else {
2020-05-29 19:33:10 -05:00
// Check potential (since its value may depend on a parameter,
// but not its existence)
if ( ! inst_module - > has_attribute ( ID : : abc9_flop ) )
continue ;
2020-05-13 23:56:06 -05:00
derived_type = inst_module - > derive ( design , cell - > parameters ) ;
derived_module = design - > module ( derived_type ) ;
log_assert ( derived_module ) ;
}
2020-05-13 20:02:05 -05:00
if ( ! derived_module - > get_bool_attribute ( ID : : abc9_flop ) )
continue ;
if ( derived_module - > get_blackbox_attribute ( true /* ignore_wb */ ) )
2020-04-21 14:22:39 -05:00
log_error ( " Module '%s' with (* abc9_flop *) is a blackbox. \n " , log_id ( derived_type ) ) ;
if ( derived_module - > has_processes ( ) )
Pass : : call_on_module ( design , derived_module , " proc " ) ;
2020-05-13 20:02:05 -05:00
bool found = false ;
for ( auto derived_cell : derived_module - > cells ( ) ) {
if ( derived_cell - > type . in ( ID ( $ dff ) , ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) ) {
if ( found )
2020-05-30 10:57:48 -05:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell. \n " , log_id ( derived_module ) ) ;
2020-05-13 20:02:05 -05:00
found = true ;
2020-04-21 14:22:39 -05:00
2020-05-13 20:02:05 -05:00
SigBit Q = derived_cell - > getPort ( ID : : Q ) ;
log_assert ( GetSize ( Q . wire ) = = 1 ) ;
2020-04-21 14:22:39 -05:00
2020-05-13 20:02:05 -05:00
if ( ! Q . wire - > port_output )
2020-05-30 10:57:48 -05:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains a %s cell where its 'Q' port does not drive a module output. \n " , log_id ( derived_module ) , log_id ( derived_cell - > type ) ) ;
2020-04-21 14:22:39 -05:00
2020-05-13 20:02:05 -05:00
Const init = Q . wire - > attributes . at ( ID : : init , State : : Sx ) ;
log_assert ( GetSize ( init ) = = 1 ) ;
}
else if ( unsupported . count ( derived_cell - > type ) )
2020-05-30 10:57:48 -05:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis. \n " , log_id ( derived_module ) , log_id ( derived_cell - > type ) ) ;
2020-04-21 14:22:39 -05:00
}
}
}
2020-01-10 13:45:41 -06:00
}
2020-04-21 14:22:39 -05:00
void prep_hier ( RTLIL : : Design * design , bool dff_mode )
2019-12-28 07:07:46 -06:00
{
2020-04-21 14:22:39 -05:00
auto r = saved_designs . emplace ( " $abc9_unmap " , nullptr ) ;
if ( r . second )
r . first - > second = new Design ;
Design * unmap_design = r . first - > second ;
for ( auto module : design - > selected_modules ( ) )
for ( auto cell : module - > cells ( ) ) {
auto inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
2020-05-13 23:56:06 -05:00
IdString derived_type ;
Module * derived_module ;
if ( cell - > parameters . empty ( ) ) {
derived_type = cell - > type ;
derived_module = inst_module ;
}
else {
derived_type = inst_module - > derive ( design , cell - > parameters ) ;
derived_module = design - > module ( derived_type ) ;
}
2020-04-21 14:22:39 -05:00
2020-05-13 23:56:06 -05:00
if ( derived_module - > get_bool_attribute ( ID : : abc9_flop ) ) {
if ( ! dff_mode )
continue ;
}
else {
2022-03-24 09:34:34 -05:00
bool has_timing = false ;
for ( auto derived_cell : derived_module - > cells ( ) ) {
if ( derived_cell - > type . in ( ID ( $ specify2 ) , ID ( $ specify3 ) , ID ( $ specrule ) ) ) {
// If the module contains timing; then we potentially care about deriving its content too,
// as timings (or associated port widths) could be dependent on parameters.
has_timing = true ;
break ;
}
}
if ( ! derived_module - > get_bool_attribute ( ID : : abc9_box ) & & ! derived_module - > get_bool_attribute ( ID : : abc9_bypass ) & & ! has_timing ) {
2021-09-09 12:05:55 -05:00
if ( unmap_design - > module ( derived_type ) ) {
// If derived_type is present in unmap_design, it means that it was processed previously, but found to be incompatible -- e.g. if
// it contained a non-zero initial state. In this case, continue to replace the cell type/parameters so that it has the same properties
// as a compatible type, yet will be safely unmapped later
cell - > type = derived_type ;
cell - > parameters . clear ( ) ;
}
2020-05-13 23:56:06 -05:00
continue ;
2021-09-09 12:05:55 -05:00
}
2020-05-13 23:56:06 -05:00
}
2020-04-21 14:22:39 -05:00
if ( ! unmap_design - > module ( derived_type ) ) {
if ( derived_module - > has_processes ( ) )
Pass : : call_on_module ( design , derived_module , " proc " ) ;
if ( derived_module - > get_bool_attribute ( ID : : abc9_flop ) ) {
for ( auto derived_cell : derived_module - > cells ( ) )
if ( derived_cell - > type . in ( ID ( $ dff ) , ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) ) {
SigBit Q = derived_cell - > getPort ( ID : : Q ) ;
Const init = Q . wire - > attributes . at ( ID : : init , State : : Sx ) ;
log_assert ( GetSize ( init ) = = 1 ) ;
// Block sequential synthesis on cells with (* init *) != 1'b0
// because ABC9 doesn't support them
if ( init ! = State : : S0 ) {
2020-05-30 10:57:48 -05:00
log_warning ( " Whitebox '%s' with (* abc9_flop *) contains a %s cell with non-zero initial state -- this is not supported for ABC9 sequential synthesis. Treating as a blackbox. \n " , log_id ( derived_module ) , log_id ( derived_cell - > type ) ) ;
2020-04-21 14:30:25 -05:00
derived_module - > set_bool_attribute ( ID : : abc9_flop , false ) ;
2020-04-21 14:22:39 -05:00
}
break ;
}
}
else if ( derived_module - > get_bool_attribute ( ID : : abc9_box ) ) {
for ( auto derived_cell : derived_module - > cells ( ) )
2021-05-22 12:14:13 -05:00
if ( derived_cell - > is_mem_cell ( ) | | RTLIL : : builtin_ff_cell_types ( ) . count ( derived_cell - > type ) ) {
2020-05-13 23:56:06 -05:00
derived_module - > set_bool_attribute ( ID : : abc9_box , false ) ;
derived_module - > set_bool_attribute ( ID : : abc9_bypass ) ;
2020-04-21 14:22:39 -05:00
break ;
}
}
if ( derived_type ! = cell - > type ) {
auto unmap_module = unmap_design - > addModule ( derived_type ) ;
for ( auto port : derived_module - > ports ) {
auto w = unmap_module - > addWire ( port , derived_module - > wire ( port ) ) ;
2020-05-14 04:09:13 -05:00
// Do not propagate (* init *) values into the box,
// in fact, remove it from outside too
2020-05-29 19:17:40 -05:00
if ( w - > port_output )
w - > attributes . erase ( ID : : init ) ;
2020-04-21 14:22:39 -05:00
}
unmap_module - > ports = derived_module - > ports ;
unmap_module - > check ( ) ;
auto replace_cell = unmap_module - > addCell ( ID : : _TECHMAP_REPLACE_ , cell - > type ) ;
for ( const auto & conn : cell - > connections ( ) ) {
auto w = unmap_module - > wire ( conn . first ) ;
log_assert ( w ) ;
replace_cell - > setPort ( conn . first , w ) ;
}
replace_cell - > parameters = cell - > parameters ;
}
2019-12-28 07:07:46 -06:00
}
2020-04-21 14:22:39 -05:00
cell - > type = derived_type ;
cell - > parameters . clear ( ) ;
2019-12-28 07:07:46 -06:00
}
}
2020-04-21 14:22:39 -05:00
void prep_bypass ( RTLIL : : Design * design )
2020-04-13 11:38:07 -05:00
{
2020-04-21 14:22:39 -05:00
auto r = saved_designs . emplace ( " $abc9_map " , nullptr ) ;
if ( r . second )
r . first - > second = new Design ;
Design * map_design = r . first - > second ;
2020-04-14 13:38:44 -05:00
2020-04-21 14:22:39 -05:00
r = saved_designs . emplace ( " $abc9_unmap " , nullptr ) ;
if ( r . second )
r . first - > second = new Design ;
Design * unmap_design = r . first - > second ;
2020-04-13 11:38:07 -05:00
2020-04-21 14:22:39 -05:00
pool < IdString > processed ;
2020-04-16 12:40:33 -05:00
for ( auto module : design - > selected_modules ( ) )
2020-04-13 11:38:07 -05:00
for ( auto cell : module - > cells ( ) ) {
2020-04-21 14:22:39 -05:00
if ( ! processed . insert ( cell - > type ) . second )
continue ;
2020-04-13 11:38:07 -05:00
auto inst_module = design - > module ( cell - > type ) ;
2020-04-21 14:22:39 -05:00
if ( ! inst_module )
continue ;
2020-04-21 16:12:28 -05:00
if ( ! inst_module - > get_bool_attribute ( ID : : abc9_bypass ) )
2020-04-21 14:22:39 -05:00
continue ;
2020-04-21 17:44:56 -05:00
log_assert ( ! inst_module - > get_blackbox_attribute ( true /* ignore_wb */ ) ) ;
2020-05-13 23:56:06 -05:00
log_assert ( cell - > parameters . empty ( ) ) ;
2020-04-21 14:22:39 -05:00
// The idea is to create two techmap designs, one which maps:
//
// box u0 (.i(i), .o(o));
//
// to
//
// wire $abc9$o;
// box u0 (.i(i), .o($abc9_byp$o));
// box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
//
// the purpose being to move the (* abc9_box *) status from 'box'
// (which is stateful) to 'box_$abc9_byp' (which becomes a new
// combinatorial black- (not white-) box with all state elements
// removed). This has the effect of preserving any combinatorial
// paths through an otherwise sequential primitive -- e.g. LUTRAMs.
//
// The unmap design performs the reverse:
//
// wire $abc9$o;
// box u0 (.i(i), .o($abc9_byp$o));
// box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
//
// to:
//
// wire $abc9$o;
// box u0 (.i(i), .o($abc9_byp$o));
// assign o = $abc9_byp$o;
2020-05-13 20:02:05 -05:00
// Copy inst_module into map_design, with the same interface
2020-04-21 14:22:39 -05:00
// and duplicate $abc9$* wires for its output ports
auto map_module = map_design - > addModule ( cell - > type ) ;
for ( auto port_name : inst_module - > ports ) {
auto w = map_module - > addWire ( port_name , inst_module - > wire ( port_name ) ) ;
if ( w - > port_output )
w - > attributes . erase ( ID : : init ) ;
}
map_module - > ports = inst_module - > ports ;
map_module - > check ( ) ;
map_module - > set_bool_attribute ( ID : : whitebox ) ;
// Create the bypass module in the user design, which has the same
// interface as the derived module but with additional input
// ports driven by the outputs of the replaced cell
auto bypass_module = design - > addModule ( cell - > type . str ( ) + " _$abc9_byp " ) ;
for ( auto port_name : inst_module - > ports ) {
auto port = inst_module - > wire ( port_name ) ;
if ( ! port - > port_output )
continue ;
auto dst = bypass_module - > addWire ( port_name , port ) ;
auto src = bypass_module - > addWire ( " $abc9byp$ " + port_name . str ( ) , GetSize ( port ) ) ;
src - > port_input = true ;
// For these new input ports driven by the replaced
// cell, then create a new simple-path specify entry:
// (input => output) = 0
auto specify = bypass_module - > addCell ( NEW_ID , ID ( $ specify2 ) ) ;
specify - > setPort ( ID : : EN , State : : S1 ) ;
specify - > setPort ( ID : : SRC , src ) ;
specify - > setPort ( ID : : DST , dst ) ;
specify - > setParam ( ID : : FULL , 0 ) ;
specify - > setParam ( ID : : SRC_WIDTH , GetSize ( src ) ) ;
specify - > setParam ( ID : : DST_WIDTH , GetSize ( dst ) ) ;
specify - > setParam ( ID : : SRC_DST_PEN , 0 ) ;
specify - > setParam ( ID : : SRC_DST_POL , 0 ) ;
specify - > setParam ( ID : : T_RISE_MIN , 0 ) ;
specify - > setParam ( ID : : T_RISE_TYP , 0 ) ;
specify - > setParam ( ID : : T_RISE_MAX , 0 ) ;
specify - > setParam ( ID : : T_FALL_MIN , 0 ) ;
specify - > setParam ( ID : : T_FALL_TYP , 0 ) ;
specify - > setParam ( ID : : T_FALL_MAX , 0 ) ;
}
bypass_module - > set_bool_attribute ( ID : : blackbox ) ;
bypass_module - > set_bool_attribute ( ID : : abc9_box ) ;
// Copy any 'simple' (combinatorial) specify paths from
// the derived module into the bypass module, if EN
// is not false and SRC/DST are driven only by
// module ports; create new input port if one doesn't
// already exist
for ( auto cell : inst_module - > cells ( ) ) {
if ( cell - > type ! = ID ( $ specify2 ) )
continue ;
auto EN = cell - > getPort ( ID : : EN ) . as_bit ( ) ;
SigBit newEN ;
if ( ! EN . wire & & EN ! = State : : S1 )
2020-04-13 19:30:29 -05:00
continue ;
2020-04-21 14:22:39 -05:00
auto SRC = cell - > getPort ( ID : : SRC ) ;
for ( const auto & c : SRC . chunks ( ) )
if ( c . wire & & ! c . wire - > port_input ) {
SRC = SigSpec ( ) ;
break ;
}
if ( SRC . empty ( ) )
continue ;
auto DST = cell - > getPort ( ID : : DST ) ;
for ( const auto & c : DST . chunks ( ) )
if ( c . wire & & ! c . wire - > port_output ) {
DST = SigSpec ( ) ;
break ;
}
if ( DST . empty ( ) )
continue ;
auto rw = [ bypass_module ] ( RTLIL : : SigSpec & sig )
{
SigSpec new_sig ;
for ( auto c : sig . chunks ( ) ) {
if ( c . wire ) {
auto port = bypass_module - > wire ( c . wire - > name ) ;
if ( ! port )
port = bypass_module - > addWire ( c . wire - > name , c . wire ) ;
c . wire = port ;
}
new_sig . append ( std : : move ( c ) ) ;
}
sig = std : : move ( new_sig ) ;
} ;
auto specify = bypass_module - > addCell ( NEW_ID , cell ) ;
specify - > rewrite_sigspecs ( rw ) ;
}
bypass_module - > fixup_ports ( ) ;
// Create an _TECHMAP_REPLACE_ cell identical to the original cell,
// and a bypass cell that has the same inputs/outputs as the
// original cell, but with additional inputs taken from the
// replaced cell
auto replace_cell = map_module - > addCell ( ID : : _TECHMAP_REPLACE_ , cell - > type ) ;
auto bypass_cell = map_module - > addCell ( NEW_ID , cell - > type . str ( ) + " _$abc9_byp " ) ;
for ( const auto & conn : cell - > connections ( ) ) {
auto port = map_module - > wire ( conn . first ) ;
if ( cell - > input ( conn . first ) ) {
replace_cell - > setPort ( conn . first , port ) ;
if ( bypass_module - > wire ( conn . first ) )
bypass_cell - > setPort ( conn . first , port ) ;
}
if ( cell - > output ( conn . first ) ) {
bypass_cell - > setPort ( conn . first , port ) ;
auto n = " $abc9byp$ " + conn . first . str ( ) ;
auto w = map_module - > addWire ( n , GetSize ( conn . second ) ) ;
replace_cell - > setPort ( conn . first , w ) ;
bypass_cell - > setPort ( n , w ) ;
2020-04-13 19:30:29 -05:00
}
2020-04-13 11:38:07 -05:00
}
2020-04-21 14:22:39 -05:00
// Lastly, create a new module in the unmap_design that shorts
// out the bypass cell back to leave the replace cell behind
// driving the outputs
auto unmap_module = unmap_design - > addModule ( cell - > type . str ( ) + " _$abc9_byp " ) ;
for ( auto port_name : inst_module - > ports ) {
auto w = unmap_module - > addWire ( port_name , inst_module - > wire ( port_name ) ) ;
if ( w - > port_output ) {
w - > attributes . erase ( ID : : init ) ;
auto w2 = unmap_module - > addWire ( " $abc9byp$ " + port_name . str ( ) , GetSize ( w ) ) ;
w2 - > port_input = true ;
unmap_module - > connect ( w , w2 ) ;
}
}
unmap_module - > fixup_ports ( ) ;
2021-09-09 12:06:31 -05:00
design - > scratchpad_set_bool ( " abc9_ops.prep_bypass.did_something " , true ) ;
2020-04-13 11:38:07 -05:00
}
2020-04-21 14:22:39 -05:00
}
void prep_dff ( RTLIL : : Design * design )
{
auto r = design - > selection_vars . insert ( std : : make_pair ( ID ( $ abc9_flops ) , RTLIL : : Selection ( false ) ) ) ;
auto & modules_sel = r . first - > second ;
2020-04-14 13:38:44 -05:00
2020-04-21 14:22:39 -05:00
for ( auto module : design - > selected_modules ( ) )
for ( auto cell : module - > cells ( ) ) {
if ( modules_sel . selected_whole_module ( cell - > type ) )
continue ;
auto inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
2020-04-21 16:12:28 -05:00
if ( ! inst_module - > get_bool_attribute ( ID : : abc9_flop ) )
2020-04-21 14:22:39 -05:00
continue ;
2020-05-13 20:02:05 -05:00
log_assert ( ! inst_module - > get_blackbox_attribute ( true /* ignore_wb */ ) ) ;
2021-09-09 12:05:55 -05:00
if ( ! cell - > parameters . empty ( ) )
{
// At this stage of the ABC9 flow, cells instantiating (* abc9_flop *) modules must not contain any parameters -- instead it should
// be instantiating the derived module which will have had any parameters constant-propagated.
// This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design.
// Please file a bug report!
log_error ( " Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_flop *) \n " , log_id ( cell - > name ) , log_id ( cell - > type ) ) ;
}
2020-05-13 20:02:05 -05:00
modules_sel . select ( inst_module ) ;
2020-04-21 14:22:39 -05:00
}
2020-04-13 11:38:07 -05:00
}
2019-12-30 18:36:33 -06:00
2020-04-21 14:30:25 -05:00
void prep_dff_submod ( RTLIL : : Design * design )
2020-04-13 11:38:07 -05:00
{
for ( auto module : design - > modules ( ) ) {
vector < Cell * > specify_cells ;
2020-04-21 14:22:39 -05:00
SigBit Q ;
2020-04-13 19:30:29 -05:00
Cell * dff_cell = nullptr ;
2020-04-15 17:41:55 -05:00
2020-04-21 14:22:39 -05:00
if ( ! module - > get_bool_attribute ( ID : : abc9_flop ) )
2020-04-15 17:41:55 -05:00
continue ;
2020-04-13 11:38:07 -05:00
for ( auto cell : module - > cells ( ) )
if ( cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) ) {
2020-04-21 14:22:39 -05:00
log_assert ( ! dff_cell ) ;
2020-04-13 19:30:29 -05:00
dff_cell = cell ;
Q = cell - > getPort ( ID : : Q ) ;
2020-04-13 11:38:07 -05:00
log_assert ( GetSize ( Q . wire ) = = 1 ) ;
}
2020-04-21 14:22:39 -05:00
else if ( cell - > type . in ( ID ( $ specify3 ) , ID ( $ specrule ) ) )
2020-04-13 11:38:07 -05:00
specify_cells . emplace_back ( cell ) ;
2020-04-21 14:22:39 -05:00
log_assert ( dff_cell ) ;
2020-04-13 11:38:07 -05:00
2020-04-21 19:25:15 -05:00
// Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that:
// (a) flop box will have an output
// (b) $_DFF_[NP]_.Q will be present as an input
2020-04-21 14:22:39 -05:00
SigBit D = module - > addWire ( NEW_ID ) ;
2020-04-21 19:25:15 -05:00
module - > addMuxGate ( NEW_ID , dff_cell - > getPort ( ID : : D ) , Q , State : : S0 , D ) ;
2020-04-16 16:03:54 -05:00
dff_cell - > setPort ( ID : : D , D ) ;
2020-04-13 19:30:29 -05:00
2020-04-15 17:41:55 -05:00
// Rewrite $specify cells that end with $_DFF_[NP]_.Q
// to $_DFF_[NP]_.D since it will be moved into
// the submodule
for ( auto cell : specify_cells ) {
auto DST = cell - > getPort ( ID : : DST ) ;
DST . replace ( Q , D ) ;
cell - > setPort ( ID : : DST , DST ) ;
2020-04-13 11:38:07 -05:00
}
2020-04-15 17:41:55 -05:00
2020-04-21 14:30:25 -05:00
design - > scratchpad_set_bool ( " abc9_ops.prep_dff_submod.did_something " , true ) ;
2020-01-04 11:17:01 -06:00
}
2020-04-13 11:38:07 -05:00
}
2019-12-30 21:23:54 -06:00
2020-04-13 11:38:07 -05:00
void prep_dff_unmap ( RTLIL : : Design * design )
{
2020-04-14 13:38:44 -05:00
Design * unmap_design = saved_designs . at ( " $abc9_unmap " ) ;
2020-04-13 11:38:07 -05:00
2020-04-21 14:22:39 -05:00
for ( auto module : design - > modules ( ) ) {
if ( ! module - > get_bool_attribute ( ID : : abc9_flop ) | | module - > get_bool_attribute ( ID : : abc9_box ) )
continue ;
2020-04-13 11:38:07 -05:00
2020-04-21 19:25:15 -05:00
// Make sure the box module has all the same ports present on flop cell
auto replace_cell = module - > cell ( ID : : _TECHMAP_REPLACE_ ) ;
log_assert ( replace_cell ) ;
auto box_module = design - > module ( module - > name . str ( ) + " _$abc9_flop " ) ;
log_assert ( box_module ) ;
2020-04-21 14:22:39 -05:00
for ( auto port_name : module - > ports ) {
2020-04-21 19:25:15 -05:00
auto port = module - > wire ( port_name ) ;
auto box_port = box_module - > wire ( port_name ) ;
if ( box_port ) {
// Do not propagate init -- already captured by box
box_port - > attributes . erase ( ID : : init ) ;
continue ;
}
log_assert ( port - > port_input ) ;
box_module - > addWire ( port_name , port ) ;
replace_cell - > setPort ( port_name , port ) ;
2020-04-21 14:22:39 -05:00
}
2020-04-21 19:25:15 -05:00
box_module - > fixup_ports ( ) ;
2020-04-21 14:22:39 -05:00
2020-04-21 19:25:15 -05:00
auto unmap_module = unmap_design - > addModule ( box_module - > name ) ;
replace_cell = unmap_module - > addCell ( ID : : _TECHMAP_REPLACE_ , module - > name ) ;
2020-04-21 14:22:39 -05:00
for ( auto port_name : box_module - > ports ) {
2020-04-21 19:25:15 -05:00
auto w = unmap_module - > addWire ( port_name , box_module - > wire ( port_name ) ) ;
if ( module - > wire ( port_name ) )
replace_cell - > setPort ( port_name , w ) ;
2020-04-13 15:12:37 -05:00
}
2020-04-21 14:22:39 -05:00
unmap_module - > ports = box_module - > ports ;
2020-04-13 11:38:07 -05:00
unmap_module - > check ( ) ;
2020-04-21 14:22:39 -05:00
}
}
2020-04-13 11:38:07 -05:00
2021-03-30 00:01:57 -05:00
void break_scc ( RTLIL : : Module * module )
2020-04-21 14:22:39 -05:00
{
// For every unique SCC found, (arbitrarily) find the first
2021-03-30 00:01:57 -05:00
// cell in the component, and interrupt all its output connections
// with the $__ABC9_SCC_BREAKER cell
// Do not break SCCs which have a cell instantiating an abc9_bypass-able
// module (but which wouldn't have been bypassed)
auto design = module - > design ;
pool < RTLIL : : Cell * > scc_cells ;
2020-04-21 14:22:39 -05:00
pool < RTLIL : : Const > ids_seen ;
for ( auto cell : module - > cells ( ) ) {
auto it = cell - > attributes . find ( ID : : abc9_scc_id ) ;
if ( it = = cell - > attributes . end ( ) )
continue ;
2021-03-30 00:01:57 -05:00
scc_cells . insert ( cell ) ;
auto inst_module = design - > module ( cell - > type ) ;
if ( inst_module & & inst_module - > has_attribute ( ID : : abc9_bypass ) )
ids_seen . insert ( it - > second ) ;
}
SigSpec I , O ;
for ( auto cell : scc_cells ) {
auto it = cell - > attributes . find ( ID : : abc9_scc_id ) ;
log_assert ( it ! = cell - > attributes . end ( ) ) ;
2020-04-21 14:22:39 -05:00
auto id = it - > second ;
auto r = ids_seen . insert ( id ) ;
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 ) ) {
Wire * w = module - > addWire ( NEW_ID , GetSize ( c . second ) ) ;
2021-03-30 00:01:57 -05:00
I . append ( w ) ;
O . append ( c . second ) ;
2020-04-21 14:22:39 -05:00
c . second = w ;
}
2020-04-14 13:38:44 -05:00
}
2019-12-30 21:23:54 -06:00
}
2021-03-30 00:01:57 -05:00
if ( ! I . empty ( ) )
{
auto cell = module - > addCell ( NEW_ID , ID ( $ __ABC9_SCC_BREAKER ) ) ;
log_assert ( GetSize ( I ) = = GetSize ( O ) ) ;
cell - > setParam ( ID : : WIDTH , GetSize ( I ) ) ;
cell - > setPort ( ID : : I , std : : move ( I ) ) ;
cell - > setPort ( ID : : O , std : : move ( O ) ) ;
}
2019-12-30 18:36:33 -06:00
}
2020-05-13 20:02:05 -05:00
void prep_delays ( RTLIL : : Design * design , bool dff_mode )
{
TimingInfo timing ;
// Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
// (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
2020-05-13 23:56:06 -05:00
std : : vector < Cell * > cells ;
2020-05-13 20:02:05 -05: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 ( ) ) {
2020-05-13 23:56:06 -05:00
if ( cell - > type . in ( ID ( $ _AND_ ) , ID ( $ _NOT_ ) , ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) )
2020-05-13 20:02:05 -05:00
continue ;
2020-05-13 23:56:06 -05:00
log_assert ( ! cell - > type . begins_with ( " $paramod$__ABC9_DELAY \\ DELAY= " ) ) ;
2020-05-13 20:02:05 -05:00
RTLIL : : Module * inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
if ( ! inst_module - > get_blackbox_attribute ( ) )
continue ;
2020-05-13 23:56:06 -05:00
if ( ! cell - > parameters . empty ( ) )
continue ;
2020-05-13 20:02:05 -05:00
2020-05-13 23:56:06 -05:00
if ( inst_module - > get_bool_attribute ( ID : : abc9_box ) )
2020-05-13 20:02:05 -05:00
continue ;
2020-05-13 23:56:06 -05:00
if ( inst_module - > get_bool_attribute ( ID : : abc9_bypass ) )
2020-05-13 20:02:05 -05:00
continue ;
if ( dff_mode & & inst_module - > get_bool_attribute ( ID : : abc9_flop ) ) {
continue ; // do not add $__ABC9_DELAY boxes to flops
// as delays will be captured in the flop box
}
2020-05-13 23:56:06 -05:00
if ( ! timing . count ( cell - > type ) )
timing . setup_module ( inst_module ) ;
2020-05-13 20:02:05 -05:00
2020-05-13 23:56:06 -05:00
cells . emplace_back ( cell ) ;
2020-05-13 20:02:05 -05:00
}
}
// Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
// (or bypassed white-boxes with required times)
2020-05-13 23:56:06 -05:00
dict < int , IdString > box_cache ;
Module * delay_module = design - > module ( ID ( $ __ABC9_DELAY ) ) ;
log_assert ( delay_module ) ;
for ( auto cell : cells ) {
2020-05-13 20:02:05 -05:00
auto module = cell - > module ;
2020-05-13 23:56:06 -05:00
auto inst_module = design - > module ( cell - > type ) ;
log_assert ( inst_module ) ;
2020-05-13 20:02:05 -05:00
2021-11-24 15:21:08 -06:00
for ( auto & i : timing . at ( cell - > type ) . required ) {
auto port_wire = inst_module - > wire ( i . first . name ) ;
2020-05-13 20:02:05 -05:00
if ( ! port_wire )
2020-05-13 23:56:06 -05:00
log_error ( " Port %s in cell %s (type %s) from module %s does not actually exist " ,
2021-11-24 15:21:08 -06:00
log_id ( i . first . name ) , log_id ( cell ) , log_id ( cell - > type ) , log_id ( module ) ) ;
log_assert ( port_wire - > port_input ) ;
auto d = i . second . first ;
if ( d = = 0 )
2020-05-13 20:02:05 -05:00
continue ;
2021-11-24 15:21:08 -06:00
auto offset = i . first . offset ;
auto O = module - > addWire ( NEW_ID ) ;
auto rhs = cell - > getPort ( i . first . name ) ;
2020-05-13 20:02:05 -05:00
# ifndef NDEBUG
2021-11-24 15:21:08 -06:00
if ( ys_debug ( 1 ) ) {
static pool < std : : pair < IdString , TimingInfo : : NameBit > > seen ;
if ( seen . emplace ( cell - > type , i . first ) . second ) log ( " %s.%s[%d] abc9_required = %d \n " ,
log_id ( cell - > type ) , log_id ( i . first . name ) , offset , d ) ;
}
2020-05-13 20:02:05 -05:00
# endif
2021-11-24 15:21:08 -06:00
auto r = box_cache . insert ( d ) ;
if ( r . second ) {
r . first - > second = delay_module - > derive ( design , { { ID : : DELAY , d } } ) ;
log_assert ( r . first - > second . begins_with ( " $paramod$__ABC9_DELAY \\ DELAY= " ) ) ;
2020-05-13 20:02:05 -05:00
}
2021-11-24 15:21:08 -06:00
auto box = module - > addCell ( NEW_ID , r . first - > second ) ;
box - > setPort ( ID : : I , rhs [ offset ] ) ;
box - > setPort ( ID : : O , O ) ;
rhs [ offset ] = O ;
cell - > setPort ( i . first . name , rhs ) ;
2020-05-13 20:02:05 -05: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-04-13 11:38:07 -05:00
if ( cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) )
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-04-13 11:38:07 -05:00
auto inst_module = design - > module ( cell - > type ) ;
2020-04-21 16:12:28 -05:00
bool abc9_flop = inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_flop ) ;
2020-01-14 17:05:49 -06:00
if ( abc9_flop & & ! dff )
continue ;
2020-01-14 14:25:45 -06:00
2020-04-13 11:38:07 -05:00
if ( inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_box ) ) {
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 ) ;
2020-04-02 11:51:32 -05:00
if ( w - > get_bool_attribute ( ID : : 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 )
2021-03-30 00:01:57 -05: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 ) )
2020-02-18 10:30:41 -06:00
for ( auto user_cell : it . second )
toposort . edge ( driver_cell , user_cell ) ;
2019-12-30 20:00:49 -06:00
2020-01-11 10:42:58 -06:00
if ( ys_debug ( 1 ) )
toposort . analyze_loops = true ;
2020-06-18 20:32:48 -05:00
bool no_loops = 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-04-15 18:13:57 -05:00
auto r = saved_designs . emplace ( " $abc9_holes " , nullptr ) ;
if ( r . second )
r . first - > second = new Design ;
RTLIL : : Design * holes_design = r . first - > second ;
log_assert ( holes_design ) ;
RTLIL : : Module * holes_module = holes_design - > addModule ( module - > name ) ;
2020-01-14 14:25:45 -06:00
log_assert ( holes_module ) ;
dict < IdString , Cell * > cell_cache ;
2020-02-14 14:54:47 -06:00
TimingInfo timing ;
2020-01-14 14:25:45 -06:00
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-05-13 20:02:05 -05:00
if ( ! box_module )
continue ;
2020-05-13 23:56:06 -05:00
if ( ! box_module - > get_bool_attribute ( ID : : abc9_box ) )
2020-05-13 20:02:05 -05:00
continue ;
2021-03-05 16:13:15 -06:00
if ( ! cell - > parameters . empty ( ) )
2021-03-30 00:02:06 -05:00
{
2021-09-09 12:05:55 -05:00
// At this stage of the ABC9 flow, cells instantiating (* abc9_box *) modules must not contain any parameters -- instead it should
// be instantiating the derived module which will have had any parameters constant-propagated.
// This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design.
// Please file a bug report!
log_error ( " Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_box *) \n " , log_id ( cell_name ) , log_id ( cell - > type ) ) ;
2021-03-30 00:02:06 -05:00
}
2020-05-13 23:56:06 -05:00
log_assert ( box_module - > get_blackbox_attribute ( ) ) ;
2020-05-13 20:02:05 -05:00
cell - > attributes [ ID : : abc9_box_seq ] = box_count + + ;
2019-12-30 20:00:49 -06:00
2020-05-13 23:56:06 -05:00
auto r = cell_cache . insert ( cell - > type ) ;
2020-01-11 19:26:25 -06:00
auto & holes_cell = r . first - > second ;
if ( r . second ) {
2020-05-13 23:56:06 -05:00
if ( box_module - > get_bool_attribute ( ID : : whitebox ) ) {
2021-09-09 12:06:20 -05:00
holes_cell = holes_module - > addCell ( NEW_ID , cell - > type ) ;
2020-01-11 19:26:25 -06:00
2020-05-13 23:56:06 -05:00
if ( box_module - > has_processes ( ) )
Pass : : call_on_module ( design , box_module , " proc " ) ;
2020-01-12 17:19:41 -06:00
2020-01-11 19:26:25 -06:00
int box_inputs = 0 ;
for ( auto port_name : box_ports . at ( cell - > type ) ) {
2020-05-13 23:56:06 -05:00
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
2020-01-11 19:26:25 -06:00
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-05-13 23:56:06 -05:00
conn = holes_module - > addWire ( stringf ( " %s.%s " , cell - > type . c_str ( ) , log_id ( port_name ) ) , GetSize ( w ) ) ;
2020-01-11 19:26:25 -06:00
}
2019-12-30 20:00:49 -06:00
}
2020-05-13 23:56:06 -05:00
else // box_module is a blackbox
2020-01-11 19:26:25 -06:00
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 ) ) {
2020-05-13 23:56:06 -05:00
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
2020-01-11 19:26:25 -06:00
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-11 10:34:13 -06:00
void prep_lut ( RTLIL : : Design * design , int maxlut )
{
2020-02-18 10:30:41 -06:00
TimingInfo timing ;
2020-02-14 13:41:43 -06:00
2020-04-20 11:39:35 -05:00
struct t_lut {
IdString name ;
int area ;
std : : vector < int > delays ;
} ;
std : : map < int , t_lut > table ;
2020-02-11 10:34:13 -06:00
for ( auto module : design - > modules ( ) ) {
2020-04-02 11:51:32 -05:00
auto it = module - > attributes . find ( ID : : abc9_lut ) ;
2020-02-11 10:34:13 -06:00
if ( it = = module - > attributes . end ( ) )
continue ;
2020-02-14 13:41:43 -06:00
2020-02-14 14:01:03 -06:00
auto & t = timing . setup_module ( module ) ;
2020-02-14 13:41:43 -06:00
2020-02-18 10:41:48 -06:00
TimingInfo : : NameBit o ;
2020-04-20 11:39:35 -05:00
std : : vector < int > delays ;
2020-02-14 13:41:43 -06:00
for ( const auto & i : t . comb ) {
auto & d = i . first . second ;
2020-02-18 10:41:48 -06:00
if ( o = = TimingInfo : : NameBit ( ) )
2020-02-11 10:34:13 -06:00
o = d ;
2020-02-14 13:41:43 -06:00
else if ( o ! = d )
2020-04-20 11:39:35 -05:00
log_error ( " Module '%s' with (* abc9_lut *) has more than one output. \n " , log_id ( module ) ) ;
delays . push_back ( i . second ) ;
2020-02-18 10:30:41 -06:00
}
2020-02-14 13:41:43 -06:00
2020-04-20 11:39:35 -05:00
if ( GetSize ( delays ) = = 0 )
log_error ( " Module '%s' with (* abc9_lut *) has no specify entries. \n " , log_id ( module ) ) ;
if ( maxlut & & GetSize ( delays ) > maxlut )
2020-02-11 10:34:13 -06:00
continue ;
2020-02-13 12:30:29 -06:00
// ABC requires non-decreasing LUT input delays
2020-04-20 11:39:35 -05:00
std : : sort ( delays . begin ( ) , delays . end ( ) ) ;
int K = GetSize ( delays ) ;
auto entry = t_lut { module - > name , it - > second . as_int ( ) , std : : move ( delays ) } ;
auto r = table . emplace ( K , entry ) ;
if ( ! r . second ) {
if ( r . first - > second . area ! = entry . area )
log_error ( " Modules '%s' and '%s' have conflicting (* abc9_lut *) values. \n " , log_id ( module ) , log_id ( r . first - > second . name ) ) ;
if ( r . first - > second . delays ! = entry . delays )
log_error ( " Modules '%s' and '%s' have conflicting specify entries. \n " , log_id ( module ) , log_id ( r . first - > second . name ) ) ;
}
2020-02-11 10:34:13 -06:00
}
2020-04-20 11:39:35 -05:00
if ( table . empty ( ) )
log_error ( " Design does not contain any modules with (* abc9_lut *). \n " ) ;
2020-02-13 11:48:48 -06:00
std : : stringstream ss ;
2020-04-20 11:39:35 -05:00
const auto & front = * table . begin ( ) ;
2020-02-13 11:48:48 -06:00
// If the first entry does not start from a 1-input LUT,
// (as ABC requires) crop the first entry to do so
2020-04-20 11:39:35 -05:00
for ( int i = 1 ; i < front . first ; i + + ) {
2020-02-13 11:48:48 -06:00
ss < < " # $__ABC9_LUT " < < i < < std : : endl ;
2020-04-20 11:39:35 -05:00
ss < < i < < " " < < front . second . area ;
2020-02-13 11:48:48 -06:00
for ( int j = 0 ; j < i ; j + + )
2020-04-20 11:39:35 -05:00
ss < < " " < < front . second . delays [ j ] ;
2020-02-13 11:48:48 -06:00
ss < < std : : endl ;
}
for ( const auto & i : table ) {
2020-04-20 11:39:35 -05:00
ss < < " # " < < log_id ( i . second . name ) < < std : : endl ;
ss < < i . first < < " " < < i . second . area ;
for ( const auto & j : i . second . delays )
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-04-13 11:38:07 -05:00
void prep_box ( RTLIL : : Design * design )
2020-02-11 10:54:13 -06:00
{
2020-02-18 10:30:41 -06:00
TimingInfo timing ;
2020-02-14 13:41:43 -06:00
2020-02-11 16:22:43 -06:00
int abc9_box_id = 1 ;
2021-09-09 12:06:31 -05:00
std : : stringstream ss ;
2020-02-11 16:22:43 -06:00
dict < IdString , std : : vector < IdString > > box_ports ;
2020-02-11 13:38:49 -06:00
for ( auto module : design - > modules ( ) ) {
2020-04-21 14:22:39 -05:00
auto it = module - > attributes . find ( ID : : abc9_box ) ;
if ( it = = module - > attributes . end ( ) )
continue ;
bool box = it - > second . as_bool ( ) ;
module - > attributes . erase ( it ) ;
if ( ! box )
2020-04-13 11:38:07 -05:00
continue ;
2020-02-11 16:22:43 -06:00
2020-04-13 11:38:07 -05:00
auto r = module - > attributes . insert ( ID : : abc9_box_id ) ;
if ( ! r . second )
continue ;
r . first - > second = abc9_box_id + + ;
if ( module - > get_bool_attribute ( ID : : abc9_flop ) ) {
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-04-13 11:38:07 -05:00
ss < < log_id ( module ) < < " " < < r . first - > second . as_int ( ) ;
2020-04-15 17:50:57 -05:00
log_assert ( module - > get_bool_attribute ( ID : : whitebox ) ) ;
ss < < " " < < " 1 " ;
2020-04-13 11:38:07 -05:00
ss < < " " < < num_inputs < < " " < < num_outputs < < std : : endl ;
2020-02-11 16:22:43 -06:00
2020-04-13 11:38:07 -05: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 < < std : : endl ;
auto & t = timing . setup_module ( module ) . required ;
2020-04-15 17:50:57 -05:00
if ( t . empty ( ) )
log_error ( " Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information. \n " , log_id ( module ) ) ;
2020-04-13 11:38:07 -05: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 < < " " ;
log_assert ( GetSize ( wire ) = = 1 ) ;
auto it = t . find ( TimingInfo : : NameBit ( port_name , 0 ) ) ;
if ( it = = t . end ( ) )
2021-11-24 15:21:08 -06:00
// Assume that no setup time means zero
ss < < 0 ;
2020-04-13 11:38:07 -05:00
else {
2021-11-24 15:21:08 -06:00
ss < < it - > second . first ;
2020-02-14 13:11:34 -06:00
# ifndef NDEBUG
2020-04-13 11:38:07 -05:00
if ( ys_debug ( 1 ) ) {
static std : : set < std : : pair < IdString , IdString > > seen ;
if ( seen . emplace ( module - > name , port_name ) . second ) log ( " %s.%s abc9_required = %d \n " , log_id ( module ) ,
2021-11-24 15:21:08 -06:00
log_id ( port_name ) , it - > second . first ) ;
2020-02-18 10:30:41 -06:00
}
2020-04-13 11:38:07 -05:00
# endif
2020-02-13 13:15:59 -06:00
}
2020-02-11 16:22:43 -06:00
}
2020-04-13 11:38:07 -05:00
ss < < " # $_DFF_[NP]_.D " < < std : : endl ;
ss < < std : : endl ;
2020-02-11 16:22:43 -06:00
}
2020-02-13 13:15:59 -06:00
else {
2020-04-13 11:38:07 -05:00
auto r2 = box_ports . insert ( module - > name ) ;
if ( r2 . 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 ( ID : : 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
r2 . first - > second . push_back ( port_name ) ;
}
2020-02-11 16:22:43 -06:00
2020-04-13 11:38:07 -05:00
if ( carry_in ! = IdString ( ) ) {
r2 . first - > second . push_back ( carry_in ) ;
r2 . first - > second . push_back ( carry_out ) ;
2020-02-11 16:22:43 -06:00
}
}
2020-04-13 11:38:07 -05:00
std : : vector < SigBit > inputs , outputs ;
for ( auto port_name : r2 . first - > second ) {
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 ) ;
2020-02-11 16:22:43 -06:00
}
2020-02-14 13:41:43 -06:00
2020-04-13 11:38:07 -05:00
ss < < log_id ( module ) < < " " < < module - > attributes . at ( ID : : abc9_box_id ) . as_int ( ) ;
ss < < " " < < ( module - > get_bool_attribute ( ID : : whitebox ) ? " 1 " : " 0 " ) ;
ss < < " " < < GetSize ( inputs ) < < " " < < GetSize ( outputs ) < < std : : endl ;
2020-02-14 13:41:43 -06:00
2020-04-13 11:38:07 -05:00
bool first = true ;
ss < < " # " ;
2020-02-11 13:38:49 -06:00
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
2020-04-13 11:38:07 -05:00
if ( GetSize ( i . wire ) = = 1 )
ss < < log_id ( i . wire ) ;
2020-02-14 13:41:43 -06:00
else
2020-04-13 11:38:07 -05:00
ss < < log_id ( i . wire ) < < " [ " < < i . offset < < " ] " ;
2020-02-11 13:38:49 -06:00
}
ss < < std : : endl ;
2020-01-10 13:45:41 -06:00
2020-04-15 17:50:57 -05:00
auto & t = timing . setup_module ( module ) ;
if ( t . comb . empty ( ) )
log_error ( " Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information. \n " , log_id ( module ) ) ;
2020-04-13 11:38:07 -05:00
for ( const auto & o : outputs ) {
first = true ;
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
2020-04-15 17:50:57 -05:00
auto jt = t . comb . find ( TimingInfo : : BitBit ( i , o ) ) ;
if ( jt = = t . comb . end ( ) )
2020-04-13 11:38:07 -05:00
ss < < " - " ;
else
ss < < jt - > second ;
}
ss < < " # " ;
if ( GetSize ( o . wire ) = = 1 )
ss < < log_id ( o . wire ) ;
else
ss < < log_id ( o . wire ) < < " [ " < < o . offset < < " ] " ;
ss < < std : : endl ;
}
ss < < std : : endl ;
2020-02-11 13:38:49 -06:00
}
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-04-13 11:38:07 -05:00
void reintegrate ( RTLIL : : Module * module , bool dff_mode )
2020-01-06 17:52:59 -06:00
{
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 ) ) ;
2020-05-02 13:19:04 -05:00
for ( auto w : mapped_mod - > wires ( ) ) {
auto nw = module - > addWire ( remap_name ( w - > name ) , GetSize ( w ) ) ;
nw - > start_offset = w - > start_offset ;
2020-05-25 09:22:26 -05:00
// Remove all (* init *) since they only exist on $_DFF_[NP]_
2020-04-13 15:12:37 -05:00
w - > attributes . erase ( ID : : init ) ;
2020-05-02 13:19:04 -05:00
}
2020-01-06 17:52:59 -06:00
2020-01-07 11:48:57 -06:00
dict < IdString , std : : vector < IdString > > box_ports ;
for ( auto m : design - > modules ( ) ) {
2020-04-02 11:51:32 -05: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 ) ;
2020-04-02 11:51:32 -05:00
if ( w - > get_bool_attribute ( ID : : abc9_carry ) ) {
2020-01-27 14:29:28 -06:00
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-05-29 19:17:40 -05:00
SigMap initmap ;
if ( dff_mode ) {
// Build a sigmap prioritising bits with (* init *)
initmap . set ( module ) ;
for ( auto w : module - > wires ( ) ) {
auto it = w - > attributes . find ( ID : : init ) ;
if ( it = = w - > attributes . end ( ) )
continue ;
for ( auto i = 0 ; i < GetSize ( w ) ; i + + )
if ( it - > second [ i ] = = State : : S0 | | it - > second [ i ] = = State : : S1 )
initmap . add ( w ) ;
}
}
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-04-13 11:38:07 -05:00
2020-05-25 09:22:26 -05:00
// Short out (so that existing name can be preserved) and remove
// $_DFF_[NP]_ cells since flop box already has all the information
// we need to reconstruct them
2020-05-14 18:44:35 -05:00
if ( dff_mode & & cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) & & ! cell - > get_bool_attribute ( ID : : abc9_keep ) ) {
2020-05-29 19:17:40 -05:00
SigBit Q = cell - > getPort ( ID : : Q ) ;
module - > connect ( Q , cell - > getPort ( ID : : D ) ) ;
2020-04-13 11:38:07 -05:00
module - > remove ( cell ) ;
2020-05-29 19:17:40 -05:00
auto Qi = initmap ( Q ) ;
auto it = Qi . wire - > attributes . find ( ID : : init ) ;
if ( it ! = Qi . wire - > attributes . end ( ) )
it - > second [ Qi . offset ] = State : : Sx ;
2020-04-13 11:38:07 -05:00
}
else if ( cell - > type . in ( ID ( $ _AND_ ) , ID ( $ _NOT_ ) ) )
2020-01-09 13:21:03 -06:00
module - > remove ( cell ) ;
2020-04-02 11:51:32 -05:00
else if ( cell - > attributes . erase ( ID : : abc9_box_seq ) )
2020-01-09 13:21:03 -06:00
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-04-16 16:03:54 -05:00
// Short out $_FF_ cells since the flop box already has
2020-04-13 15:12:37 -05:00
// all the information we need to reconstruct cell
2020-04-16 16:03:54 -05:00
if ( dff_mode & & mapped_cell - > type = = ID ( $ _FF_ ) ) {
2020-04-13 11:38:07 -05:00
SigBit D = mapped_cell - > getPort ( ID : : D ) ;
SigBit Q = mapped_cell - > getPort ( ID : : Q ) ;
if ( D . wire )
D . wire = module - > wires_ . at ( remap_name ( D . wire - > name ) ) ;
Q . wire = module - > wires_ . at ( remap_name ( Q . wire - > name ) ) ;
module - > connect ( Q , D ) ;
continue ;
}
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 ;
}
2020-04-13 11:38:07 -05:00
if ( mapped_cell - > type = = ID ( $ lut ) ) {
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-05-13 23:56:06 -05:00
if ( existing_cell - > type . begins_with ( " $paramod$__ABC9_DELAY \\ 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-05-13 23:56:06 -05:00
log_assert ( existing_cell - > parameters . empty ( ) ) ;
log_assert ( mapped_cell - > type = = stringf ( " $__boxid%d " , box_module - > attributes . at ( ID : : 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-04-02 11:51:32 -05:00
auto jt = mapped_cell - > connections_ . find ( ID ( i ) ) ;
2020-01-24 00:45:34 -06:00
log_assert ( jt ! = mapped_cell - > connections_ . end ( ) ) ;
SigSpec inputs = std : : move ( jt - > second ) ;
mapped_cell - > connections_ . erase ( jt ) ;
2020-04-02 11:51:32 -05:00
jt = mapped_cell - > connections_ . find ( ID ( o ) ) ;
2020-01-24 00:45:34 -06:00
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
2020-04-13 19:30:29 -05:00
auto abc9_flop = box_module - > get_bool_attribute ( ID : : abc9_flop ) ;
2020-05-25 09:22:26 -05:00
if ( abc9_flop ) {
// Link this sole flop box output to the output of the existing
// flop box, so that any (public) signal it drives will be
// preserved
SigBit old_q ;
for ( const auto & port_name : box_ports . at ( existing_cell - > type ) ) {
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
log_assert ( w ) ;
if ( ! w - > port_output )
continue ;
log_assert ( old_q = = SigBit ( ) ) ;
log_assert ( GetSize ( w ) = = 1 ) ;
old_q = existing_cell - > getPort ( port_name ) ;
}
auto new_q = outputs [ 0 ] ;
new_q . wire = module - > wires_ . at ( remap_name ( new_q . wire - > name ) ) ;
module - > connect ( old_q , new_q ) ;
}
else {
2020-01-07 11:48:57 -06:00
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-05-13 23:56:06 -05:00
for ( const auto & port_name : box_ports . at ( existing_cell - > 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 ) ;
}
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-05-25 09:22:26 -05:00
cell - > setPort ( port_name , std : : move ( newsig ) ) ;
2020-01-07 11:48:57 -06:00
}
}
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-03-06 12:20:30 -06:00
2020-01-06 17:52:59 -06:00
RTLIL : : Wire * remap_wire = module - > wire ( remap_name ( port ) ) ;
2020-05-02 13:19:04 -05:00
RTLIL : : SigSpec signal ( wire , remap_wire - > start_offset - wire - > start_offset , 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.
2020-05-30 11:01:03 -05:00
// Instead of just mapping those $_NOT_ gates into 1-input $lut-s
2020-01-27 13:18:21 -06:00
// 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 ) ;
2020-06-18 20:32:48 -05:00
bool no_loops = toposort . sort ( ) ;
2020-01-06 17:52:59 -06:00
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 ) ;
2020-04-02 11:51:32 -05:00
RTLIL : : Const mask = sink_cell - > getParam ( ID : : LUT ) ;
2020-01-06 17:52:59 -06:00
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 ) ;
2020-04-02 11:51:32 -05:00
sink_cell - > setParam ( ID : : LUT , mask ) ;
2020-01-06 17:52:59 -06:00
}
// 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 :
2020-04-02 11:51:32 -05:00
driver_mask = driver_lut - > getParam ( ID : : LUT ) ;
2020-01-06 17:52:59 -06:00
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 " ) { }
2020-06-18 18:34:52 -05:00
void help ( ) override
2019-12-28 07:07:46 -06:00
{
// |---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 " ) ;
2020-04-21 14:22:39 -05:00
log ( " -prep_hier \n " ) ;
2020-05-13 23:56:06 -05:00
log ( " derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option) \n " ) ;
log ( " whitebox modules. with (* abc9_flop *) modules, only those containing \n " ) ;
log ( " $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation \n " ) ;
log ( " -- will be derived. \n " ) ;
2020-04-21 14:22:39 -05:00
log ( " \n " ) ;
log ( " -prep_bypass \n " ) ;
log ( " create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for \n " ) ;
log ( " bypassing sequential (* abc9_box *) modules using a combinatorial box \n " ) ;
2020-05-13 23:56:06 -05:00
log ( " (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g. \n " ) ;
log ( " $dff, $mem, etc.) are discovered inside so that any combinatorial paths \n " ) ;
log ( " will be correctly captured. this bypass box will only contain ports that \n " ) ;
log ( " are referenced by a simple path declaration ($specify2 cell) inside a \n " ) ;
2020-04-22 15:07:19 -05:00
log ( " specify block. \n " ) ;
2020-04-21 14:22:39 -05:00
log ( " \n " ) ;
log ( " -prep_dff \n " ) ;
log ( " select all (* abc9_flop *) modules instantiated in the design and store \n " ) ;
log ( " in the named selection '$abc9_flops'. \n " ) ;
2020-04-13 11:38:07 -05:00
log ( " \n " ) ;
2020-04-21 14:30:25 -05:00
log ( " -prep_dff_submod \n " ) ;
2020-04-22 15:07:19 -05:00
log ( " within (* abc9_flop *) modules, rewrite all edge-sensitive path \n " ) ;
log ( " declarations and $setup() timing checks ($specify3 and $specrule cells) \n " ) ;
log ( " that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to \n " ) ;
log ( " the DFF's 'D' port. this is to prepare such specify cells to be moved \n " ) ;
log ( " into the flop box. \n " ) ;
2020-04-13 11:38:07 -05:00
log ( " \n " ) ;
log ( " -prep_dff_unmap \n " ) ;
2020-04-21 14:22:39 -05:00
log ( " populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop \n " ) ;
log ( " cells back into their derived cell types (where the rules created by \n " ) ;
log ( " -prep_hier will then map back to the original cell with parameters). \n " ) ;
2020-04-13 11:38:07 -05:00
log ( " \n " ) ;
2020-01-14 15:21:58 -06:00
log ( " -prep_delays \n " ) ;
log ( " insert `$__ABC9_DELAY' blackbox cells into the design to account for \n " ) ;
2020-02-14 14:54:47 -06:00
log ( " certain required times. \n " ) ;
2020-01-14 15:21:58 -06:00
log ( " \n " ) ;
2021-03-30 00:01:57 -05:00
log ( " -break_scc \n " ) ;
2020-01-14 14:25:45 -06:00
log ( " for an arbitrarily chosen cell in each unique SCC of each selected module \n " ) ;
2021-03-30 00:01:57 -05:00
log ( " (tagged with an (* abc9_scc_id = <int> *) attribute) interrupt all wires \n " ) ;
log ( " driven by this cell's outputs with a temporary $__ABC9_SCC_BREAKER cell \n " ) ;
log ( " to break the SCC. \n " ) ;
2020-01-14 14:25:45 -06:00
log ( " \n " ) ;
log ( " -prep_xaiger \n " ) ;
log ( " prepare the design for XAIGER output. this includes computing the \n " ) ;
2020-04-15 18:13:57 -05:00
log ( " topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes' \n " ) ;
log ( " design that contains the logic behaviour of ABC9 whiteboxes. \n " ) ;
2020-01-14 14:25:45 -06:00
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 " ) ;
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
}
2020-06-18 18:34:52 -05:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
2019-12-28 07:07:46 -06:00
{
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 ;
2021-03-30 00:01:57 -05:00
bool break_scc_mode = false ;
2020-04-21 14:22:39 -05:00
bool prep_hier_mode = false ;
bool prep_bypass_mode = false ;
2020-04-21 14:30:25 -05:00
bool prep_dff_mode = false , prep_dff_submod_mode = false , prep_dff_unmap_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
2020-04-13 11:38:07 -05:00
bool valid = false ;
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 ;
2020-04-13 11:38:07 -05:00
valid = true ;
2020-01-10 13:45:41 -06:00
continue ;
}
2021-03-30 00:01:57 -05:00
if ( arg = = " -break_scc " ) {
break_scc_mode = true ;
2020-04-13 11:38:07 -05:00
valid = true ;
continue ;
}
2020-04-21 14:22:39 -05:00
if ( arg = = " -prep_hier " ) {
prep_hier_mode = true ;
valid = true ;
continue ;
}
if ( arg = = " -prep_bypass " ) {
prep_bypass_mode = true ;
valid = true ;
continue ;
}
if ( arg = = " -prep_dff " ) {
prep_dff_mode = true ;
2020-04-13 11:38:07 -05:00
valid = true ;
2019-12-28 07:07:46 -06:00
continue ;
}
2020-04-21 14:30:25 -05:00
if ( arg = = " -prep_dff_submod " ) {
prep_dff_submod_mode = true ;
2020-04-13 11:38:07 -05:00
valid = true ;
continue ;
}
if ( arg = = " -prep_dff_unmap " ) {
prep_dff_unmap_mode = true ;
valid = true ;
2019-12-30 18:36:33 -06:00
continue ;
}
2020-01-14 14:25:45 -06:00
if ( arg = = " -prep_xaiger " ) {
prep_xaiger_mode = true ;
2020-04-13 11:38:07 -05:00
valid = 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-04-13 11:38:07 -05:00
valid = 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 ( ) ) ;
2020-04-13 11:38:07 -05:00
valid = true ;
2020-02-11 10:54:13 -06:00
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 ) ;
2020-04-13 11:38:07 -05:00
valid = true ;
2020-02-11 10:34:13 -06:00
continue ;
}
2020-02-11 13:38:49 -06:00
if ( arg = = " -prep_box " ) {
prep_box_mode = true ;
2020-04-13 11:38:07 -05:00
valid = 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 ) ;
2020-04-13 11:38:07 -05:00
valid = true ;
2020-01-10 13:45:41 -06:00
continue ;
}
2020-01-06 17:52:59 -06:00
if ( arg = = " -reintegrate " ) {
reintegrate_mode = true ;
2020-04-13 11:38:07 -05:00
valid = true ;
2020-01-06 17:52:59 -06:00
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-04-13 11:38:07 -05:00
if ( ! valid )
2021-03-30 00:01:57 -05:00
log_cmd_error ( " At least one of -check, -break_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified. \n " ) ;
2020-01-11 10:42:58 -06:00
2020-04-21 14:22:39 -05:00
if ( dff_mode & & ! check_mode & & ! prep_hier_mode & & ! prep_delays_mode & & ! prep_xaiger_mode & & ! reintegrate_mode )
log_cmd_error ( " '-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate. \n " ) ;
2020-01-10 13:45:41 -06:00
if ( check_mode )
2020-04-21 14:22:39 -05:00
check ( design , dff_mode ) ;
if ( prep_hier_mode )
prep_hier ( design , dff_mode ) ;
if ( prep_bypass_mode )
prep_bypass ( design ) ;
if ( prep_dff_mode )
prep_dff ( design ) ;
2020-04-21 14:30:25 -05:00
if ( prep_dff_submod_mode )
prep_dff_submod ( design ) ;
2020-04-13 11:38:07 -05:00
if ( prep_dff_unmap_mode )
prep_dff_unmap ( 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-04-13 11:38:07 -05:00
prep_box ( design ) ;
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 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 ) ;
2021-03-30 00:01:57 -05:00
if ( break_scc_mode )
break_scc ( 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 )
2020-04-13 11:38:07 -05:00
reintegrate ( mod , dff_mode ) ;
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