2020-02-14 13:11:34 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2020-02-14 13:11:34 -06:00
* ( C ) 2020 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 .
*
*/
2020-02-27 12:29:53 -06:00
# ifndef TIMINGINFO_H
# define TIMINGINFO_H
2020-02-14 13:11:34 -06:00
# include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
struct TimingInfo
{
2020-02-18 10:41:48 -06:00
struct NameBit
{
RTLIL : : IdString name ;
int offset ;
2020-02-18 13:02:28 -06:00
NameBit ( ) : offset ( 0 ) { }
NameBit ( const RTLIL : : IdString name , int offset ) : name ( name ) , offset ( offset ) { }
explicit NameBit ( const RTLIL : : SigBit & b ) : name ( b . wire - > name ) , offset ( b . offset ) { }
2020-02-18 10:41:48 -06:00
bool operator = = ( const NameBit & nb ) const { return nb . name = = name & & nb . offset = = offset ; }
bool operator ! = ( const NameBit & nb ) const { return ! operator = = ( nb ) ; }
2024-11-13 09:20:05 -06:00
std : : optional < SigBit > get_connection ( RTLIL : : Cell * cell ) {
if ( ! cell - > hasPort ( name ) )
return { } ;
auto & port = cell - > getPort ( name ) ;
if ( offset > = port . size ( ) )
return { } ;
return port [ offset ] ;
}
2024-10-01 08:12:03 -05:00
Hasher hash_acc ( Hasher h ) const {
h . acc ( name ) ;
h . acc ( offset ) ;
return h ;
}
2020-02-18 10:41:48 -06:00
} ;
2020-02-20 09:52:08 -06:00
struct BitBit
{
NameBit first , second ;
BitBit ( const NameBit & first , const NameBit & second ) : first ( first ) , second ( second ) { }
BitBit ( const SigBit & first , const SigBit & second ) : first ( first ) , second ( second ) { }
bool operator = = ( const BitBit & bb ) const { return bb . first = = first & & bb . second = = second ; }
2024-10-01 08:12:03 -05:00
Hasher hash_acc ( Hasher h ) const {
h . acc ( first ) ;
h . acc ( second ) ;
return h ;
}
2020-02-20 09:52:08 -06:00
} ;
2020-02-18 10:41:48 -06:00
struct ModuleTiming
{
dict < BitBit , int > comb ;
2021-11-24 15:21:08 -06:00
dict < NameBit , std : : pair < int , NameBit > > arrival , required ;
bool has_inputs ;
2020-02-18 10:41:48 -06:00
} ;
2020-02-18 10:30:41 -06:00
dict < RTLIL : : IdString , ModuleTiming > data ;
2020-02-14 13:11:34 -06:00
TimingInfo ( )
{
}
TimingInfo ( RTLIL : : Design * design )
{
setup ( design ) ;
}
void setup ( RTLIL : : Design * design )
{
for ( auto module : design - > modules ( ) ) {
if ( ! module - > get_blackbox_attribute ( ) )
continue ;
setup_module ( module ) ;
2020-02-18 10:30:41 -06:00
}
2020-02-14 13:11:34 -06:00
}
2020-02-14 14:01:03 -06:00
const ModuleTiming & setup_module ( RTLIL : : Module * module )
2020-02-14 13:11:34 -06:00
{
2020-02-18 10:30:41 -06:00
auto r = data . insert ( module - > name ) ;
log_assert ( r . second ) ;
auto & t = r . first - > second ;
2020-02-14 13:11:34 -06:00
for ( auto cell : module - > cells ( ) ) {
2020-02-18 10:30:41 -06:00
if ( cell - > type = = ID ( $ specify2 ) ) {
2020-04-21 19:03:28 -05:00
auto en = cell - > getPort ( ID : : EN ) ;
if ( en . is_fully_const ( ) & & ! en . as_bool ( ) )
continue ;
2020-04-02 11:51:32 -05:00
auto src = cell - > getPort ( ID : : SRC ) ;
auto dst = cell - > getPort ( ID : : DST ) ;
2020-02-18 10:30:41 -06:00
for ( const auto & c : src . chunks ( ) )
2020-12-14 11:14:42 -06:00
if ( ! c . wire | | ! c . wire - > port_input )
2020-02-18 10:30:41 -06:00
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
for ( const auto & c : dst . chunks ( ) )
2020-12-14 11:14:42 -06:00
if ( ! c . wire | | ! c . wire - > port_output )
2020-02-18 10:30:41 -06:00
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module output. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
2020-04-02 11:51:32 -05:00
int rise_max = cell - > getParam ( ID : : T_RISE_MAX ) . as_int ( ) ;
int fall_max = cell - > getParam ( ID : : T_FALL_MAX ) . as_int ( ) ;
2020-02-18 10:30:41 -06:00
int max = std : : max ( rise_max , fall_max ) ;
if ( max < 0 )
log_error ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0. \n " , log_id ( module ) , log_id ( cell ) ) ;
2020-04-02 11:51:32 -05:00
if ( cell - > getParam ( ID : : FULL ) . as_bool ( ) ) {
2020-02-18 10:30:41 -06:00
for ( const auto & s : src )
for ( const auto & d : dst ) {
auto r = t . comb . insert ( BitBit ( s , d ) ) ;
if ( ! r . second )
log_error ( " Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'. \n " , log_id ( module ) , log_signal ( s ) , log_signal ( d ) ) ;
r . first - > second = max ;
}
}
else {
log_assert ( GetSize ( src ) = = GetSize ( dst ) ) ;
for ( auto i = 0 ; i < GetSize ( src ) ; i + + ) {
const auto & s = src [ i ] ;
const auto & d = dst [ i ] ;
auto r = t . comb . insert ( BitBit ( s , d ) ) ;
if ( ! r . second )
log_error ( " Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'. \n " , log_id ( module ) , log_signal ( s ) , log_signal ( d ) ) ;
r . first - > second = max ;
}
}
}
else if ( cell - > type = = ID ( $ specify3 ) ) {
2021-11-24 15:21:08 -06:00
auto src = cell - > getPort ( ID : : SRC ) . as_bit ( ) ;
2020-04-02 11:51:32 -05:00
auto dst = cell - > getPort ( ID : : DST ) ;
2021-11-24 15:21:08 -06:00
if ( ! src . wire | | ! src . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
2020-02-14 13:11:34 -06:00
for ( const auto & c : dst . chunks ( ) )
if ( ! c . wire - > port_output )
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module output. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
2020-04-02 11:51:32 -05:00
int rise_max = cell - > getParam ( ID : : T_RISE_MAX ) . as_int ( ) ;
int fall_max = cell - > getParam ( ID : : T_FALL_MAX ) . as_int ( ) ;
2020-02-14 13:11:34 -06:00
int max = std : : max ( rise_max , fall_max ) ;
2020-04-16 12:21:08 -05:00
if ( max < 0 ) {
log_warning ( " Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0. \n " , log_id ( module ) , log_id ( cell ) ) ;
max = 0 ;
2020-02-14 13:11:34 -06:00
}
for ( const auto & d : dst ) {
2021-11-24 15:21:08 -06:00
auto r = t . arrival . insert ( NameBit ( d ) ) ;
auto & v = r . first - > second ;
if ( r . second | | v . first < max ) {
v . first = max ;
v . second = NameBit ( src ) ;
}
2020-02-18 10:30:41 -06:00
}
2020-02-14 13:11:34 -06:00
}
else if ( cell - > type = = ID ( $ specrule ) ) {
2021-11-24 15:21:08 -06:00
IdString type = cell - > getParam ( ID : : TYPE ) . decode_string ( ) ;
if ( type ! = ID ( $ setup ) & & type ! = ID ( $ setuphold ) )
2020-02-14 13:11:34 -06:00
continue ;
2020-04-02 11:51:32 -05:00
auto src = cell - > getPort ( ID : : SRC ) ;
2021-11-24 15:21:08 -06:00
auto dst = cell - > getPort ( ID : : DST ) . as_bit ( ) ;
2020-02-14 13:11:34 -06:00
for ( const auto & c : src . chunks ( ) )
2021-11-24 15:21:08 -06:00
if ( ! c . wire | | ! c . wire - > port_input )
2020-02-14 13:11:34 -06:00
log_error ( " Module '%s' contains specify cell '%s' where SRC '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( src ) ) ;
2021-11-24 15:21:08 -06:00
if ( ! dst . wire | | ! dst . wire - > port_input )
log_error ( " Module '%s' contains specify cell '%s' where DST '%s' is not a module input. \n " , log_id ( module ) , log_id ( cell ) , log_signal ( dst ) ) ;
2020-04-02 11:51:32 -05:00
int max = cell - > getParam ( ID : : T_LIMIT_MAX ) . as_int ( ) ;
2020-04-16 12:21:08 -05:00
if ( max < 0 ) {
log_warning ( " Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0. \n " , log_id ( module ) , log_id ( cell ) ) ;
max = 0 ;
2020-02-14 13:11:34 -06:00
}
for ( const auto & s : src ) {
2021-11-24 15:21:08 -06:00
auto r = t . required . insert ( NameBit ( s ) ) ;
auto & v = r . first - > second ;
if ( r . second | | v . first < max ) {
v . first = max ;
v . second = NameBit ( dst ) ;
}
2020-02-18 10:30:41 -06:00
}
2020-02-14 13:11:34 -06:00
}
}
2020-02-14 14:01:03 -06:00
2021-11-24 15:21:08 -06:00
for ( auto port_name : module - > ports ) {
auto wire = module - > wire ( port_name ) ;
if ( wire - > port_input ) {
t . has_inputs = true ;
break ;
}
}
2020-02-18 10:30:41 -06:00
return t ;
2020-02-14 13:11:34 -06:00
}
2020-02-18 10:30:41 -06:00
decltype ( data ) : : const_iterator find ( RTLIL : : IdString module_name ) const { return data . find ( module_name ) ; }
decltype ( data ) : : const_iterator end ( ) const { return data . end ( ) ; }
int count ( RTLIL : : IdString module_name ) const { return data . count ( module_name ) ; }
const ModuleTiming & at ( RTLIL : : IdString module_name ) const { return data . at ( module_name ) ; }
2020-02-14 13:11:34 -06:00
} ;
YOSYS_NAMESPACE_END
# endif