2020-04-20 16:13:59 -05:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2020 Alberto Gonzalez < boqwxp @ airmail . cc >
*
* 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"
# include "kernel/rtlil.h"
# include "kernel/log.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct GliftPass : public Pass {
2020-04-20 22:21:28 -05:00
private :
2020-04-23 01:41:58 -05:00
bool opt_create , opt_sketchify , opt_taintconstants , opt_keepoutputs , opt_nomodeloptimize ;
2020-04-20 22:21:28 -05:00
std : : vector < std : : string > args ;
std : : vector < std : : string > : : size_type argidx ;
2020-04-22 16:33:22 -05:00
std : : vector < RTLIL : : Wire * > new_taint_outputs ;
2020-04-23 01:41:58 -05:00
std : : vector < RTLIL : : SigSpec > meta_mux_selects ;
2020-04-20 22:21:28 -05:00
RTLIL : : Module * module ;
void parse_args ( ) {
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
if ( args [ argidx ] = = " -create " ) {
opt_create = true ;
continue ;
}
2020-04-22 01:16:12 -05:00
if ( args [ argidx ] = = " -sketchify " ) {
opt_sketchify = true ;
continue ;
}
2020-04-20 22:21:28 -05:00
if ( args [ argidx ] = = " -taint-constants " ) {
opt_taintconstants = true ;
continue ;
}
2020-04-22 16:33:22 -05:00
if ( args [ argidx ] = = " -keep-outputs " ) {
opt_keepoutputs = true ;
continue ;
}
2020-04-23 01:41:58 -05:00
if ( args [ argidx ] = = " -no-model-optimize " ) {
opt_nomodeloptimize = true ;
continue ;
}
2020-04-20 22:21:28 -05:00
break ;
}
2020-04-22 01:16:12 -05:00
if ( ! opt_create & & ! opt_sketchify ) log_cmd_error ( " One of `-create` or `-sketchify` must be specified. \n " ) ;
if ( opt_create & & opt_sketchify ) log_cmd_error ( " Only one of `-create` or `-sketchify` may be specified. \n " ) ;
2020-04-20 22:21:28 -05:00
}
RTLIL : : SigSpec get_corresponding_taint_signal ( RTLIL : : SigSpec sig ) {
RTLIL : : SigSpec ret ;
//Get the connected wire for the cell port:
log_assert ( sig . is_wire ( ) | | sig . is_fully_const ( ) ) ;
log_assert ( sig . is_wire ( ) | | sig . is_fully_const ( ) ) ;
//Get a SigSpec for the corresponding taint signal for the cell port, creating one if necessary:
if ( sig . is_wire ( ) ) {
RTLIL : : Wire * w = module - > wire ( sig . as_wire ( ) - > name . str ( ) + " _t " ) ;
if ( w = = nullptr ) w = module - > addWire ( sig . as_wire ( ) - > name . str ( ) + " _t " , 1 ) ;
ret = w ;
}
else if ( sig . is_fully_const ( ) & & opt_taintconstants )
ret = RTLIL : : State : : S1 ;
else if ( sig . is_fully_const ( ) )
ret = RTLIL : : State : : S0 ;
else
log_cmd_error ( " Cell port SigSpec has unexpected type. \n " ) ;
//Finally, if the cell port was a module input or output, make sure the corresponding taint signal is marked, too:
if ( sig . is_wire ( ) & & sig . as_wire ( ) - > port_input )
ret . as_wire ( ) - > port_input = true ;
if ( sig . is_wire ( ) & & sig . as_wire ( ) - > port_output )
2020-04-22 16:33:22 -05:00
new_taint_outputs . push_back ( ret . as_wire ( ) ) ;
2020-04-20 22:21:28 -05:00
return ret ;
}
2020-04-22 01:16:12 -05:00
void add_precise_GLIFT_logic ( const RTLIL : : Cell * cell , RTLIL : : SigSpec & port_a , RTLIL : : SigSpec & port_a_taint , RTLIL : : SigSpec & port_b , RTLIL : : SigSpec & port_b_taint , RTLIL : : SigSpec & port_y_taint ) {
//AKA AN2_SH2 or OR2_SH2
RTLIL : : SigSpec n_port_a = module - > LogicNot ( cell - > name . str ( ) + " _t_1_1 " , port_a , false , cell - > get_src_attribute ( ) ) ;
RTLIL : : SigSpec n_port_b = module - > LogicNot ( cell - > name . str ( ) + " _t_1_2 " , port_b , false , cell - > get_src_attribute ( ) ) ;
auto subexpr1 = module - > And ( cell - > name . str ( ) + " _t_1_3 " , ( cell - > type = = " $_AND_ " ) ? port_a : n_port_a , port_b_taint , false , cell - > get_src_attribute ( ) ) ;
auto subexpr2 = module - > And ( cell - > name . str ( ) + " _t_1_4 " , ( cell - > type = = " $_AND_ " ) ? port_b : n_port_b , port_a_taint , false , cell - > get_src_attribute ( ) ) ;
auto subexpr3 = module - > And ( cell - > name . str ( ) + " _t_1_5 " , port_a_taint , port_b_taint , false , cell - > get_src_attribute ( ) ) ;
auto subexpr4 = module - > Or ( cell - > name . str ( ) + " _t_1_6 " , subexpr1 , subexpr2 , false , cell - > get_src_attribute ( ) ) ;
module - > addOr ( cell - > name . str ( ) + " _t_1_7 " , subexpr4 , subexpr3 , port_y_taint , false , cell - > get_src_attribute ( ) ) ;
}
void add_imprecise_GLIFT_logic_1 ( const RTLIL : : Cell * cell , RTLIL : : SigSpec & port_a , RTLIL : : SigSpec & port_a_taint , RTLIL : : SigSpec & port_b , RTLIL : : SigSpec & port_b_taint , RTLIL : : SigSpec & port_y_taint ) {
//AKA AN2_SH3 or OR2_SH3
RTLIL : : SigSpec n_port_a = module - > LogicNot ( cell - > name . str ( ) + " _t_2_1 " , port_a , false , cell - > get_src_attribute ( ) ) ;
auto subexpr1 = module - > And ( cell - > name . str ( ) + " _t_2_2 " , ( cell - > type = = " $_AND_ " ) ? port_b : n_port_a , ( cell - > type = = " $_AND_ " ) ? port_a_taint : port_b_taint , false , cell - > get_src_attribute ( ) ) ;
module - > addOr ( cell - > name . str ( ) + " _t_2_3 " , ( cell - > type = = " $_AND_ " ) ? port_b_taint : port_a_taint , subexpr1 , port_y_taint , false , cell - > get_src_attribute ( ) ) ;
}
void add_imprecise_GLIFT_logic_2 ( const RTLIL : : Cell * cell , RTLIL : : SigSpec & port_a , RTLIL : : SigSpec & port_a_taint , RTLIL : : SigSpec & port_b , RTLIL : : SigSpec & port_b_taint , RTLIL : : SigSpec & port_y_taint ) {
//AKA AN2_SH4 or OR2_SH4
RTLIL : : SigSpec n_port_b = module - > LogicNot ( cell - > name . str ( ) + " _t_3_1 " , port_b , false , cell - > get_src_attribute ( ) ) ;
auto subexpr1 = module - > And ( cell - > name . str ( ) + " _t_3_2 " , ( cell - > type = = " $_AND_ " ) ? port_a : n_port_b , ( cell - > type = = " $_AND_ " ) ? port_b_taint : port_a_taint , false , cell - > get_src_attribute ( ) ) ;
module - > addOr ( cell - > name . str ( ) + " _t_3_3 " , ( cell - > type = = " $_AND_ " ) ? port_a_taint : port_b_taint , subexpr1 , port_y_taint , false , cell - > get_src_attribute ( ) ) ;
}
void add_imprecise_GLIFT_logic_3 ( const RTLIL : : Cell * cell , RTLIL : : SigSpec & port_a_taint , RTLIL : : SigSpec & port_b_taint , RTLIL : : SigSpec & port_y_taint ) {
//AKA AN2_SH5 or OR2_SH5
module - > addOr ( cell - > name . str ( ) + " _t_4_1 " , port_a_taint , port_b_taint , port_y_taint , false , cell - > get_src_attribute ( ) ) ;
}
2020-04-23 01:41:58 -05:00
RTLIL : : SigSpec score_metamux_select ( const RTLIL : : SigSpec & metamux_select ) {
log_assert ( metamux_select . is_wire ( ) ) ;
log_assert ( metamux_select . as_wire ( ) - > width = = 2 ) ;
RTLIL : : Const precise_y_cost ( 5 ) ; //5 AND/OR gates
RTLIL : : Const imprecise_1_y_cost ( 2 ) ;
RTLIL : : Const imprecise_2_y_cost ( 2 ) ;
RTLIL : : Const imprecise_3_y_cost ( 1 ) ;
RTLIL : : SigSpec meta_mux1 = module - > Pmux ( metamux_select . as_wire ( ) - > name . str ( ) + " _mux1 " , precise_y_cost , imprecise_1_y_cost , metamux_select [ 1 ] , metamux_select . as_wire ( ) - > get_src_attribute ( ) ) ;
RTLIL : : SigSpec meta_mux2 = module - > Pmux ( metamux_select . as_wire ( ) - > name . str ( ) + " _mux2 " , imprecise_2_y_cost , imprecise_3_y_cost , metamux_select [ 1 ] , metamux_select . as_wire ( ) - > get_src_attribute ( ) ) ;
RTLIL : : SigSpec ret = module - > Pmux ( metamux_select . as_wire ( ) - > name . str ( ) + " _mux3 " , meta_mux1 , meta_mux2 , metamux_select [ 0 ] , metamux_select . as_wire ( ) - > get_src_attribute ( ) ) ;
return ret ;
}
2020-04-22 01:16:12 -05:00
void create_glift_logic ( ) {
2020-04-20 22:21:28 -05:00
std : : vector < RTLIL : : SigSig > connections ( module - > connections ( ) ) ;
std : : vector < RTLIL : : SigSig > new_connections ;
for ( auto & cell : module - > cells ( ) . to_vector ( ) ) {
if ( ! cell - > type . in ( " $_AND_ " , " $_OR_ " , " $_NOT_ " , " $anyconst " , " $allconst " , " $assume " , " $assert " ) ) {
log_cmd_error ( " Invalid cell type \" %s \" found. Module must be techmapped. \n " , cell - > type . c_str ( ) ) ;
}
if ( cell - > type . in ( " $_AND_ " , " $_OR_ " ) ) {
const unsigned int A = 0 , B = 1 , Y = 2 ;
const unsigned int NUM_PORTS = 3 ;
RTLIL : : SigSpec ports [ NUM_PORTS ] = { cell - > getPort ( ID : : A ) , cell - > getPort ( ID : : B ) , cell - > getPort ( ID : : Y ) } ;
RTLIL : : SigSpec port_taints [ NUM_PORTS ] ;
if ( ports [ A ] . size ( ) ! = 1 | | ports [ B ] . size ( ) ! = 1 | | ports [ Y ] . size ( ) ! = 1 )
log_cmd_error ( " Multi-bit signal found. Run `splitnets` first. \n " ) ;
for ( unsigned int i = 0 ; i < NUM_PORTS ; + + i )
port_taints [ i ] = get_corresponding_taint_signal ( ports [ i ] ) ;
2020-04-22 01:16:12 -05:00
if ( opt_create )
add_precise_GLIFT_logic ( cell , ports [ A ] , port_taints [ A ] , ports [ B ] , port_taints [ B ] , port_taints [ Y ] ) ;
else if ( opt_sketchify ) {
RTLIL : : SigSpec precise_y ( module - > addWire ( cell - > name . str ( ) + " _y1 " , 1 ) ) ,
imprecise_1_y ( module - > addWire ( cell - > name . str ( ) + " _y2 " , 1 ) ) ,
imprecise_2_y ( module - > addWire ( cell - > name . str ( ) + " _y3 " , 1 ) ) ,
imprecise_3_y ( module - > addWire ( cell - > name . str ( ) + " _y4 " , 1 ) ) ;
add_precise_GLIFT_logic ( cell , ports [ A ] , port_taints [ A ] , ports [ B ] , port_taints [ B ] , precise_y ) ;
add_imprecise_GLIFT_logic_1 ( cell , ports [ A ] , port_taints [ A ] , ports [ B ] , port_taints [ B ] , imprecise_1_y ) ;
add_imprecise_GLIFT_logic_2 ( cell , ports [ A ] , port_taints [ A ] , ports [ B ] , port_taints [ B ] , imprecise_2_y ) ;
add_imprecise_GLIFT_logic_3 ( cell , port_taints [ A ] , port_taints [ B ] , imprecise_3_y ) ;
RTLIL : : SigSpec meta_mux_select ( module - > addWire ( cell - > name . str ( ) + " _sel " , 2 ) ) ;
2020-04-23 01:41:58 -05:00
meta_mux_selects . push_back ( meta_mux_select ) ;
2020-04-22 01:16:12 -05:00
new_connections . emplace_back ( meta_mux_select , module - > Anyconst ( cell - > name . str ( ) + " _hole " , 2 , cell - > get_src_attribute ( ) ) ) ;
2020-04-23 01:41:58 -05:00
2020-04-22 01:16:12 -05:00
RTLIL : : SigSpec meta_mux1 ( module - > Mux ( cell - > name . str ( ) + " _mux1 " , precise_y , imprecise_1_y , meta_mux_select [ 1 ] ) ) ;
RTLIL : : SigSpec meta_mux2 ( module - > Mux ( cell - > name . str ( ) + " _mux2 " , imprecise_2_y , imprecise_3_y , meta_mux_select [ 1 ] ) ) ;
module - > addMux ( cell - > name . str ( ) + " _mux3 " , meta_mux1 , meta_mux2 , meta_mux_select [ 0 ] , port_taints [ Y ] ) ;
2020-04-20 22:21:28 -05:00
}
2020-04-22 16:33:22 -05:00
else log_cmd_error ( " This is a bug (1) . \ n " ) ;
2020-04-20 22:21:28 -05:00
}
else if ( cell - > type . in ( " $_NOT_ " ) ) {
const unsigned int A = 0 , Y = 1 ;
const unsigned int NUM_PORTS = 2 ;
RTLIL : : SigSpec ports [ NUM_PORTS ] = { cell - > getPort ( ID : : A ) , cell - > getPort ( ID : : Y ) } ;
RTLIL : : SigSpec port_taints [ NUM_PORTS ] ;
if ( ports [ A ] . size ( ) ! = 1 | | ports [ Y ] . size ( ) ! = 1 )
log_cmd_error ( " Multi-bit signal found. Run `splitnets` first. \n " ) ;
for ( unsigned int i = 0 ; i < NUM_PORTS ; + + i )
port_taints [ i ] = get_corresponding_taint_signal ( ports [ i ] ) ;
if ( cell - > type = = " $_NOT_ " ) {
new_connections . emplace_back ( port_taints [ Y ] , port_taints [ A ] ) ;
}
2020-04-22 16:33:22 -05:00
else log_cmd_error ( " This is a bug (2) . \ n " ) ;
2020-04-20 22:21:28 -05:00
}
} //end foreach cell in cells
for ( auto & conn : connections ) {
RTLIL : : SigSpec first = get_corresponding_taint_signal ( conn . first ) ;
RTLIL : : SigSpec second = get_corresponding_taint_signal ( conn . second ) ;
module - > connect ( get_corresponding_taint_signal ( conn . first ) , get_corresponding_taint_signal ( conn . second ) ) ;
if ( conn . second . is_wire ( ) & & conn . second . as_wire ( ) - > port_input )
second . as_wire ( ) - > port_input = true ;
if ( conn . first . is_wire ( ) & & conn . first . as_wire ( ) - > port_output )
2020-04-22 16:33:22 -05:00
new_taint_outputs . push_back ( first . as_wire ( ) ) ;
2020-04-20 22:21:28 -05:00
} //end foreach conn in connections
2020-04-23 01:41:58 -05:00
//Create a rough model of area by summing the "weight" score of each meta-mux select:
if ( ! opt_nomodeloptimize ) {
std : : vector < RTLIL : : SigSpec > meta_mux_select_sums ;
std : : vector < RTLIL : : SigSpec > meta_mux_select_sums_buf ;
for ( auto & wire : meta_mux_selects ) {
meta_mux_select_sums . emplace_back ( score_metamux_select ( wire ) ) ;
}
for ( unsigned int i = 0 ; meta_mux_select_sums . size ( ) > 1 ; ) {
meta_mux_select_sums_buf . clear ( ) ;
for ( i = 0 ; i + 1 < meta_mux_select_sums . size ( ) ; i + = 2 ) {
meta_mux_select_sums_buf . push_back ( module - > Add ( meta_mux_select_sums [ i ] . as_wire ( ) - > name . str ( ) + " _add " , meta_mux_select_sums [ i ] , meta_mux_select_sums [ i + 1 ] , false ) ) ;
}
if ( meta_mux_select_sums . size ( ) % 2 = = 1 )
meta_mux_select_sums_buf . push_back ( meta_mux_select_sums [ meta_mux_select_sums . size ( ) - 1 ] ) ;
meta_mux_select_sums . swap ( meta_mux_select_sums_buf ) ;
}
if ( meta_mux_select_sums . size ( ) > 0 ) {
meta_mux_select_sums [ 0 ] . as_wire ( ) - > set_bool_attribute ( " \\ minimize " ) ;
meta_mux_select_sums [ 0 ] . as_wire ( ) - > set_bool_attribute ( " \\ keep " ) ;
module - > rename ( meta_mux_select_sums [ 0 ] . as_wire ( ) , ID ( __glift_weight ) ) ;
}
}
//Add new connections and mark new module outputs:
2020-04-20 22:21:28 -05:00
for ( auto & conn : new_connections )
module - > connect ( conn ) ;
2020-04-22 16:33:22 -05:00
for ( auto & port_name : module - > ports ) {
RTLIL : : Wire * port = module - > wire ( port_name ) ;
log_assert ( port ! = nullptr ) ;
if ( port - > port_output & & ! opt_keepoutputs )
port - > port_output = false ;
}
for ( auto & output : new_taint_outputs )
output - > port_output = true ;
2020-04-20 22:21:28 -05:00
module - > fixup_ports ( ) ; //we have some new taint signals in the module interface
}
2020-04-22 16:33:22 -05:00
void reset ( ) {
opt_create = false ;
opt_sketchify = false ;
opt_taintconstants = false ;
opt_keepoutputs = false ;
2020-04-23 01:41:58 -05:00
opt_nomodeloptimize = false ;
2020-04-22 16:33:22 -05:00
module = nullptr ;
args . clear ( ) ;
argidx = 0 ;
new_taint_outputs . clear ( ) ;
2020-04-23 01:41:58 -05:00
meta_mux_selects . clear ( ) ;
2020-04-22 16:33:22 -05:00
}
2020-04-20 22:21:28 -05:00
public :
2020-04-23 01:41:58 -05:00
GliftPass ( ) : Pass ( " glift " , " create and transform GLIFT models " ) , opt_create ( false ) , opt_sketchify ( false ) , opt_taintconstants ( false ) , opt_keepoutputs ( false ) , opt_nomodeloptimize ( false ) , module ( nullptr ) { }
2020-04-22 16:33:22 -05:00
2020-04-20 16:13:59 -05:00
void help ( ) YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
2020-04-22 01:16:12 -05:00
log ( " glift -create|-sketchify [options] [selection] \n " ) ;
2020-04-20 16:13:59 -05:00
log ( " \n " ) ;
log ( " Adds, removes, or manipulates gate-level information flow tracking (GLIFT) logic \n " ) ;
log ( " to the current or specified module. \n " ) ;
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " Commands: \n " ) ;
2020-04-20 16:13:59 -05:00
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " -create \n " ) ;
2020-04-20 16:13:59 -05:00
log ( " Replaces the current or specified module with one that has additional \" taint \" \n " ) ;
log ( " inputs, outputs, and internal nets along with precise taint-tracking logic. \n " ) ;
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " -sketchify \n " ) ;
2020-04-22 01:16:12 -05:00
log ( " Replaces the current or specified module with one that has additional \" taint \" \n " ) ;
log ( " inputs, outputs, and internal nets along with varying-precision taint-tracking logic. \n " ) ;
log ( " Which version of taint tracking logic is used at a given cell is determined by a MUX \n " ) ;
log ( " selected by an $anyconst cell. \n " ) ;
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " Options: \n " ) ;
2020-04-22 01:16:12 -05:00
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " -taint-constants \n " ) ;
2020-04-20 22:21:28 -05:00
log ( " Constant values in the design are labeled as tainted. \n " ) ;
log ( " (default: label constants as un-tainted) \n " ) ;
log ( " \n " ) ;
2020-04-22 16:33:22 -05:00
log ( " -keep-outputs \n " ) ;
log ( " Do not remove module outputs. Taint tracking outputs will appear in the module ports \n " ) ;
log ( " alongside the orignal outputs. \n " ) ;
log ( " (default: original module outputs are removed) \n " ) ;
log ( " \n " ) ;
2020-04-23 01:41:58 -05:00
log ( " -no-model-optimize \n " ) ;
log ( " Do not model imprecise taint tracking logic area and attempt to minimize it. \n " ) ;
log ( " (default: model area and give that signal the \" minimize \" attribute) \n " ) ;
log ( " \n " ) ;
2020-04-20 16:13:59 -05:00
}
2020-04-23 01:41:58 -05:00
2020-04-20 22:21:28 -05:00
void execute ( std : : vector < std : : string > _args , RTLIL : : Design * design ) YS_OVERRIDE
2020-04-20 16:13:59 -05:00
{
2020-04-20 22:21:28 -05:00
log_header ( design , " Executing GLIFT pass (creating and manipulating GLIFT models). \n " ) ;
2020-04-22 16:33:22 -05:00
reset ( ) ;
2020-04-20 22:21:28 -05:00
args = _args ;
parse_args ( ) ;
extra_args ( args , argidx , design ) ;
for ( auto mod : design - > selected_modules ( ) ) {
if ( module )
log_cmd_error ( " Only one module may be selected for the glift pass! Flatten the design if necessary. (selected: %s and %s) \n " , log_id ( module ) , log_id ( mod ) ) ;
module = mod ;
}
if ( module = = nullptr )
log_cmd_error ( " Can't operate on an empty selection! \n " ) ;
2020-04-22 01:16:12 -05:00
create_glift_logic ( ) ;
2020-04-20 16:13:59 -05:00
}
} GliftPass ;
PRIVATE_NAMESPACE_END