2019-12-28 14:07:46 +01:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-08 00:39:36 +02:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2019-12-28 14:07:46 +01: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-31 01:36:33 +01:00
# include "kernel/sigtools.h"
2019-12-31 03:00:49 +01:00
# include "kernel/utils.h"
2025-11-26 00:50:41 +01:00
# include "kernel/newcelltypes.h"
2020-02-14 20:11:34 +01:00
# include "kernel/timinginfo.h"
2026-02-24 18:55:11 +01:00
# include <optional>
2019-12-28 14:07:46 +01:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2020-04-21 21:22:39 +02:00
void check ( RTLIL : : Design * design , bool dff_mode )
2020-01-10 20:45:41 +01:00
{
dict < IdString , IdString > box_lookup ;
for ( auto m : design - > modules ( ) ) {
2020-04-02 18:51:32 +02:00
auto flop = m - > get_bool_attribute ( ID : : abc9_flop ) ;
auto it = m - > attributes . find ( ID : : abc9_box_id ) ;
2020-01-15 00:05:49 +01: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 " ,
2026-05-08 09:01:43 +02:00
m , id , r . first - > second . unescape ( ) ) ;
2020-01-10 23:49:52 +01:00
}
2020-01-10 20:45:41 +01: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 18:51:32 +02:00
if ( w - > get_bool_attribute ( ID : : abc9_carry ) ) {
2020-01-10 20:45:41 +01:00
if ( w - > port_input ) {
if ( carry_in ! = IdString ( ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' contains more than one (* abc9_carry *) input port. \n " , m ) ;
2020-01-10 20:45:41 +01:00
carry_in = port_name ;
}
if ( w - > port_output ) {
if ( carry_out ! = IdString ( ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' contains more than one (* abc9_carry *) output port. \n " , m ) ;
2020-01-10 20:45:41 +01:00
carry_out = port_name ;
}
}
}
if ( carry_in ! = IdString ( ) & & carry_out = = IdString ( ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' contains an (* abc9_carry *) input port but no output port. \n " , m ) ;
2020-01-10 20:45:41 +01:00
if ( carry_in = = IdString ( ) & & carry_out ! = IdString ( ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' contains an (* abc9_carry *) output port but no input port. \n " , m ) ;
2020-01-10 23:49:52 +01:00
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 )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_flop *) has %d outputs (expect 1). \n " , m , num_outputs ) ;
2020-01-10 23:49:52 +01:00
}
2020-01-10 20:45:41 +01:00
}
2020-04-21 21:22:39 +02:00
if ( dff_mode ) {
2020-05-14 03:02:05 +02:00
static pool < IdString > unsupported {
2020-04-21 21:22:39 +02: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_ )
} ;
for ( auto module : design - > selected_modules ( ) )
for ( auto cell : module - > cells ( ) ) {
auto inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
2020-05-14 06:56:06 +02:00
IdString derived_type ;
Module * derived_module ;
if ( cell - > parameters . empty ( ) ) {
derived_type = cell - > type ;
derived_module = inst_module ;
}
else {
2020-05-30 02:33:10 +02: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-14 06:56:06 +02:00
derived_type = inst_module - > derive ( design , cell - > parameters ) ;
derived_module = design - > module ( derived_type ) ;
log_assert ( derived_module ) ;
}
2020-05-14 03:02:05 +02:00
if ( ! derived_module - > get_bool_attribute ( ID : : abc9_flop ) )
continue ;
if ( derived_module - > get_blackbox_attribute ( true /* ignore_wb */ ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_flop *) is a blackbox. \n " , derived_type . unescape ( ) ) ;
2020-04-21 21:22:39 +02:00
if ( derived_module - > has_processes ( ) )
2025-05-31 02:16:37 +02:00
Pass : : call_on_module ( design , derived_module , " proc -noopt " ) ;
2020-04-21 21:22:39 +02:00
2020-05-14 03:02:05 +02: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 )
2026-05-08 09:01:43 +02:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell. \n " , derived_module ) ;
2020-05-14 03:02:05 +02:00
found = true ;
2020-04-21 21:22:39 +02:00
2020-05-14 03:02:05 +02:00
SigBit Q = derived_cell - > getPort ( ID : : Q ) ;
log_assert ( GetSize ( Q . wire ) = = 1 ) ;
2020-04-21 21:22:39 +02:00
2020-05-14 03:02:05 +02:00
if ( ! Q . wire - > port_output )
2026-05-08 09:01:43 +02:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains a %s cell where its 'Q' port does not drive a module output. \n " , derived_module , derived_cell - > type . unescape ( ) ) ;
2020-04-21 21:22:39 +02:00
2020-05-14 03:02:05 +02:00
Const init = Q . wire - > attributes . at ( ID : : init , State : : Sx ) ;
log_assert ( GetSize ( init ) = = 1 ) ;
}
else if ( unsupported . count ( derived_cell - > type ) )
2026-05-08 09:01:43 +02:00
log_error ( " Whitebox '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis. \n " , derived_module , derived_cell - > type . unescape ( ) ) ;
2020-04-21 21:22:39 +02:00
}
}
}
2020-01-10 20:45:41 +01:00
}
2020-04-21 21:22:39 +02:00
void prep_hier ( RTLIL : : Design * design , bool dff_mode )
2019-12-28 14:07:46 +01:00
{
2020-04-21 21:22:39 +02:00
auto r = saved_designs . emplace ( " $abc9_unmap " , nullptr ) ;
if ( r . second )
r . first - > second = new Design ;
Design * unmap_design = r . first - > second ;
2022-05-01 10:24:17 +02:00
// Keep track of derived versions of modules that we haven't used, to prevent these being used for unwanted techmaps later on.
pool < IdString > unused_derived ;
2020-04-21 21:22:39 +02:00
for ( auto module : design - > selected_modules ( ) )
for ( auto cell : module - > cells ( ) ) {
auto inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
2020-05-14 06:56:06 +02: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 ) ;
2022-05-01 10:24:17 +02:00
unused_derived . insert ( derived_type ) ;
2020-05-14 06:56:06 +02:00
}
2020-04-21 21:22:39 +02:00
2020-05-14 06:56:06 +02:00
if ( derived_module - > get_bool_attribute ( ID : : abc9_flop ) ) {
if ( ! dff_mode )
continue ;
}
else {
2022-03-24 15:34:34 +01: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 19:05:55 +02: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 ( ) ;
2022-05-01 10:24:17 +02:00
unused_derived . erase ( derived_type ) ;
2021-09-09 19:05:55 +02:00
}
2020-05-14 06:56:06 +02:00
continue ;
2021-09-09 19:05:55 +02:00
}
2020-05-14 06:56:06 +02:00
}
2020-04-21 21:22:39 +02:00
if ( ! unmap_design - > module ( derived_type ) ) {
if ( derived_module - > has_processes ( ) )
2025-05-31 02:16:37 +02:00
Pass : : call_on_module ( design , derived_module , " proc -noopt " ) ;
2020-04-21 21:22:39 +02:00
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 ) {
2026-05-08 09:01:43 +02: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 " , derived_module , derived_cell - > type . unescape ( ) ) ;
2020-04-21 21:30:25 +02:00
derived_module - > set_bool_attribute ( ID : : abc9_flop , false ) ;
2020-04-21 21:22:39 +02:00
}
break ;
}
}
else if ( derived_module - > get_bool_attribute ( ID : : abc9_box ) ) {
for ( auto derived_cell : derived_module - > cells ( ) )
2025-09-17 05:23:52 +02:00
if ( derived_cell - > is_mem_cell ( ) | | derived_cell - > is_builtin_ff ( ) ) {
2020-05-14 06:56:06 +02:00
derived_module - > set_bool_attribute ( ID : : abc9_box , false ) ;
derived_module - > set_bool_attribute ( ID : : abc9_bypass ) ;
2020-04-21 21:22:39 +02:00
break ;
}
}
if ( derived_type ! = cell - > type ) {
auto unmap_module = unmap_design - > addModule ( derived_type ) ;
2023-05-22 03:20:18 +02:00
auto replace_cell = unmap_module - > addCell ( ID : : _TECHMAP_REPLACE_ , cell - > type ) ;
2020-04-21 21:22:39 +02:00
for ( auto port : derived_module - > ports ) {
auto w = unmap_module - > addWire ( port , derived_module - > wire ( port ) ) ;
2020-05-14 11:09:13 +02:00
// Do not propagate (* init *) values into the box,
// in fact, remove it from outside too
2020-05-30 02:17:40 +02:00
if ( w - > port_output )
w - > attributes . erase ( ID : : init ) ;
2023-05-22 03:20:18 +02:00
// Attach (* techmap_autopurge *) to all ports to ensure that
// undriven inputs/unused outputs are propagated through to
// the techmapped cell
w - > attributes [ ID : : techmap_autopurge ] = 1 ;
replace_cell - > setPort ( port , w ) ;
2020-04-21 21:22:39 +02:00
}
unmap_module - > ports = derived_module - > ports ;
unmap_module - > check ( ) ;
replace_cell - > parameters = cell - > parameters ;
}
2019-12-28 14:07:46 +01:00
}
2020-04-21 21:22:39 +02:00
cell - > type = derived_type ;
cell - > parameters . clear ( ) ;
2022-05-01 10:24:17 +02:00
unused_derived . erase ( derived_type ) ;
2019-12-28 14:07:46 +01:00
}
2022-05-01 10:24:17 +02:00
for ( auto unused : unused_derived ) {
design - > remove ( design - > module ( unused ) ) ;
}
2019-12-28 14:07:46 +01:00
}
2020-04-21 21:22:39 +02:00
void prep_bypass ( RTLIL : : Design * design )
2020-04-13 18:38:07 +02:00
{
2020-04-21 21:22:39 +02: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 20:38:44 +02:00
2020-04-21 21:22:39 +02: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 18:38:07 +02:00
2020-04-21 21:22:39 +02:00
pool < IdString > processed ;
2020-04-16 19:40:33 +02:00
for ( auto module : design - > selected_modules ( ) )
2020-04-13 18:38:07 +02:00
for ( auto cell : module - > cells ( ) ) {
2020-04-21 21:22:39 +02:00
if ( ! processed . insert ( cell - > type ) . second )
continue ;
2020-04-13 18:38:07 +02:00
auto inst_module = design - > module ( cell - > type ) ;
2020-04-21 21:22:39 +02:00
if ( ! inst_module )
continue ;
2020-04-21 23:12:28 +02:00
if ( ! inst_module - > get_bool_attribute ( ID : : abc9_bypass ) )
2020-04-21 21:22:39 +02:00
continue ;
2020-04-22 00:44:56 +02:00
log_assert ( ! inst_module - > get_blackbox_attribute ( true /* ignore_wb */ ) ) ;
2020-05-14 06:56:06 +02:00
log_assert ( cell - > parameters . empty ( ) ) ;
2020-04-21 21:22:39 +02: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-14 03:02:05 +02:00
// Copy inst_module into map_design, with the same interface
2020-04-21 21:22:39 +02: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-14 02:30:29 +02:00
continue ;
2020-04-21 21:22:39 +02: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-14 02:30:29 +02:00
}
2020-04-13 18:38:07 +02:00
}
2020-04-21 21:22:39 +02: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 19:06:31 +02:00
design - > scratchpad_set_bool ( " abc9_ops.prep_bypass.did_something " , true ) ;
2020-04-13 18:38:07 +02:00
}
2020-04-21 21:22:39 +02:00
}
void prep_dff ( RTLIL : : Design * design )
{
2025-04-08 01:57:43 +02:00
auto r = design - > selection_vars . insert ( std : : make_pair ( ID ( $ abc9_flops ) , RTLIL : : Selection : : EmptySelection ( design ) ) ) ;
2020-04-21 21:22:39 +02:00
auto & modules_sel = r . first - > second ;
2020-04-14 20:38:44 +02:00
2020-04-21 21:22:39 +02: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 23:12:28 +02:00
if ( ! inst_module - > get_bool_attribute ( ID : : abc9_flop ) )
2020-04-21 21:22:39 +02:00
continue ;
2020-05-14 03:02:05 +02:00
log_assert ( ! inst_module - > get_blackbox_attribute ( true /* ignore_wb */ ) ) ;
2021-09-09 19:05:55 +02: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!
2026-05-08 09:01:43 +02:00
log_error ( " Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_flop *) \n " , cell - > name . unescape ( ) , cell - > type . unescape ( ) ) ;
2021-09-09 19:05:55 +02:00
}
2020-05-14 03:02:05 +02:00
modules_sel . select ( inst_module ) ;
2020-04-21 21:22:39 +02:00
}
2020-04-13 18:38:07 +02:00
}
2019-12-31 01:36:33 +01:00
2020-04-21 21:30:25 +02:00
void prep_dff_submod ( RTLIL : : Design * design )
2020-04-13 18:38:07 +02:00
{
for ( auto module : design - > modules ( ) ) {
vector < Cell * > specify_cells ;
2020-04-21 21:22:39 +02:00
SigBit Q ;
2020-04-14 02:30:29 +02:00
Cell * dff_cell = nullptr ;
2020-04-16 00:41:55 +02:00
2020-04-21 21:22:39 +02:00
if ( ! module - > get_bool_attribute ( ID : : abc9_flop ) )
2020-04-16 00:41:55 +02:00
continue ;
2020-04-13 18:38:07 +02:00
for ( auto cell : module - > cells ( ) )
if ( cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) ) {
2020-04-21 21:22:39 +02:00
log_assert ( ! dff_cell ) ;
2020-04-14 02:30:29 +02:00
dff_cell = cell ;
Q = cell - > getPort ( ID : : Q ) ;
2020-04-13 18:38:07 +02:00
log_assert ( GetSize ( Q . wire ) = = 1 ) ;
}
2020-04-21 21:22:39 +02:00
else if ( cell - > type . in ( ID ( $ specify3 ) , ID ( $ specrule ) ) )
2020-04-13 18:38:07 +02:00
specify_cells . emplace_back ( cell ) ;
2020-04-21 21:22:39 +02:00
log_assert ( dff_cell ) ;
2020-04-13 18:38:07 +02:00
2020-04-22 02:25:15 +02: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 21:22:39 +02:00
SigBit D = module - > addWire ( NEW_ID ) ;
2020-04-22 02:25:15 +02:00
module - > addMuxGate ( NEW_ID , dff_cell - > getPort ( ID : : D ) , Q , State : : S0 , D ) ;
2020-04-16 23:03:54 +02:00
dff_cell - > setPort ( ID : : D , D ) ;
2020-04-14 02:30:29 +02:00
2020-04-16 00:41:55 +02: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 18:38:07 +02:00
}
2020-04-16 00:41:55 +02:00
2020-04-21 21:30:25 +02:00
design - > scratchpad_set_bool ( " abc9_ops.prep_dff_submod.did_something " , true ) ;
2020-01-04 18:17:01 +01:00
}
2020-04-13 18:38:07 +02:00
}
2019-12-31 04:23:54 +01:00
2020-04-13 18:38:07 +02:00
void prep_dff_unmap ( RTLIL : : Design * design )
{
2020-04-14 20:38:44 +02:00
Design * unmap_design = saved_designs . at ( " $abc9_unmap " ) ;
2020-04-13 18:38:07 +02:00
2020-04-21 21:22:39 +02: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 18:38:07 +02:00
2020-04-22 02:25:15 +02: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 21:22:39 +02:00
for ( auto port_name : module - > ports ) {
2020-04-22 02:25:15 +02: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 21:22:39 +02:00
}
2020-04-22 02:25:15 +02:00
box_module - > fixup_ports ( ) ;
2020-04-21 21:22:39 +02:00
2020-04-22 02:25:15 +02:00
auto unmap_module = unmap_design - > addModule ( box_module - > name ) ;
replace_cell = unmap_module - > addCell ( ID : : _TECHMAP_REPLACE_ , module - > name ) ;
2020-04-21 21:22:39 +02:00
for ( auto port_name : box_module - > ports ) {
2020-04-22 02:25:15 +02: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 22:12:37 +02:00
}
2020-04-21 21:22:39 +02:00
unmap_module - > ports = box_module - > ports ;
2020-04-13 18:38:07 +02:00
unmap_module - > check ( ) ;
2020-04-21 21:22:39 +02:00
}
}
2020-04-13 18:38:07 +02:00
2021-03-30 07:01:57 +02:00
void break_scc ( RTLIL : : Module * module )
2020-04-21 21:22:39 +02:00
{
// For every unique SCC found, (arbitrarily) find the first
2021-03-30 07:01:57 +02: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 21:22:39 +02: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 07:01:57 +02: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 21:22:39 +02:00
auto id = it - > second ;
auto r = ids_seen . insert ( id ) ;
cell - > attributes . erase ( it ) ;
2026-02-24 18:55:11 +01:00
// Cut exactly one representative cell per SCC id.
2020-04-21 21:22:39 +02:00
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 07:01:57 +02:00
I . append ( w ) ;
O . append ( c . second ) ;
2020-04-21 21:22:39 +02:00
c . second = w ;
}
2020-04-14 20:38:44 +02:00
}
2019-12-31 04:23:54 +01:00
}
2021-03-30 07:01:57 +02: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-31 01:36:33 +01:00
}
2020-05-14 03:02:05 +02: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-14 06:56:06 +02:00
std : : vector < Cell * > cells ;
2020-05-14 03:02:05 +02:00
for ( auto module : design - > selected_modules ( ) ) {
if ( module - > processes . size ( ) > 0 ) {
2026-05-08 09:01:43 +02:00
log ( " Skipping module %s as it contains processes. \n " , module ) ;
2020-05-14 03:02:05 +02:00
continue ;
}
for ( auto cell : module - > cells ( ) ) {
2020-05-14 06:56:06 +02:00
if ( cell - > type . in ( ID ( $ _AND_ ) , ID ( $ _NOT_ ) , ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) )
2020-05-14 03:02:05 +02:00
continue ;
2020-05-14 06:56:06 +02:00
log_assert ( ! cell - > type . begins_with ( " $paramod$__ABC9_DELAY \\ DELAY= " ) ) ;
2020-05-14 03:02:05 +02:00
RTLIL : : Module * inst_module = design - > module ( cell - > type ) ;
if ( ! inst_module )
continue ;
if ( ! inst_module - > get_blackbox_attribute ( ) )
continue ;
2020-05-14 06:56:06 +02:00
if ( ! cell - > parameters . empty ( ) )
continue ;
2020-05-14 03:02:05 +02:00
2020-05-14 06:56:06 +02:00
if ( inst_module - > get_bool_attribute ( ID : : abc9_box ) )
2020-05-14 03:02:05 +02:00
continue ;
2020-05-14 06:56:06 +02:00
if ( inst_module - > get_bool_attribute ( ID : : abc9_bypass ) )
2020-05-14 03:02:05 +02: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-14 06:56:06 +02:00
if ( ! timing . count ( cell - > type ) )
timing . setup_module ( inst_module ) ;
2020-05-14 03:02:05 +02:00
2020-05-14 06:56:06 +02:00
cells . emplace_back ( cell ) ;
2020-05-14 03:02:05 +02:00
}
}
// Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
// (or bypassed white-boxes with required times)
2020-05-14 06:56:06 +02:00
dict < int , IdString > box_cache ;
Module * delay_module = design - > module ( ID ( $ __ABC9_DELAY ) ) ;
log_assert ( delay_module ) ;
for ( auto cell : cells ) {
2020-05-14 03:02:05 +02:00
auto module = cell - > module ;
2020-05-14 06:56:06 +02:00
auto inst_module = design - > module ( cell - > type ) ;
log_assert ( inst_module ) ;
2020-05-14 03:02:05 +02:00
2021-11-24 22:21:08 +01:00
for ( auto & i : timing . at ( cell - > type ) . required ) {
auto port_wire = inst_module - > wire ( i . first . name ) ;
2020-05-14 03:02:05 +02:00
if ( ! port_wire )
2020-05-14 06:56:06 +02:00
log_error ( " Port %s in cell %s (type %s) from module %s does not actually exist " ,
2026-05-08 09:01:43 +02:00
i . first . name . unescape ( ) , cell , cell - > type . unescape ( ) , module ) ;
2021-11-24 22:21:08 +01:00
log_assert ( port_wire - > port_input ) ;
auto d = i . second . first ;
if ( d = = 0 )
2020-05-14 03:02:05 +02:00
continue ;
2021-11-24 22:21:08 +01:00
auto offset = i . first . offset ;
2023-04-23 01:24:36 +02:00
if ( ! cell - > hasPort ( i . first . name ) )
continue ;
2021-11-24 22:21:08 +01:00
auto rhs = cell - > getPort ( i . first . name ) ;
2023-04-23 01:24:36 +02:00
if ( offset > = rhs . size ( ) )
continue ;
auto O = module - > addWire ( NEW_ID ) ;
2020-05-14 03:02:05 +02:00
# ifndef NDEBUG
2021-11-24 22:21:08 +01: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 " ,
2026-05-08 09:01:43 +02:00
cell - > type . unescape ( ) , i . first . name . unescape ( ) , offset , d ) ;
2021-11-24 22:21:08 +01:00
}
2020-05-14 03:02:05 +02:00
# endif
2021-11-24 22:21:08 +01: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-14 03:02:05 +02:00
}
2021-11-24 22:21:08 +01: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-14 03:02:05 +02:00
}
}
}
2020-01-14 21:25:45 +01:00
void prep_xaiger ( RTLIL : : Module * module , bool dff )
2019-12-31 03:00:49 +01:00
{
auto design = module - > design ;
log_assert ( design ) ;
SigMap sigmap ( module ) ;
2020-01-14 21:25:45 +01:00
dict < IdString , std : : vector < IdString > > box_ports ;
2019-12-31 03:00:49 +01:00
2020-01-11 17:42:58 +01:00
for ( auto cell : module - > cells ( ) ) {
2020-04-13 18:38:07 +02:00
if ( cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) )
2019-12-31 03:00:49 +01:00
continue ;
2020-01-24 03:56:06 +01:00
if ( cell - > has_keep_attr ( ) )
continue ;
2019-12-31 03:00:49 +01:00
2020-04-13 18:38:07 +02:00
auto inst_module = design - > module ( cell - > type ) ;
2020-04-21 23:12:28 +02:00
bool abc9_flop = inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_flop ) ;
2020-01-15 00:05:49 +01:00
if ( abc9_flop & & ! dff )
continue ;
2020-01-14 21:25:45 +01:00
2020-04-13 18:38:07 +02:00
if ( inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_box ) ) {
2020-01-14 21:25:45 +01: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 18:51:32 +02:00
if ( w - > get_bool_attribute ( ID : : abc9_carry ) ) {
2020-01-14 22:13:15 +01:00
log_assert ( w - > port_input ! = w - > port_output ) ;
if ( w - > port_input )
2020-01-14 21:25:45 +01:00
carry_in = port_name ;
2020-01-14 22:13:15 +01:00
else if ( w - > port_output )
2020-01-14 21:25:45 +01: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 18:17:01 +01:00
}
2019-12-31 03:00:49 +01:00
}
2020-01-14 21:25:45 +01:00
if ( box_ports . empty ( ) )
2019-12-31 03:00:49 +01:00
return ;
2026-02-24 18:55:11 +01:00
// Build the same topo graph for the initial pass and the optional retry.
auto build_toposort = [ & ] ( TopoSort < IdString , RTLIL : : sort_by_id_str > & toposort ) {
dict < SigBit , pool < IdString > > bit_drivers , bit_users ;
for ( auto cell : module - > cells ( ) ) {
if ( cell - > type . in ( ID ( $ _DFF_N_ ) , ID ( $ _DFF_P_ ) ) )
continue ;
if ( cell - > has_keep_attr ( ) )
continue ;
auto inst_module = design - > module ( cell - > type ) ;
bool abc9_flop = inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_flop ) ;
if ( abc9_flop & & ! dff )
continue ;
if ( ! ( inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_box ) ) & & ! yosys_celltypes . cell_known ( cell - > type ) )
continue ;
2019-12-31 03:00:49 +01:00
2026-02-24 18:55:11 +01:00
// TODO: Speed up toposort -- we care about box ordering only
for ( auto conn : cell - > connections ( ) ) {
if ( cell - > input ( conn . first ) )
for ( auto bit : sigmap ( conn . second ) )
bit_users [ bit ] . insert ( cell - > name ) ;
2020-01-11 17:42:58 +01:00
2026-02-24 18:55:11 +01:00
if ( cell - > output ( conn . first ) & & ! abc9_flop )
for ( auto bit : sigmap ( conn . second ) )
bit_drivers [ bit ] . insert ( cell - > name ) ;
}
toposort . node ( cell - > name ) ;
}
// Build producer -> consumer edges on sigmapped nets.
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 ) ;
if ( ys_debug ( 1 ) )
toposort . analyze_loops = true ;
return toposort . sort ( ) ;
} ;
// Build TopoSort in a container, as we may need to conditionally rebuild it on retry.
std : : optional < TopoSort < IdString , RTLIL : : sort_by_id_str > > toposort ;
toposort . emplace ( ) ;
bool no_loops = build_toposort ( toposort . value ( ) ) ;
// Fallback for residual loops after SCC cutting: insert additional
// breakers on non-box loop cells, then re-run toposort checks.
if ( ! no_loops ) {
SigSpec I , O ;
pool < IdString > broken_cells ;
for ( auto & loop : toposort . value ( ) . loops )
for ( auto cell_name : loop ) {
// Loop reports can overlap; cut each cell at most once.
if ( ! broken_cells . insert ( cell_name ) . second )
continue ;
auto cell = module - > cell ( cell_name ) ;
log_assert ( cell ) ;
auto inst_module = design - > module ( cell - > type ) ;
if ( inst_module & & inst_module - > get_bool_attribute ( ID : : abc9_box ) )
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 ) ) ;
I . append ( w ) ;
O . append ( c . second ) ;
c . second = w ;
}
}
}
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 ) ) ;
// Rebuild topo ordering after inserting the additional breakers.
toposort . emplace ( ) ;
no_loops = build_toposort ( toposort . value ( ) ) ;
}
}
2020-01-11 17:42:58 +01:00
if ( ys_debug ( 1 ) ) {
unsigned i = 0 ;
2026-02-24 18:55:11 +01:00
for ( auto & it : toposort . value ( ) . loops ) {
2020-01-11 17:42:58 +01:00
log ( " loop %d \n " , i + + ) ;
for ( auto cell_name : it ) {
auto cell = module - > cell ( cell_name ) ;
log_assert ( cell ) ;
2026-05-08 09:01:43 +02:00
log ( " \t %s (%s @ %s) \n " , cell , cell - > type . unescape ( ) , cell - > get_src_attribute ( ) ) ;
2020-01-11 17:42:58 +01:00
}
2019-12-31 03:00:49 +01:00
}
}
2020-01-11 17:42:58 +01:00
2019-12-31 03:00:49 +01:00
log_assert ( no_loops ) ;
2020-04-16 01:13:57 +02: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 21:25:45 +01:00
log_assert ( holes_module ) ;
dict < IdString , Cell * > cell_cache ;
2020-02-14 21:54:47 +01:00
TimingInfo timing ;
2020-01-14 21:25:45 +01:00
int port_id = 1 , box_count = 0 ;
2026-02-24 18:55:11 +01:00
for ( auto cell_name : toposort . value ( ) . sorted ) {
2019-12-31 03:00:49 +01:00
RTLIL : : Cell * cell = module - > cell ( cell_name ) ;
log_assert ( cell ) ;
RTLIL : : Module * box_module = design - > module ( cell - > type ) ;
2020-05-14 03:02:05 +02:00
if ( ! box_module )
continue ;
2020-05-14 06:56:06 +02:00
if ( ! box_module - > get_bool_attribute ( ID : : abc9_box ) )
2020-05-14 03:02:05 +02:00
continue ;
2021-03-05 23:13:15 +01:00
if ( ! cell - > parameters . empty ( ) )
2021-03-30 07:02:06 +02:00
{
2021-09-09 19:05:55 +02: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!
2026-05-08 09:01:43 +02:00
log_error ( " Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_box *) \n " , cell_name . unescape ( ) , cell - > type . unescape ( ) ) ;
2021-03-30 07:02:06 +02:00
}
2020-05-14 06:56:06 +02:00
log_assert ( box_module - > get_blackbox_attribute ( ) ) ;
2020-05-14 03:02:05 +02:00
cell - > attributes [ ID : : abc9_box_seq ] = box_count + + ;
2019-12-31 03:00:49 +01:00
2020-05-14 06:56:06 +02:00
auto r = cell_cache . insert ( cell - > type ) ;
2020-01-12 02:26:25 +01:00
auto & holes_cell = r . first - > second ;
if ( r . second ) {
2020-05-14 06:56:06 +02:00
if ( box_module - > get_bool_attribute ( ID : : whitebox ) ) {
2021-09-09 19:06:20 +02:00
holes_cell = holes_module - > addCell ( NEW_ID , cell - > type ) ;
2020-01-12 02:26:25 +01:00
2020-05-14 06:56:06 +02:00
if ( box_module - > has_processes ( ) )
2025-05-31 02:16:37 +02:00
Pass : : call_on_module ( design , box_module , " proc -noopt " ) ;
2020-01-13 00:19:41 +01:00
2020-01-12 02:26:25 +01:00
int box_inputs = 0 ;
for ( auto port_name : box_ports . at ( cell - > type ) ) {
2020-05-14 06:56:06 +02:00
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
2020-01-12 02:26:25 +01: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 )
2026-05-08 09:01:43 +02:00
conn = holes_module - > addWire ( stringf ( " %s.%s " , cell - > type , port_name . unescape ( ) ) , GetSize ( w ) ) ;
2020-01-12 02:26:25 +01:00
}
2019-12-31 03:00:49 +01:00
}
2020-05-14 06:56:06 +02:00
else // box_module is a blackbox
2020-01-12 02:26:25 +01:00
log_assert ( holes_cell = = nullptr ) ;
2019-12-31 03:00:49 +01:00
}
2020-01-12 02:26:25 +01:00
for ( auto port_name : box_ports . at ( cell - > type ) ) {
2020-05-14 06:56:06 +02:00
RTLIL : : Wire * w = box_module - > wire ( port_name ) ;
2020-01-12 02:26:25 +01:00
log_assert ( w ) ;
if ( ! w - > port_output )
continue ;
2026-05-08 09:01:43 +02:00
Wire * holes_wire = holes_module - > addWire ( stringf ( " $abc%s.%s " , cell - > name , port_name . unescape ( ) ) , GetSize ( w ) ) ;
2020-01-12 02:26:25 +01:00
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-31 03:00:49 +01:00
}
}
}
2020-02-11 17:34:13 +01:00
void prep_lut ( RTLIL : : Design * design , int maxlut )
{
2020-02-18 17:30:41 +01:00
TimingInfo timing ;
2020-02-14 20:41:43 +01:00
2020-04-20 18:39:35 +02:00
struct t_lut {
IdString name ;
int area ;
std : : vector < int > delays ;
} ;
std : : map < int , t_lut > table ;
2020-02-11 17:34:13 +01:00
for ( auto module : design - > modules ( ) ) {
2020-04-02 18:51:32 +02:00
auto it = module - > attributes . find ( ID : : abc9_lut ) ;
2020-02-11 17:34:13 +01:00
if ( it = = module - > attributes . end ( ) )
continue ;
2020-02-14 20:41:43 +01:00
2020-02-14 21:01:03 +01:00
auto & t = timing . setup_module ( module ) ;
2020-02-14 20:41:43 +01:00
2020-02-18 17:41:48 +01:00
TimingInfo : : NameBit o ;
2020-04-20 18:39:35 +02:00
std : : vector < int > delays ;
2020-02-14 20:41:43 +01:00
for ( const auto & i : t . comb ) {
auto & d = i . first . second ;
2020-02-18 17:41:48 +01:00
if ( o = = TimingInfo : : NameBit ( ) )
2020-02-11 17:34:13 +01:00
o = d ;
2020-02-14 20:41:43 +01:00
else if ( o ! = d )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_lut *) has more than one output. \n " , module ) ;
2020-04-20 18:39:35 +02:00
delays . push_back ( i . second ) ;
2020-02-18 17:30:41 +01:00
}
2020-02-14 20:41:43 +01:00
2020-04-20 18:39:35 +02:00
if ( GetSize ( delays ) = = 0 )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_lut *) has no specify entries. \n " , module ) ;
2020-04-20 18:39:35 +02:00
if ( maxlut & & GetSize ( delays ) > maxlut )
2020-02-11 17:34:13 +01:00
continue ;
2020-02-13 19:30:29 +01:00
// ABC requires non-decreasing LUT input delays
2020-04-20 18:39:35 +02: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 )
2026-05-08 09:01:43 +02:00
log_error ( " Modules '%s' and '%s' have conflicting (* abc9_lut *) values. \n " , module , r . first - > second . name . unescape ( ) ) ;
2020-04-20 18:39:35 +02:00
if ( r . first - > second . delays ! = entry . delays )
2026-05-08 09:01:43 +02:00
log_error ( " Modules '%s' and '%s' have conflicting specify entries. \n " , module , r . first - > second . name . unescape ( ) ) ;
2020-04-20 18:39:35 +02:00
}
2020-02-11 17:34:13 +01:00
}
2020-04-20 18:39:35 +02:00
if ( table . empty ( ) )
log_error ( " Design does not contain any modules with (* abc9_lut *). \n " ) ;
2020-02-13 18:48:48 +01:00
std : : stringstream ss ;
2020-04-20 18:39:35 +02:00
const auto & front = * table . begin ( ) ;
2020-02-13 18:48:48 +01: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 18:39:35 +02:00
for ( int i = 1 ; i < front . first ; i + + ) {
2020-02-13 18:48:48 +01:00
ss < < " # $__ABC9_LUT " < < i < < std : : endl ;
2020-04-20 18:39:35 +02:00
ss < < i < < " " < < front . second . area ;
2020-02-13 18:48:48 +01:00
for ( int j = 0 ; j < i ; j + + )
2020-04-20 18:39:35 +02:00
ss < < " " < < front . second . delays [ j ] ;
2020-02-13 18:48:48 +01:00
ss < < std : : endl ;
}
for ( const auto & i : table ) {
2026-05-08 09:01:43 +02:00
ss < < " # " < < i . second . name . unescape ( ) < < std : : endl ;
2020-04-20 18:39:35 +02:00
ss < < i . first < < " " < < i . second . area ;
for ( const auto & j : i . second . delays )
2020-02-13 18:48:48 +01:00
ss < < " " < < j ;
ss < < std : : endl ;
}
2020-02-11 17:34:13 +01: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 18:38:07 +02:00
void prep_box ( RTLIL : : Design * design )
2020-02-11 17:54:13 +01:00
{
2020-02-18 17:30:41 +01:00
TimingInfo timing ;
2020-02-14 20:41:43 +01:00
2020-02-11 23:22:43 +01:00
int abc9_box_id = 1 ;
2021-09-09 19:06:31 +02:00
std : : stringstream ss ;
2020-02-11 23:22:43 +01:00
dict < IdString , std : : vector < IdString > > box_ports ;
2020-02-11 20:38:49 +01:00
for ( auto module : design - > modules ( ) ) {
2020-04-21 21:22:39 +02:00
auto it = module - > attributes . find ( ID : : abc9_box ) ;
if ( it = = module - > attributes . end ( ) )
continue ;
bool box = it - > second . as_bool ( ) ;
if ( ! box )
2020-04-13 18:38:07 +02:00
continue ;
2020-02-11 23:22:43 +01:00
2020-04-13 18:38:07 +02:00
auto r = module - > attributes . insert ( ID : : abc9_box_id ) ;
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 23:22:43 +01:00
2026-05-08 09:01:43 +02:00
ss < < module - > name . unescape ( ) < < " " < < r . first - > second . as_int ( ) ;
2020-04-16 00:50:57 +02:00
log_assert ( module - > get_bool_attribute ( ID : : whitebox ) ) ;
ss < < " " < < " 1 " ;
2020-04-13 18:38:07 +02:00
ss < < " " < < num_inputs < < " " < < num_outputs < < std : : endl ;
2020-02-11 23:22:43 +01:00
2020-04-13 18:38:07 +02: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 < < " " ;
2026-05-08 09:01:43 +02:00
ss < < wire - > name . unescape ( ) ;
2020-04-13 18:38:07 +02:00
}
ss < < std : : endl ;
auto & t = timing . setup_module ( module ) . required ;
2020-04-16 00:50:57 +02:00
if ( t . empty ( ) )
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information. \n " , module ) ;
2020-04-16 00:50:57 +02:00
2020-04-13 18:38:07 +02: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 22:21:08 +01:00
// Assume that no setup time means zero
ss < < 0 ;
2020-04-13 18:38:07 +02:00
else {
2021-11-24 22:21:08 +01:00
ss < < it - > second . first ;
2020-02-14 20:11:34 +01:00
# ifndef NDEBUG
2020-04-13 18:38:07 +02:00
if ( ys_debug ( 1 ) ) {
static std : : set < std : : pair < IdString , IdString > > seen ;
2026-05-08 09:01:43 +02:00
if ( seen . emplace ( module - > name , port_name ) . second ) log ( " %s.%s abc9_required = %d \n " , module ,
port_name . unescape ( ) , it - > second . first ) ;
2020-02-18 17:30:41 +01:00
}
2020-04-13 18:38:07 +02:00
# endif
2020-02-13 20:15:59 +01:00
}
2020-02-11 23:22:43 +01:00
}
2020-04-13 18:38:07 +02:00
ss < < " # $_DFF_[NP]_.D " < < std : : endl ;
ss < < std : : endl ;
2020-02-11 23:22:43 +01:00
}
2020-02-13 20:15:59 +01:00
else {
2020-04-13 18:38:07 +02: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 23:22:43 +01:00
2020-04-13 18:38:07 +02:00
if ( carry_in ! = IdString ( ) ) {
r2 . first - > second . push_back ( carry_in ) ;
r2 . first - > second . push_back ( carry_out ) ;
2020-02-11 23:22:43 +01:00
}
}
2020-04-13 18:38:07 +02: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 23:22:43 +01:00
}
2020-02-14 20:41:43 +01:00
2026-05-08 09:01:43 +02:00
ss < < module - > name . unescape ( ) < < " " < < module - > attributes . at ( ID : : abc9_box_id ) . as_int ( ) ;
2024-11-13 16:05:39 +01:00
bool has_model = module - > get_bool_attribute ( ID : : whitebox ) | | ! module - > get_bool_attribute ( ID : : blackbox ) ;
ss < < " " < < ( has_model ? " 1 " : " 0 " ) ;
2020-04-13 18:38:07 +02:00
ss < < " " < < GetSize ( inputs ) < < " " < < GetSize ( outputs ) < < std : : endl ;
2020-02-14 20:41:43 +01:00
2020-04-13 18:38:07 +02:00
bool first = true ;
ss < < " # " ;
2020-02-11 20:38:49 +01:00
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
2020-04-13 18:38:07 +02:00
if ( GetSize ( i . wire ) = = 1 )
2026-05-08 09:01:43 +02:00
ss < < i . wire - > name . unescape ( ) ;
2020-02-14 20:41:43 +01:00
else
2026-05-08 09:01:43 +02:00
ss < < i . wire - > name . unescape ( ) < < " [ " < < i . offset < < " ] " ;
2020-02-11 20:38:49 +01:00
}
ss < < std : : endl ;
2020-01-10 20:45:41 +01:00
2020-04-16 00:50:57 +02:00
auto & t = timing . setup_module ( module ) ;
2024-12-05 16:19:55 +01:00
if ( t . comb . empty ( ) & & ! outputs . empty ( ) & & ! inputs . empty ( ) ) {
2026-05-08 09:01:43 +02:00
log_error ( " Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information. \n " , module ) ;
2024-12-05 16:19:55 +01:00
}
2020-04-13 18:38:07 +02:00
for ( const auto & o : outputs ) {
first = true ;
for ( const auto & i : inputs ) {
if ( first )
first = false ;
else
ss < < " " ;
2020-04-16 00:50:57 +02:00
auto jt = t . comb . find ( TimingInfo : : BitBit ( i , o ) ) ;
if ( jt = = t . comb . end ( ) )
2020-04-13 18:38:07 +02:00
ss < < " - " ;
else
ss < < jt - > second ;
}
ss < < " # " ;
if ( GetSize ( o . wire ) = = 1 )
2026-05-08 09:01:43 +02:00
ss < < o . wire - > name . unescape ( ) ;
2020-04-13 18:38:07 +02:00
else
2026-05-08 09:01:43 +02:00
ss < < o . wire - > name . unescape ( ) < < " [ " < < o . offset < < " ] " ;
2020-04-13 18:38:07 +02:00
ss < < std : : endl ;
}
ss < < std : : endl ;
2020-02-11 20:38:49 +01:00
}
2020-01-10 20:45:41 +01:00
}
2020-02-11 23:22:43 +01:00
// ABC expects at least one box
if ( ss . tellp ( ) = = 0 )
ss < < " (dummy) 1 0 0 0 " ;
2020-02-11 17:54:13 +01:00
design - > scratchpad_set_string ( " abc9_ops.box_library " , ss . str ( ) ) ;
}
2020-01-10 20:45:41 +01:00
2020-02-11 17:54:13 +01: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 20:45:41 +01:00
ofs . close ( ) ;
}
2025-09-16 13:40:12 +02:00
static void replace_zbufs ( Design * design )
{
design - > bufNormalize ( true ) ;
std : : vector < Cell * > zbufs ;
for ( auto mod : design - > modules ( ) ) {
zbufs . clear ( ) ;
for ( auto cell : mod - > cells ( ) ) {
if ( cell - > type ! = ID ( $ buf ) )
continue ;
auto & sig = cell - > getPort ( ID : : A ) ;
for ( int i = 0 ; i < GetSize ( sig ) ; + + i ) {
if ( sig [ i ] = = State : : Sz ) {
zbufs . push_back ( cell ) ;
break ;
}
}
}
for ( auto cell : zbufs ) {
auto sig = cell - > getPort ( ID : : A ) ;
for ( int i = 0 ; i < GetSize ( sig ) ; + + i ) {
if ( sig [ i ] = = State : : Sz ) {
Wire * w = mod - > addWire ( NEW_ID ) ;
Cell * ud = mod - > addCell ( NEW_ID , ID ( $ tribuf ) ) ;
2026-05-06 15:03:07 +02:00
ud - > set_bool_attribute ( ID : : aiger2_zbuf ) ;
2025-09-16 13:40:12 +02:00
ud - > setParam ( ID : : WIDTH , 1 ) ;
ud - > setPort ( ID : : Y , w ) ;
ud - > setPort ( ID : : EN , State : : S0 ) ;
ud - > setPort ( ID : : A , State : : S0 ) ;
sig [ i ] = w ;
}
}
cell - > setPort ( ID : : A , sig ) ;
}
mod - > bufNormalize ( ) ;
}
2025-10-07 17:35:32 +02:00
design - > bufNormalize ( false ) ;
2025-09-16 13:40:12 +02:00
}
static void restore_zbufs ( Design * design )
{
std : : vector < Cell * > to_remove ;
for ( auto mod : design - > modules ( ) ) {
to_remove . clear ( ) ;
for ( auto cell : mod - > cells ( ) )
if ( cell - > type = = ID ( $ tribuf ) & & cell - > has_attribute ( ID ( aiger2_zbuf ) ) )
to_remove . push_back ( cell ) ;
for ( auto cell : to_remove ) {
SigSpec sig_y = cell - > getPort ( ID : : Y ) ;
mod - > addBuf ( NEW_ID , Const ( State : : Sz , GetSize ( sig_y ) ) , sig_y ) ;
mod - > remove ( cell ) ;
}
}
}
2019-12-31 07:56:19 +01:00
struct Abc9OpsPass : public Pass {
Abc9OpsPass ( ) : Pass ( " abc9_ops " , " helper functions for ABC9 " ) { }
2020-06-19 01:34:52 +02:00
void help ( ) override
2019-12-28 14:07:46 +01:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " abc9_ops [options] [selection] \n " ) ;
log ( " \n " ) ;
2020-01-14 21:25:45 +01: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 22:21:58 +01:00
log ( " -check \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " check that the design is valid, e.g. (* abc9_box_id *) values are \n " ) ;
log ( " unique, (* abc9_carry *) is only given for one input/output port, etc. \n " ) ;
2020-01-14 22:21:58 +01:00
log ( " \n " ) ;
2020-04-21 21:22:39 +02:00
log ( " -prep_hier \n " ) ;
2020-05-14 06:56:06 +02: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 " ) ;
2022-08-24 00:28:27 +02:00
log ( " $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC \n " ) ;
log ( " limitation -- will be derived. \n " ) ;
2020-04-21 21:22:39 +02: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-14 06:56:06 +02: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 22:07:19 +02:00
log ( " specify block. \n " ) ;
2020-04-21 21:22:39 +02: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 18:38:07 +02:00
log ( " \n " ) ;
2020-04-21 21:30:25 +02:00
log ( " -prep_dff_submod \n " ) ;
2020-04-22 22:07:19 +02:00
log ( " within (* abc9_flop *) modules, rewrite all edge-sensitive path \n " ) ;
log ( " declarations and $setup() timing checks ($specify3 and $specrule cells) \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port \n " ) ;
log ( " to the DFF's 'D' port. this is to prepare such specify cells to be moved \n " ) ;
2020-04-22 22:07:19 +02:00
log ( " into the flop box. \n " ) ;
2020-04-13 18:38:07 +02:00
log ( " \n " ) ;
log ( " -prep_dff_unmap \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " populate the '$abc9_unmap' design with techmap rules for mapping \n " ) ;
log ( " *_$abc9_flop cells back into their derived cell types (where the rules \n " ) ;
log ( " created by -prep_hier will then map back to the original cell with \n " ) ;
log ( " parameters). \n " ) ;
2020-04-13 18:38:07 +02:00
log ( " \n " ) ;
2020-01-14 22:21:58 +01:00
log ( " -prep_delays \n " ) ;
log ( " insert `$__ABC9_DELAY' blackbox cells into the design to account for \n " ) ;
2020-02-14 21:54:47 +01:00
log ( " certain required times. \n " ) ;
2020-01-14 22:21:58 +01:00
log ( " \n " ) ;
2021-03-30 07:01:57 +02:00
log ( " -break_scc \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " for an arbitrarily chosen cell in each unique SCC of each selected \n " ) ;
log ( " module (tagged with an (* abc9_scc_id = <int> *) attribute) interrupt \n " ) ;
log ( " all wires driven by this cell's outputs with a temporary \n " ) ;
log ( " $__ABC9_SCC_BREAKER cell to break the SCC. \n " ) ;
2020-01-14 21:25:45 +01:00
log ( " \n " ) ;
log ( " -prep_xaiger \n " ) ;
log ( " prepare the design for XAIGER output. this includes computing the \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " topological ordering of ABC9 boxes, as well as preparing the \n " ) ;
log ( " '$abc9_holes' design that contains the logic behaviour of ABC9 \n " ) ;
log ( " whiteboxes. \n " ) ;
2020-01-14 21:25:45 +01:00
log ( " \n " ) ;
2020-01-14 21:40:36 +01:00
log ( " -dff \n " ) ;
2022-08-24 00:28:27 +02:00
log ( " consider flop cells (those instantiating modules marked with \n " ) ;
log ( " (* abc9_flop *)) during -prep_{delays,xaiger,box}. \n " ) ;
2020-01-14 21:40:36 +01:00
log ( " \n " ) ;
2020-02-11 17:34:13 +01:00
log ( " -prep_lut <maxlut> \n " ) ;
2020-02-11 20:38:49 +01:00
log ( " pre-compute the lut library by analysing all modules marked with \n " ) ;
log ( " (* abc9_lut=<area> *). \n " ) ;
2020-02-11 17:34:13 +01:00
log ( " \n " ) ;
log ( " -write_lut <dst> \n " ) ;
2020-02-11 17:54:13 +01:00
log ( " write the pre-computed lut library to <dst>. \n " ) ;
2020-02-11 17:34:13 +01:00
log ( " \n " ) ;
2020-02-11 20:38:49 +01:00
log ( " -prep_box \n " ) ;
log ( " pre-compute the box library by analysing all modules marked with \n " ) ;
2020-02-13 00:25:30 +01:00
log ( " (* abc9_box *). \n " ) ;
2020-02-11 17:54:13 +01:00
log ( " \n " ) ;
log ( " -write_box <dst> \n " ) ;
log ( " write the pre-computed box library to <dst>. \n " ) ;
2020-01-14 22:21:58 +01:00
log ( " \n " ) ;
2019-12-28 14:07:46 +01:00
}
2020-06-19 01:34:52 +02:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
2019-12-28 14:07:46 +01:00
{
log_header ( design , " Executing ABC9_OPS pass (helper functions for ABC9). \n " ) ;
2020-01-10 20:45:41 +01:00
bool check_mode = false ;
2020-01-14 22:21:58 +01:00
bool prep_delays_mode = false ;
2021-03-30 07:01:57 +02:00
bool break_scc_mode = false ;
2020-04-21 21:22:39 +02:00
bool prep_hier_mode = false ;
bool prep_bypass_mode = false ;
2020-04-21 21:30:25 +02:00
bool prep_dff_mode = false , prep_dff_submod_mode = false , prep_dff_unmap_mode = false ;
2020-01-14 21:25:45 +01:00
bool prep_xaiger_mode = false ;
2020-02-11 17:34:13 +01:00
bool prep_lut_mode = false ;
2020-02-11 20:38:49 +01:00
bool prep_box_mode = false ;
2025-09-16 13:40:12 +02:00
bool replace_zbufs_mode = false ;
bool restore_zbufs_mode = false ;
2020-01-04 18:17:01 +01:00
bool dff_mode = false ;
2020-02-11 17:34:13 +01:00
std : : string write_lut_dst ;
int maxlut = 0 ;
2020-02-11 20:38:49 +01:00
std : : string write_box_dst ;
2019-12-28 14:07:46 +01:00
2020-04-13 18:38:07 +02:00
bool valid = false ;
2019-12-28 14:07:46 +01:00
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
std : : string arg = args [ argidx ] ;
2020-01-10 20:45:41 +01:00
if ( arg = = " -check " ) {
check_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-01-10 20:45:41 +01:00
continue ;
}
2021-03-30 07:01:57 +02:00
if ( arg = = " -break_scc " ) {
break_scc_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
continue ;
}
2020-04-21 21:22:39 +02: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 18:38:07 +02:00
valid = true ;
2019-12-28 14:07:46 +01:00
continue ;
}
2020-04-21 21:30:25 +02:00
if ( arg = = " -prep_dff_submod " ) {
prep_dff_submod_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
continue ;
}
if ( arg = = " -prep_dff_unmap " ) {
prep_dff_unmap_mode = true ;
valid = true ;
2019-12-31 01:36:33 +01:00
continue ;
}
2020-01-14 21:25:45 +01:00
if ( arg = = " -prep_xaiger " ) {
prep_xaiger_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
2019-12-31 03:00:49 +01:00
continue ;
}
2020-01-14 22:21:58 +01:00
if ( arg = = " -prep_delays " ) {
prep_delays_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-01-10 20:45:41 +01:00
continue ;
}
2020-02-11 17:34:13 +01:00
if ( arg = = " -prep_lut " & & argidx + 1 < args . size ( ) ) {
prep_lut_mode = true ;
maxlut = atoi ( args [ + + argidx ] . c_str ( ) ) ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-02-11 17:54:13 +01:00
continue ;
}
2020-02-11 17:34:13 +01:00
if ( arg = = " -write_lut " & & argidx + 1 < args . size ( ) ) {
write_lut_dst = args [ + + argidx ] ;
rewrite_filename ( write_lut_dst ) ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-02-11 17:34:13 +01:00
continue ;
}
2020-02-11 20:38:49 +01:00
if ( arg = = " -prep_box " ) {
prep_box_mode = true ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-02-11 17:34:13 +01:00
continue ;
}
2020-02-11 17:54:13 +01:00
if ( arg = = " -write_box " & & argidx + 1 < args . size ( ) ) {
2020-01-10 20:45:41 +01:00
write_box_dst = args [ + + argidx ] ;
rewrite_filename ( write_box_dst ) ;
2020-04-13 18:38:07 +02:00
valid = true ;
2020-01-10 20:45:41 +01:00
continue ;
}
2020-01-04 18:17:01 +01:00
if ( arg = = " -dff " ) {
dff_mode = true ;
continue ;
}
2025-09-16 13:40:12 +02:00
if ( arg = = " -replace_zbufs " ) {
replace_zbufs_mode = true ;
valid = true ;
continue ;
}
if ( arg = = " -restore_zbufs " ) {
restore_zbufs_mode = true ;
valid = true ;
continue ;
}
2019-12-28 14:07:46 +01:00
break ;
}
extra_args ( args , argidx , design ) ;
2020-04-13 18:38:07 +02:00
if ( ! valid )
2025-09-16 13:40:12 +02:00
log_cmd_error ( " At least one of -check, -break_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate, -{replace,restore}_zbufs must be specified. \n " ) ;
2020-01-11 17:42:58 +01:00
2026-06-08 11:57:12 +02:00
if ( dff_mode & & ! check_mode & & ! prep_hier_mode & & ! prep_delays_mode & & ! prep_xaiger_mode )
log_cmd_error ( " '-dff' option is only relevant for -prep_{hier,delay,xaiger}. \n " ) ;
2020-01-10 20:45:41 +01:00
2025-09-16 13:40:12 +02:00
if ( replace_zbufs_mode )
replace_zbufs ( design ) ;
if ( restore_zbufs_mode )
restore_zbufs ( design ) ;
2020-01-10 20:45:41 +01:00
if ( check_mode )
2020-04-21 21:22:39 +02: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 21:30:25 +02:00
if ( prep_dff_submod_mode )
prep_dff_submod ( design ) ;
2020-04-13 18:38:07 +02:00
if ( prep_dff_unmap_mode )
prep_dff_unmap ( design ) ;
2020-01-14 22:21:58 +01:00
if ( prep_delays_mode )
2020-02-13 20:15:59 +01:00
prep_delays ( design , dff_mode ) ;
2020-02-11 17:34:13 +01:00
if ( prep_lut_mode )
prep_lut ( design , maxlut ) ;
2020-02-11 20:38:49 +01:00
if ( prep_box_mode )
2020-04-13 18:38:07 +02:00
prep_box ( design ) ;
2020-01-10 20:45:41 +01:00
2019-12-28 14:07:46 +01:00
for ( auto mod : design - > selected_modules ( ) ) {
2019-12-31 03:46:22 +01:00
if ( mod - > processes . size ( ) > 0 ) {
2026-05-08 09:01:43 +02:00
log ( " Skipping module %s as it contains processes. \n " , mod ) ;
2019-12-31 03:46:22 +01:00
continue ;
}
2020-01-11 17:42:58 +01:00
if ( ! design - > selected_whole_module ( mod ) )
2026-05-08 09:01:43 +02:00
log_error ( " Can't handle partially selected module %s! \n " , mod ) ;
2020-01-11 17:42:58 +01:00
2020-02-11 17:34:13 +01:00
if ( ! write_lut_dst . empty ( ) )
write_lut ( mod , write_lut_dst ) ;
if ( ! write_box_dst . empty ( ) )
2020-02-11 17:54:13 +01:00
write_box ( mod , write_box_dst ) ;
2021-03-30 07:01:57 +02:00
if ( break_scc_mode )
break_scc ( mod ) ;
2020-01-14 21:25:45 +01:00
if ( prep_xaiger_mode )
prep_xaiger ( mod , dff_mode ) ;
2019-12-28 14:07:46 +01:00
}
}
2019-12-31 07:56:19 +01:00
} Abc9OpsPass ;
2019-12-28 14:07:46 +01:00
PRIVATE_NAMESPACE_END