2017-08-16 06:05:21 -05:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2017-08-16 06:05:21 -05:00
*
* 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/yosys.h"
# include "kernel/sigtools.h"
# include "kernel/celltypes.h"
2020-10-17 08:49:36 -05:00
# include "kernel/mem.h"
2022-01-26 08:50:38 -06:00
# include "kernel/fstdata.h"
2022-02-15 02:30:42 -06:00
# include "kernel/ff.h"
2022-12-21 07:44:15 -06:00
# include "kernel/yw.h"
2023-01-10 10:04:06 -06:00
# include "kernel/json.h"
2017-08-16 06:05:21 -05:00
2020-10-16 11:46:59 -05:00
# include <ctime>
2017-08-16 06:05:21 -05:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2022-01-28 03:18:02 -06:00
enum class SimulationMode {
2022-02-02 02:37:32 -06:00
sim ,
2022-01-28 03:18:02 -06:00
cmp ,
gold ,
gate ,
} ;
static const std : : map < std : : string , int > g_units =
{
{ " " , - 9 } , // default is ns
{ " s " , 0 } ,
{ " ms " , - 3 } ,
{ " us " , - 6 } ,
{ " ns " , - 9 } ,
{ " ps " , - 12 } ,
{ " fs " , - 15 } ,
{ " as " , - 18 } ,
{ " zs " , - 21 } ,
} ;
static double stringToTime ( std : : string str )
{
if ( str = = " END " ) return - 1 ;
char * endptr ;
long value = strtol ( str . c_str ( ) , & endptr , 10 ) ;
if ( g_units . find ( endptr ) = = g_units . end ( ) )
log_error ( " Cannot parse '%s', bad unit '%s' \n " , str . c_str ( ) , endptr ) ;
if ( value < 0 )
log_error ( " Time value '%s' must be positive \n " , str . c_str ( ) ) ;
return value * pow ( 10.0 , g_units . at ( endptr ) ) ;
}
2022-02-28 11:22:39 -06:00
struct SimWorker ;
struct OutputWriter
{
OutputWriter ( SimWorker * w ) { worker = w ; } ;
virtual ~ OutputWriter ( ) { } ;
2022-03-02 09:02:13 -06:00
virtual void write ( std : : map < int , bool > & use_signal ) = 0 ;
2022-02-28 11:22:39 -06:00
SimWorker * worker ;
} ;
2023-01-10 10:04:06 -06:00
struct SimInstance ;
struct TriggeredAssertion {
int step ;
SimInstance * instance ;
Cell * cell ;
TriggeredAssertion ( int step , SimInstance * instance , Cell * cell ) :
step ( step ) , instance ( instance ) , cell ( cell )
{ }
} ;
2017-08-17 05:27:08 -05:00
struct SimShared
{
bool debug = false ;
2022-03-11 09:26:11 -06:00
bool verbose = true ;
2017-08-17 05:27:08 -05:00
bool hide_internal = true ;
2017-08-17 08:54:51 -05:00
bool writeback = false ;
2017-08-18 05:54:17 -05:00
bool zinit = false ;
2022-08-09 08:43:26 -05:00
bool hdlname = false ;
2017-08-18 05:54:17 -05:00
int rstlen = 1 ;
2022-01-26 08:50:38 -06:00
FstData * fst = nullptr ;
2022-01-28 03:18:02 -06:00
double start_time = 0 ;
double stop_time = - 1 ;
2022-02-02 02:37:32 -06:00
SimulationMode sim_mode = SimulationMode : : sim ;
2022-01-31 02:38:25 -06:00
bool cycles_set = false ;
2022-02-28 11:22:39 -06:00
std : : vector < std : : unique_ptr < OutputWriter > > outputfiles ;
2022-03-02 08:23:07 -06:00
std : : vector < std : : pair < int , std : : map < int , Const > > > output_data ;
2022-03-02 09:02:13 -06:00
bool ignore_x = false ;
2022-03-11 09:01:59 -06:00
bool date = false ;
2022-03-31 06:10:13 -05:00
bool multiclock = false ;
2022-12-21 07:33:20 -06:00
int next_output_id = 0 ;
2023-01-10 10:04:06 -06:00
int step = 0 ;
std : : vector < TriggeredAssertion > triggered_assertions ;
2017-08-17 05:27:08 -05:00
} ;
2017-08-18 05:54:17 -05:00
void zinit ( State & v )
{
if ( v ! = State : : S1 )
v = State : : S0 ;
}
void zinit ( Const & v )
{
for ( auto & bit : v . bits )
zinit ( bit ) ;
}
2017-08-16 06:05:21 -05:00
struct SimInstance
{
2017-08-17 05:27:08 -05:00
SimShared * shared ;
2022-01-26 08:50:38 -06:00
std : : string scope ;
2017-08-16 06:05:21 -05:00
Module * module ;
Cell * instance ;
SimInstance * parent ;
dict < Cell * , SimInstance * > children ;
SigMap sigmap ;
dict < SigBit , State > state_nets ;
dict < SigBit , pool < Cell * > > upd_cells ;
dict < SigBit , pool < Wire * > > upd_outports ;
2023-02-13 05:26:06 -06:00
dict < SigBit , SigBit > in_parent_drivers ;
2017-08-16 06:05:21 -05:00
pool < SigBit > dirty_bits ;
2017-08-18 04:44:50 -05:00
pool < Cell * > dirty_cells ;
2020-10-17 08:49:36 -05:00
pool < IdString > dirty_memories ;
2017-08-17 05:27:08 -05:00
pool < SimInstance * , hash_ptr_ops > dirty_children ;
2017-08-16 06:05:21 -05:00
2017-08-17 05:27:08 -05:00
struct ff_state_t
{
Const past_d ;
2022-02-15 02:30:42 -06:00
Const past_ad ;
2022-02-17 10:18:36 -06:00
State past_clk ;
State past_ce ;
State past_srst ;
2022-02-15 02:30:42 -06:00
FfData data ;
2017-08-17 05:27:08 -05:00
} ;
2017-08-18 03:24:14 -05:00
struct mem_state_t
{
2020-10-17 08:49:36 -05:00
Mem * mem ;
std : : vector < Const > past_wr_clk ;
std : : vector < Const > past_wr_en ;
std : : vector < Const > past_wr_addr ;
std : : vector < Const > past_wr_data ;
2017-08-18 03:24:14 -05:00
Const data ;
} ;
2017-08-17 05:27:08 -05:00
dict < Cell * , ff_state_t > ff_database ;
2020-10-17 08:49:36 -05:00
dict < IdString , mem_state_t > mem_database ;
2017-08-18 03:24:14 -05:00
pool < Cell * > formal_database ;
2022-12-21 07:39:49 -06:00
pool < Cell * > initstate_database ;
2020-10-17 08:49:36 -05:00
dict < Cell * , IdString > mem_cells ;
std : : vector < Mem > memories ;
2017-08-16 06:05:21 -05:00
2022-02-28 11:22:39 -06:00
dict < Wire * , pair < int , Const > > signal_database ;
2022-12-21 07:33:20 -06:00
dict < IdString , std : : map < int , pair < int , Const > > > trace_mem_database ;
2023-01-10 10:04:06 -06:00
dict < std : : pair < IdString , int > , Const > trace_mem_init_database ;
2022-01-28 06:24:38 -06:00
dict < Wire * , fstHandle > fst_handles ;
2022-07-22 07:47:00 -05:00
dict < Wire * , fstHandle > fst_inputs ;
2022-05-04 03:41:04 -05:00
dict < IdString , dict < int , fstHandle > > fst_memories ;
2017-08-17 05:27:08 -05:00
2022-01-26 08:50:38 -06:00
SimInstance ( SimShared * shared , std : : string scope , Module * module , Cell * instance = nullptr , SimInstance * parent = nullptr ) :
shared ( shared ) , scope ( scope ) , module ( module ) , instance ( instance ) , parent ( parent ) , sigmap ( module )
2017-08-16 06:05:21 -05:00
{
2019-06-05 16:16:24 -05:00
log_assert ( module ) ;
2017-08-16 06:05:21 -05:00
if ( parent ) {
log_assert ( parent - > children . count ( instance ) = = 0 ) ;
parent - > children [ instance ] = this ;
}
for ( auto wire : module - > wires ( ) )
{
SigSpec sig = sigmap ( wire ) ;
for ( int i = 0 ; i < GetSize ( sig ) ; i + + ) {
if ( state_nets . count ( sig [ i ] ) = = 0 )
state_nets [ sig [ i ] ] = State : : Sx ;
if ( wire - > port_output ) {
upd_outports [ sig [ i ] ] . insert ( wire ) ;
dirty_bits . insert ( sig [ i ] ) ;
}
}
2022-02-02 03:15:22 -06:00
if ( ( shared - > fst ) & & ! ( shared - > hide_internal & & wire - > name [ 0 ] = = ' $ ' ) ) {
2022-01-28 06:24:38 -06:00
fstHandle id = shared - > fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) ;
2022-01-28 07:20:16 -06:00
if ( id = = 0 & & wire - > name . isPublic ( ) )
2022-03-11 09:26:11 -06:00
log_warning ( " Unable to find wire %s in input file. \n " , ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) . c_str ( ) ) ;
2022-01-28 06:24:38 -06:00
fst_handles [ wire ] = id ;
}
2020-04-02 11:51:32 -05:00
if ( wire - > attributes . count ( ID : : init ) ) {
Const initval = wire - > attributes . at ( ID : : init ) ;
2017-08-16 06:05:21 -05:00
for ( int i = 0 ; i < GetSize ( sig ) & & i < GetSize ( initval ) ; i + + )
if ( initval [ i ] = = State : : S0 | | initval [ i ] = = State : : S1 ) {
state_nets [ sig [ i ] ] = initval [ i ] ;
dirty_bits . insert ( sig [ i ] ) ;
}
}
2023-02-13 05:26:06 -06:00
if ( wire - > port_input & & instance ! = nullptr & & parent ! = nullptr ) {
for ( int i = 0 ; i < GetSize ( sig ) ; i + + ) {
2023-05-18 09:50:11 -05:00
if ( instance - > hasPort ( wire - > name ) )
in_parent_drivers . emplace ( sig [ i ] , parent - > sigmap ( instance - > getPort ( wire - > name ) [ i ] ) ) ;
2023-02-13 05:26:06 -06:00
}
}
2017-08-16 06:05:21 -05:00
}
2020-10-17 08:49:36 -05:00
memories = Mem : : get_all_memories ( module ) ;
for ( auto & mem : memories ) {
auto & mdb = mem_database [ mem . memid ] ;
mdb . mem = & mem ;
for ( auto & port : mem . wr_ports ) {
mdb . past_wr_clk . push_back ( Const ( State : : Sx ) ) ;
mdb . past_wr_en . push_back ( Const ( State : : Sx , GetSize ( port . en ) ) ) ;
mdb . past_wr_addr . push_back ( Const ( State : : Sx , GetSize ( port . addr ) ) ) ;
mdb . past_wr_data . push_back ( Const ( State : : Sx , GetSize ( port . data ) ) ) ;
}
mdb . data = mem . get_init_data ( ) ;
}
2017-08-16 06:05:21 -05:00
for ( auto cell : module - > cells ( ) )
{
Module * mod = module - > design - > module ( cell - > type ) ;
if ( mod ! = nullptr ) {
2022-01-31 01:56:29 -06:00
dirty_children . insert ( new SimInstance ( shared , scope + " . " + RTLIL : : unescape_id ( cell - > name ) , mod , cell , this ) ) ;
2017-08-16 06:05:21 -05:00
}
for ( auto & port : cell - > connections ( ) ) {
if ( cell - > input ( port . first ) )
2020-04-21 02:58:52 -05:00
for ( auto bit : sigmap ( port . second ) ) {
2017-08-16 06:05:21 -05:00
upd_cells [ bit ] . insert ( cell ) ;
2020-04-21 02:58:52 -05:00
// Make sure cell inputs connected to constants are updated in the first cycle
if ( bit . wire = = nullptr )
dirty_bits . insert ( bit ) ;
}
2017-08-16 06:05:21 -05:00
}
2017-08-17 05:27:08 -05:00
2022-07-21 07:22:15 -05:00
if ( RTLIL : : builtin_ff_cell_types ( ) . count ( cell - > type ) | | cell - > type = = ID ( $ anyinit ) ) {
2022-02-15 02:30:42 -06:00
FfData ff_data ( nullptr , cell ) ;
2017-08-17 05:27:08 -05:00
ff_state_t ff ;
2022-02-15 02:30:42 -06:00
ff . past_d = Const ( State : : Sx , ff_data . width ) ;
ff . past_ad = Const ( State : : Sx , ff_data . width ) ;
ff . past_clk = State : : Sx ;
ff . past_ce = State : : Sx ;
ff . past_srst = State : : Sx ;
ff . data = ff_data ;
2017-08-17 05:27:08 -05:00
ff_database [ cell ] = ff ;
}
2017-08-18 03:24:14 -05:00
2021-05-22 12:14:13 -05:00
if ( cell - > is_mem_cell ( ) )
2020-06-29 03:33:39 -05:00
{
2022-05-04 03:41:04 -05:00
std : : string name = cell - > parameters . at ( ID : : MEMID ) . decode_string ( ) ;
mem_cells [ cell ] = name ;
2022-05-04 04:21:39 -05:00
if ( shared - > fst )
fst_memories [ name ] = shared - > fst - > getMemoryHandles ( scope + " . " + RTLIL : : unescape_id ( name ) ) ;
2020-06-29 03:33:39 -05:00
}
2020-04-02 11:51:32 -05:00
if ( cell - > type . in ( ID ( $ assert ) , ID ( $ cover ) , ID ( $ assume ) ) ) {
2017-08-18 03:24:14 -05:00
formal_database . insert ( cell ) ;
}
2022-12-21 07:39:49 -06:00
if ( cell - > type = = ID ( $ initstate ) )
initstate_database . insert ( cell ) ;
2017-08-16 06:05:21 -05:00
}
2017-08-18 05:54:17 -05:00
if ( shared - > zinit )
{
for ( auto & it : ff_database )
{
ff_state_t & ff = it . second ;
zinit ( ff . past_d ) ;
2022-04-02 03:59:15 -05:00
zinit ( ff . past_ad ) ;
2017-08-18 05:54:17 -05:00
2022-02-15 02:30:42 -06:00
SigSpec qsig = it . second . data . sig_q ;
2017-08-18 05:54:17 -05:00
Const qdata = get_state ( qsig ) ;
zinit ( qdata ) ;
set_state ( qsig , qdata ) ;
}
for ( auto & it : mem_database ) {
mem_state_t & mem = it . second ;
2020-10-17 08:49:36 -05:00
for ( auto & val : mem . past_wr_en )
zinit ( val ) ;
2017-08-18 05:54:17 -05:00
zinit ( mem . data ) ;
}
}
2017-08-16 06:05:21 -05:00
}
2017-08-17 05:27:08 -05:00
~ SimInstance ( )
{
for ( auto child : children )
delete child . second ;
}
2017-08-16 06:05:21 -05:00
IdString name ( ) const
{
if ( instance ! = nullptr )
return instance - > name ;
return module - > name ;
}
std : : string hiername ( ) const
{
if ( instance ! = nullptr )
return parent - > hiername ( ) + " . " + log_id ( instance - > name ) ;
return log_id ( module - > name ) ;
}
2023-01-10 10:04:06 -06:00
vector < std : : string > witness_full_path ( ) const
{
if ( instance ! = nullptr )
return parent - > witness_full_path ( instance ) ;
return vector < std : : string > ( ) ;
}
vector < std : : string > witness_full_path ( Cell * cell ) const
{
auto result = witness_full_path ( ) ;
auto cell_path = witness_path ( cell ) ;
result . insert ( result . end ( ) , cell_path . begin ( ) , cell_path . end ( ) ) ;
return result ;
}
2017-08-16 06:05:21 -05:00
Const get_state ( SigSpec sig )
{
Const value ;
for ( auto bit : sigmap ( sig ) )
2017-08-17 05:27:08 -05:00
if ( bit . wire = = nullptr )
value . bits . push_back ( bit . data ) ;
else if ( state_nets . count ( bit ) )
2017-08-16 06:05:21 -05:00
value . bits . push_back ( state_nets . at ( bit ) ) ;
else
value . bits . push_back ( State : : Sz ) ;
2017-08-17 05:27:08 -05:00
if ( shared - > debug )
log ( " [%s] get %s: %s \n " , hiername ( ) . c_str ( ) , log_signal ( sig ) , log_signal ( value ) ) ;
2017-08-16 06:05:21 -05:00
return value ;
}
2017-08-17 05:27:08 -05:00
bool set_state ( SigSpec sig , Const value )
2017-08-16 06:05:21 -05:00
{
2017-08-17 05:27:08 -05:00
bool did_something = false ;
2017-08-16 06:05:21 -05:00
sig = sigmap ( sig ) ;
2019-12-17 10:32:48 -06:00
log_assert ( GetSize ( sig ) < = GetSize ( value ) ) ;
2017-08-16 06:05:21 -05:00
for ( int i = 0 ; i < GetSize ( sig ) ; i + + )
2022-12-21 07:33:20 -06:00
if ( value [ i ] ! = State : : Sa & & state_nets . at ( sig [ i ] ) ! = value [ i ] ) {
2017-08-16 06:05:21 -05:00
state_nets . at ( sig [ i ] ) = value [ i ] ;
dirty_bits . insert ( sig [ i ] ) ;
2017-08-17 05:27:08 -05:00
did_something = true ;
2017-08-16 06:05:21 -05:00
}
2017-08-17 05:27:08 -05:00
if ( shared - > debug )
log ( " [%s] set %s: %s \n " , hiername ( ) . c_str ( ) , log_signal ( sig ) , log_signal ( value ) ) ;
return did_something ;
2017-08-16 06:05:21 -05:00
}
2023-02-13 05:26:06 -06:00
void set_state_parent_drivers ( SigSpec sig , Const value )
{
sigmap . apply ( sig ) ;
for ( int i = 0 ; i < GetSize ( sig ) ; i + + ) {
auto sigbit = sig [ i ] ;
auto sigval = value [ i ] ;
auto in_parent_driver = in_parent_drivers . find ( sigbit ) ;
if ( in_parent_driver = = in_parent_drivers . end ( ) )
set_state ( sigbit , sigval ) ;
else
parent - > set_state_parent_drivers ( in_parent_driver - > second , sigval ) ;
}
}
2022-03-11 04:19:53 -06:00
void set_memory_state ( IdString memid , Const addr , Const data )
2022-12-21 07:33:20 -06:00
{
set_memory_state ( memid , addr . as_int ( ) , data ) ;
}
void set_memory_state ( IdString memid , int addr , Const data )
2022-03-11 04:19:53 -06:00
{
auto & state = mem_database [ memid ] ;
2022-12-21 07:33:20 -06:00
bool dirty = false ;
int offset = ( addr - state . mem - > start_offset ) * state . mem - > width ;
2022-03-11 04:19:53 -06:00
for ( int i = 0 ; i < GetSize ( data ) ; i + + )
2022-12-21 07:33:20 -06:00
if ( 0 < = i + offset & & i + offset < state . mem - > size * state . mem - > width & & data . bits [ i ] ! = State : : Sa )
if ( state . data . bits [ i + offset ] ! = data . bits [ i ] )
dirty = true , state . data . bits [ i + offset ] = data . bits [ i ] ;
if ( dirty )
dirty_memories . insert ( memid ) ;
2022-03-11 04:19:53 -06:00
}
2022-03-31 06:10:13 -05:00
void set_memory_state_bit ( IdString memid , int offset , State data )
{
auto & state = mem_database [ memid ] ;
if ( offset > = state . mem - > size * state . mem - > width )
log_error ( " Addressing out of bounds bit %d/%d of memory %s \n " , offset , state . mem - > size * state . mem - > width , log_id ( memid ) ) ;
2022-12-21 07:33:20 -06:00
if ( state . data . bits [ offset ] ! = data ) {
state . data . bits [ offset ] = data ;
dirty_memories . insert ( memid ) ;
}
2022-03-31 06:10:13 -05:00
}
2017-08-16 06:05:21 -05:00
void update_cell ( Cell * cell )
{
2017-08-17 05:27:08 -05:00
if ( ff_database . count ( cell ) )
return ;
2017-08-18 03:24:14 -05:00
if ( formal_database . count ( cell ) )
return ;
2020-10-17 08:49:36 -05:00
if ( mem_cells . count ( cell ) )
2017-08-18 04:44:50 -05:00
{
2020-10-17 08:49:36 -05:00
dirty_memories . insert ( mem_cells [ cell ] ) ;
2017-08-18 04:44:50 -05:00
return ;
}
2017-08-16 06:05:21 -05:00
if ( children . count ( cell ) )
{
auto child = children . at ( cell ) ;
for ( auto & conn : cell - > connections ( ) )
2021-03-01 13:01:39 -06:00
if ( cell - > input ( conn . first ) & & GetSize ( conn . second ) ) {
2017-08-16 06:05:21 -05:00
Const value = get_state ( conn . second ) ;
child - > set_state ( child - > module - > wire ( conn . first ) , value ) ;
}
2017-08-17 05:27:08 -05:00
dirty_children . insert ( child ) ;
2017-08-16 06:05:21 -05:00
return ;
}
if ( yosys_celltypes . cell_evaluable ( cell - > type ) )
{
RTLIL : : SigSpec sig_a , sig_b , sig_c , sig_d , sig_s , sig_y ;
bool has_a , has_b , has_c , has_d , has_s , has_y ;
2020-03-12 14:57:01 -05:00
has_a = cell - > hasPort ( ID : : A ) ;
has_b = cell - > hasPort ( ID : : B ) ;
2020-04-02 11:51:32 -05:00
has_c = cell - > hasPort ( ID : : C ) ;
has_d = cell - > hasPort ( ID : : D ) ;
2020-03-12 14:57:01 -05:00
has_s = cell - > hasPort ( ID : : S ) ;
has_y = cell - > hasPort ( ID : : Y ) ;
2017-08-16 06:05:21 -05:00
2020-03-12 14:57:01 -05:00
if ( has_a ) sig_a = cell - > getPort ( ID : : A ) ;
if ( has_b ) sig_b = cell - > getPort ( ID : : B ) ;
2020-04-02 11:51:32 -05:00
if ( has_c ) sig_c = cell - > getPort ( ID : : C ) ;
if ( has_d ) sig_d = cell - > getPort ( ID : : D ) ;
2020-03-12 14:57:01 -05:00
if ( has_s ) sig_s = cell - > getPort ( ID : : S ) ;
if ( has_y ) sig_y = cell - > getPort ( ID : : Y ) ;
2017-08-16 06:05:21 -05:00
2017-08-17 05:27:08 -05:00
if ( shared - > debug )
log ( " [%s] eval %s (%s) \n " , hiername ( ) . c_str ( ) , log_id ( cell ) , log_id ( cell - > type ) ) ;
2017-08-16 06:05:21 -05:00
// Simple (A -> Y) and (A,B -> Y) cells
if ( has_a & & ! has_c & & ! has_d & & ! has_s & & has_y ) {
set_state ( sig_y , CellTypes : : eval ( cell , get_state ( sig_a ) , get_state ( sig_b ) ) ) ;
return ;
}
// (A,B,C -> Y) cells
if ( has_a & & has_b & & has_c & & ! has_d & & ! has_s & & has_y ) {
set_state ( sig_y , CellTypes : : eval ( cell , get_state ( sig_a ) , get_state ( sig_b ) , get_state ( sig_c ) ) ) ;
return ;
}
2022-01-24 09:02:29 -06:00
// (A,S -> Y) cells
if ( has_a & & ! has_b & & ! has_c & & ! has_d & & has_s & & has_y ) {
set_state ( sig_y , CellTypes : : eval ( cell , get_state ( sig_a ) , get_state ( sig_s ) ) ) ;
return ;
}
2017-08-16 06:05:21 -05:00
// (A,B,S -> Y) cells
if ( has_a & & has_b & & ! has_c & & ! has_d & & has_s & & has_y ) {
set_state ( sig_y , CellTypes : : eval ( cell , get_state ( sig_a ) , get_state ( sig_b ) , get_state ( sig_s ) ) ) ;
return ;
}
log_warning ( " Unsupported evaluable cell type: %s (%s.%s) \n " , log_id ( cell - > type ) , log_id ( module ) , log_id ( cell ) ) ;
return ;
}
2017-08-18 03:24:14 -05:00
log_error ( " Unsupported cell type: %s (%s.%s) \n " , log_id ( cell - > type ) , log_id ( module ) , log_id ( cell ) ) ;
2017-08-16 06:05:21 -05:00
}
2020-10-17 08:49:36 -05:00
void update_memory ( IdString id ) {
auto & mdb = mem_database [ id ] ;
auto & mem = * mdb . mem ;
for ( int port_idx = 0 ; port_idx < GetSize ( mem . rd_ports ) ; port_idx + + )
{
auto & port = mem . rd_ports [ port_idx ] ;
Const addr = get_state ( port . addr ) ;
2021-05-24 18:12:19 -05:00
Const data = Const ( State : : Sx , mem . width < < port . wide_log2 ) ;
2020-10-17 08:49:36 -05:00
if ( port . clk_enable )
log_error ( " Memory %s.%s has clocked read ports. Run 'memory' with -nordff. \n " , log_id ( module ) , log_id ( mem . memid ) ) ;
if ( addr . is_fully_def ( ) ) {
2022-12-21 07:33:20 -06:00
int addr_int = addr . as_int ( ) ;
int index = addr_int - mem . start_offset ;
2020-10-17 08:49:36 -05:00
if ( index > = 0 & & index < mem . size )
2021-05-24 18:12:19 -05:00
data = mdb . data . extract ( index * mem . width , mem . width < < port . wide_log2 ) ;
2022-12-21 07:33:20 -06:00
for ( int offset = 0 ; offset < 1 < < port . wide_log2 ; offset + + ) {
register_memory_addr ( id , addr_int + offset ) ;
}
2020-10-17 08:49:36 -05:00
}
set_state ( port . data , data ) ;
}
}
2017-08-17 05:27:08 -05:00
void update_ph1 ( )
2017-08-16 06:05:21 -05:00
{
2017-08-17 05:27:08 -05:00
pool < Cell * > queue_cells ;
pool < Wire * > queue_outports ;
2017-08-18 04:44:50 -05:00
queue_cells . swap ( dirty_cells ) ;
2017-08-16 06:05:21 -05:00
while ( 1 )
{
2017-08-17 05:27:08 -05:00
for ( auto bit : dirty_bits )
2017-08-16 06:05:21 -05:00
{
if ( upd_cells . count ( bit ) )
for ( auto cell : upd_cells . at ( bit ) )
2017-08-17 05:27:08 -05:00
queue_cells . insert ( cell ) ;
2017-08-16 06:05:21 -05:00
if ( upd_outports . count ( bit ) & & parent ! = nullptr )
for ( auto wire : upd_outports . at ( bit ) )
2017-08-17 05:27:08 -05:00
queue_outports . insert ( wire ) ;
2017-08-16 06:05:21 -05:00
}
2017-08-17 05:27:08 -05:00
dirty_bits . clear ( ) ;
if ( ! queue_cells . empty ( ) )
{
for ( auto cell : queue_cells )
update_cell ( cell ) ;
queue_cells . clear ( ) ;
continue ;
}
2020-10-17 08:49:36 -05:00
for ( auto & memid : dirty_memories )
update_memory ( memid ) ;
dirty_memories . clear ( ) ;
2017-08-17 05:27:08 -05:00
for ( auto wire : queue_outports )
if ( instance - > hasPort ( wire - > name ) ) {
Const value = get_state ( wire ) ;
parent - > set_state ( instance - > getPort ( wire - > name ) , value ) ;
}
queue_outports . clear ( ) ;
for ( auto child : dirty_children )
child - > update_ph1 ( ) ;
dirty_children . clear ( ) ;
2017-08-16 06:05:21 -05:00
if ( dirty_bits . empty ( ) )
break ;
}
}
2023-05-25 05:46:16 -05:00
bool update_ph2 ( bool gclk , bool stable_past_update = false )
2017-08-17 05:27:08 -05:00
{
bool did_something = false ;
for ( auto & it : ff_database )
{
ff_state_t & ff = it . second ;
2022-02-17 10:18:36 -06:00
FfData & ff_data = ff . data ;
2022-02-15 02:30:42 -06:00
2022-02-18 02:17:36 -06:00
Const current_q = get_state ( ff . data . sig_q ) ;
2023-05-25 05:46:16 -05:00
if ( ff_data . has_clk & & ! stable_past_update ) {
2022-02-15 02:30:42 -06:00
// flip-flops
State current_clk = get_state ( ff_data . sig_clk ) [ 0 ] ;
2022-02-18 02:17:36 -06:00
if ( ff_data . pol_clk ? ( ff . past_clk = = State : : S0 & & current_clk ! = State : : S0 ) :
( ff . past_clk = = State : : S1 & & current_clk ! = State : : S1 ) ) {
bool ce = ff . past_ce = = ( ff_data . pol_ce ? State : : S1 : State : : S0 ) ;
// set if no ce, or ce is enabled
if ( ! ff_data . has_ce | | ( ff_data . has_ce & & ce ) ) {
current_q = ff . past_d ;
2022-02-15 02:30:42 -06:00
}
2022-02-18 02:17:36 -06:00
// override if sync reset
2022-02-21 09:36:12 -06:00
if ( ( ff_data . has_srst ) & & ( ff . past_srst = = ( ff_data . pol_srst ? State : : S1 : State : : S0 ) ) & &
( ( ! ff_data . ce_over_srst ) | | ( ff_data . ce_over_srst & & ce ) ) ) {
2022-02-18 02:17:36 -06:00
current_q = ff_data . val_srst ;
2022-02-15 02:30:42 -06:00
}
}
2022-02-18 02:17:36 -06:00
}
// async load
if ( ff_data . has_aload ) {
State current_aload = get_state ( ff_data . sig_aload ) [ 0 ] ;
if ( current_aload = = ( ff_data . pol_aload ? State : : S1 : State : : S0 ) ) {
2023-05-25 05:46:16 -05:00
current_q = ff_data . has_clk & & ! stable_past_update ? ff . past_ad : get_state ( ff . data . sig_ad ) ;
2022-02-18 02:17:36 -06:00
}
}
// async reset
if ( ff_data . has_arst ) {
State current_arst = get_state ( ff_data . sig_arst ) [ 0 ] ;
if ( current_arst = = ( ff_data . pol_arst ? State : : S1 : State : : S0 ) ) {
current_q = ff_data . val_arst ;
2022-02-15 02:30:42 -06:00
}
2022-02-18 02:17:36 -06:00
}
// handle set/reset
if ( ff . data . has_sr ) {
Const current_clr = get_state ( ff . data . sig_clr ) ;
Const current_set = get_state ( ff . data . sig_set ) ;
for ( int i = 0 ; i < ff . past_d . size ( ) ; i + + ) {
if ( current_clr [ i ] = = ( ff_data . pol_clr ? State : : S1 : State : : S0 ) ) {
current_q [ i ] = State : : S0 ;
2022-02-15 02:30:42 -06:00
}
2022-02-18 02:17:36 -06:00
else if ( current_set [ i ] = = ( ff_data . pol_set ? State : : S1 : State : : S0 ) ) {
current_q [ i ] = State : : S1 ;
2022-02-15 02:30:42 -06:00
}
}
2017-08-17 05:27:08 -05:00
}
2022-02-18 02:17:36 -06:00
if ( ff_data . has_gclk ) {
// $ff
2022-11-25 10:43:51 -06:00
if ( gclk )
current_q = ff . past_d ;
2022-02-18 02:17:36 -06:00
}
if ( set_state ( ff_data . sig_q , current_q ) )
did_something = true ;
2017-08-17 05:27:08 -05:00
}
2017-08-18 04:44:50 -05:00
for ( auto & it : mem_database )
{
2020-10-17 08:49:36 -05:00
mem_state_t & mdb = it . second ;
auto & mem = * mdb . mem ;
2017-08-18 04:44:50 -05:00
2020-10-17 08:49:36 -05:00
for ( int port_idx = 0 ; port_idx < GetSize ( mem . wr_ports ) ; port_idx + + )
2017-08-18 04:44:50 -05:00
{
2020-10-17 08:49:36 -05:00
auto & port = mem . wr_ports [ port_idx ] ;
2017-08-18 04:44:50 -05:00
Const addr , data , enable ;
2020-10-17 08:49:36 -05:00
if ( ! port . clk_enable )
2017-08-18 04:44:50 -05:00
{
2020-10-17 08:49:36 -05:00
addr = get_state ( port . addr ) ;
data = get_state ( port . data ) ;
enable = get_state ( port . en ) ;
2017-08-18 04:44:50 -05:00
}
else
{
2023-05-25 05:46:16 -05:00
if ( stable_past_update )
continue ;
2020-10-17 08:49:36 -05:00
if ( port . clk_polarity ?
( mdb . past_wr_clk [ port_idx ] = = State : : S1 | | get_state ( port . clk ) ! = State : : S1 ) :
( mdb . past_wr_clk [ port_idx ] = = State : : S0 | | get_state ( port . clk ) ! = State : : S0 ) )
2017-08-18 04:44:50 -05:00
continue ;
2020-10-17 08:49:36 -05:00
addr = mdb . past_wr_addr [ port_idx ] ;
data = mdb . past_wr_data [ port_idx ] ;
enable = mdb . past_wr_en [ port_idx ] ;
2017-08-18 04:44:50 -05:00
}
if ( addr . is_fully_def ( ) )
{
2022-12-21 07:33:20 -06:00
int addr_int = addr . as_int ( ) ;
int index = addr_int - mem . start_offset ;
2020-10-17 08:49:36 -05:00
if ( index > = 0 & & index < mem . size )
2021-05-24 18:12:19 -05:00
for ( int i = 0 ; i < ( mem . width < < port . wide_log2 ) ; i + + )
2020-10-17 08:49:36 -05:00
if ( enable [ i ] = = State : : S1 & & mdb . data . bits . at ( index * mem . width + i ) ! = data [ i ] ) {
mdb . data . bits . at ( index * mem . width + i ) = data [ i ] ;
dirty_memories . insert ( mem . memid ) ;
2017-08-18 04:44:50 -05:00
did_something = true ;
}
2022-12-21 07:33:20 -06:00
for ( int i = 0 ; i < 1 < < port . wide_log2 ; i + + )
register_memory_addr ( it . first , addr_int + i ) ;
2017-08-18 04:44:50 -05:00
}
}
}
2017-08-17 05:27:08 -05:00
for ( auto it : children )
2023-05-25 05:46:16 -05:00
if ( it . second - > update_ph2 ( gclk , stable_past_update ) ) {
2017-08-17 05:27:08 -05:00
dirty_children . insert ( it . second ) ;
did_something = true ;
}
return did_something ;
}
2022-12-21 07:40:58 -06:00
void update_ph3 ( bool check_assertions )
2017-08-17 05:27:08 -05:00
{
for ( auto & it : ff_database )
{
ff_state_t & ff = it . second ;
2022-02-15 02:30:42 -06:00
if ( ff . data . has_aload )
ff . past_ad = get_state ( ff . data . sig_ad ) ;
if ( ff . data . has_clk | | ff . data . has_gclk )
ff . past_d = get_state ( ff . data . sig_d ) ;
if ( ff . data . has_clk )
ff . past_clk = get_state ( ff . data . sig_clk ) [ 0 ] ;
if ( ff . data . has_ce )
ff . past_ce = get_state ( ff . data . sig_ce ) [ 0 ] ;
if ( ff . data . has_srst )
ff . past_srst = get_state ( ff . data . sig_srst ) [ 0 ] ;
2017-08-17 05:27:08 -05:00
}
2017-08-18 04:44:50 -05:00
for ( auto & it : mem_database )
{
mem_state_t & mem = it . second ;
2020-10-17 08:49:36 -05:00
for ( int i = 0 ; i < GetSize ( mem . mem - > wr_ports ) ; i + + ) {
auto & port = mem . mem - > wr_ports [ i ] ;
mem . past_wr_clk [ i ] = get_state ( port . clk ) ;
mem . past_wr_en [ i ] = get_state ( port . en ) ;
mem . past_wr_addr [ i ] = get_state ( port . addr ) ;
mem . past_wr_data [ i ] = get_state ( port . data ) ;
}
2017-08-18 04:44:50 -05:00
}
2022-12-21 07:40:58 -06:00
if ( check_assertions )
2017-08-18 03:24:14 -05:00
{
2022-12-21 07:40:58 -06:00
for ( auto cell : formal_database )
{
string label = log_id ( cell ) ;
if ( cell - > attributes . count ( ID : : src ) )
label = cell - > attributes . at ( ID : : src ) . decode_string ( ) ;
2017-08-18 03:24:14 -05:00
2022-12-21 07:40:58 -06:00
State a = get_state ( cell - > getPort ( ID : : A ) ) [ 0 ] ;
State en = get_state ( cell - > getPort ( ID : : EN ) ) [ 0 ] ;
2017-08-18 03:24:14 -05:00
2023-01-10 10:04:06 -06:00
if ( en = = State : : S1 & & ( cell - > type = = ID ( $ cover ) ? a = = State : : S1 : a ! = State : : S1 ) ) {
shared - > triggered_assertions . emplace_back ( shared - > step , this , cell ) ;
}
if ( cell - > type = = ID ( $ cover ) & & en = = State : : S1 & & a = = State : : S1 )
2022-12-21 07:40:58 -06:00
log ( " Cover %s.%s (%s) reached. \n " , hiername ( ) . c_str ( ) , log_id ( cell ) , label . c_str ( ) ) ;
2017-08-18 03:24:14 -05:00
2022-12-21 07:40:58 -06:00
if ( cell - > type = = ID ( $ assume ) & & en = = State : : S1 & & a ! = State : : S1 )
log ( " Assumption %s.%s (%s) failed. \n " , hiername ( ) . c_str ( ) , log_id ( cell ) , label . c_str ( ) ) ;
2017-08-18 03:24:14 -05:00
2022-12-21 07:40:58 -06:00
if ( cell - > type = = ID ( $ assert ) & & en = = State : : S1 & & a ! = State : : S1 )
log_warning ( " Assert %s.%s (%s) failed. \n " , hiername ( ) . c_str ( ) , log_id ( cell ) , label . c_str ( ) ) ;
}
2017-08-18 03:24:14 -05:00
}
2017-08-17 05:27:08 -05:00
for ( auto it : children )
2022-12-21 07:40:58 -06:00
it . second - > update_ph3 ( check_assertions ) ;
2017-08-17 05:27:08 -05:00
}
2022-12-21 07:39:49 -06:00
void set_initstate_outputs ( State state )
{
for ( auto cell : initstate_database )
set_state ( cell - > getPort ( ID : : Y ) , state ) ;
for ( auto child : children )
child . second - > set_initstate_outputs ( state ) ;
}
2017-08-17 08:54:51 -05:00
void writeback ( pool < Module * > & wbmods )
{
2022-12-21 03:43:02 -06:00
if ( ! ff_database . empty ( ) | | ! mem_database . empty ( ) ) {
if ( wbmods . count ( module ) )
log_error ( " Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.) \n " , hiername ( ) . c_str ( ) , log_id ( module ) ) ;
wbmods . insert ( module ) ;
}
2017-08-17 08:54:51 -05:00
for ( auto wire : module - > wires ( ) )
2020-04-02 11:51:32 -05:00
wire - > attributes . erase ( ID : : init ) ;
2017-08-17 08:54:51 -05:00
for ( auto & it : ff_database )
{
2022-02-15 02:30:42 -06:00
SigSpec sig_q = it . second . data . sig_q ;
2017-08-17 08:54:51 -05:00
Const initval = get_state ( sig_q ) ;
for ( int i = 0 ; i < GetSize ( sig_q ) ; i + + )
{
Wire * w = sig_q [ i ] . wire ;
2020-04-02 11:51:32 -05:00
if ( w - > attributes . count ( ID : : init ) = = 0 )
w - > attributes [ ID : : init ] = Const ( State : : Sx , GetSize ( w ) ) ;
2017-08-17 08:54:51 -05:00
2020-04-02 11:51:32 -05:00
w - > attributes [ ID : : init ] [ sig_q [ i ] . offset ] = initval [ i ] ;
2017-08-17 08:54:51 -05:00
}
}
2017-08-18 04:44:50 -05:00
for ( auto & it : mem_database )
{
mem_state_t & mem = it . second ;
2020-10-17 08:49:36 -05:00
mem . mem - > clear_inits ( ) ;
MemInit minit ;
minit . addr = mem . mem - > start_offset ;
minit . data = mem . data ;
2021-05-20 19:26:52 -05:00
minit . en = Const ( State : : S1 , mem . mem - > width ) ;
2020-10-17 08:49:36 -05:00
mem . mem - > inits . push_back ( minit ) ;
mem . mem - > emit ( ) ;
2017-08-18 04:44:50 -05:00
}
2017-08-17 08:54:51 -05:00
for ( auto it : children )
it . second - > writeback ( wbmods ) ;
}
2022-03-02 08:23:07 -06:00
void register_signals ( int & id )
2017-08-16 06:05:21 -05:00
{
for ( auto wire : module - > wires ( ) )
{
2017-08-17 05:27:08 -05:00
if ( shared - > hide_internal & & wire - > name [ 0 ] = = ' $ ' )
2017-08-16 06:05:21 -05:00
continue ;
2022-02-28 11:22:39 -06:00
signal_database [ wire ] = make_pair ( id , Const ( ) ) ;
id + + ;
2017-08-16 06:05:21 -05:00
}
for ( auto child : children )
2022-03-02 08:23:07 -06:00
child . second - > register_signals ( id ) ;
}
2022-12-21 07:33:20 -06:00
void write_output_header ( std : : function < void ( IdString ) > enter_scope , std : : function < void ( ) > exit_scope , std : : function < void ( const char * , int , Wire * , int , bool ) > register_signal )
2022-03-02 08:23:07 -06:00
{
2022-08-09 08:43:26 -05:00
int exit_scopes = 1 ;
if ( shared - > hdlname & & instance ! = nullptr & & instance - > name . isPublic ( ) & & instance - > has_attribute ( ID : : hdlname ) ) {
auto hdlname = instance - > get_hdlname_attribute ( ) ;
log_assert ( ! hdlname . empty ( ) ) ;
for ( auto name : hdlname )
enter_scope ( " \\ " + name ) ;
exit_scopes = hdlname . size ( ) ;
} else
enter_scope ( name ( ) ) ;
2017-08-16 06:05:21 -05:00
2022-03-16 08:35:39 -05:00
dict < Wire * , bool > registers ;
for ( auto cell : module - > cells ( ) )
{
if ( RTLIL : : builtin_ff_cell_types ( ) . count ( cell - > type ) ) {
FfData ff_data ( nullptr , cell ) ;
SigSpec q = sigmap ( ff_data . sig_q ) ;
if ( q . is_wire ( ) & & signal_database . count ( q . as_wire ( ) ) ! = 0 ) {
registers [ q . as_wire ( ) ] = true ;
}
}
}
2022-03-02 08:23:07 -06:00
for ( auto signal : signal_database )
{
2022-08-09 08:43:26 -05:00
if ( shared - > hdlname & & signal . first - > name . isPublic ( ) & & signal . first - > has_attribute ( ID : : hdlname ) ) {
auto hdlname = signal . first - > get_hdlname_attribute ( ) ;
log_assert ( ! hdlname . empty ( ) ) ;
auto signal_name = std : : move ( hdlname . back ( ) ) ;
hdlname . pop_back ( ) ;
for ( auto name : hdlname )
enter_scope ( " \\ " + name ) ;
2022-12-21 07:33:20 -06:00
register_signal ( signal_name . c_str ( ) , GetSize ( signal . first ) , signal . first , signal . second . first , registers . count ( signal . first ) ! = 0 ) ;
2022-08-09 08:43:26 -05:00
for ( auto name : hdlname )
exit_scope ( ) ;
} else
2022-12-21 07:33:20 -06:00
register_signal ( log_id ( signal . first - > name ) , GetSize ( signal . first ) , signal . first , signal . second . first , registers . count ( signal . first ) ! = 0 ) ;
}
for ( auto & trace_mem : trace_mem_database )
{
auto memid = trace_mem . first ;
auto & mdb = mem_database . at ( memid ) ;
Cell * cell = mdb . mem - > cell ;
std : : vector < std : : string > hdlname ;
std : : string signal_name ;
bool has_hdlname = shared - > hdlname & & cell ! = nullptr & & cell - > name . isPublic ( ) & & cell - > has_attribute ( ID : : hdlname ) ;
if ( has_hdlname ) {
hdlname = cell - > get_hdlname_attribute ( ) ;
log_assert ( ! hdlname . empty ( ) ) ;
signal_name = std : : move ( hdlname . back ( ) ) ;
hdlname . pop_back ( ) ;
for ( auto name : hdlname )
enter_scope ( " \\ " + name ) ;
} else {
signal_name = log_id ( memid ) ;
}
for ( auto & trace_index : trace_mem . second ) {
int output_id = trace_index . second . first ;
int index = trace_index . first ;
register_signal (
stringf ( " %s[%d] " , signal_name . c_str ( ) , ( index + mdb . mem - > start_offset ) ) . c_str ( ) ,
mdb . mem - > width , nullptr , output_id , true ) ;
}
if ( has_hdlname )
for ( auto name : hdlname )
exit_scope ( ) ;
2022-03-02 08:23:07 -06:00
}
for ( auto child : children )
child . second - > write_output_header ( enter_scope , exit_scope , register_signal ) ;
2022-08-09 08:43:26 -05:00
for ( int i = 0 ; i < exit_scopes ; i + + )
exit_scope ( ) ;
2017-08-16 06:05:21 -05:00
}
2022-12-21 07:33:20 -06:00
void register_memory_addr ( IdString memid , int addr )
{
auto & mdb = mem_database . at ( memid ) ;
auto & mem = * mdb . mem ;
int index = addr - mem . start_offset ;
if ( index < 0 | | index > = mem . size )
return ;
auto it = trace_mem_database . find ( memid ) ;
if ( it ! = trace_mem_database . end ( ) & & it - > second . count ( index ) )
return ;
int output_id = shared - > next_output_id + + ;
Const data ;
if ( ! shared - > output_data . empty ( ) ) {
2023-01-10 10:04:06 -06:00
auto init_it = trace_mem_init_database . find ( std : : make_pair ( memid , addr ) ) ;
if ( init_it ! = trace_mem_init_database . end ( ) )
data = init_it - > second ;
else
data = mem . get_init_data ( ) . extract ( index * mem . width , mem . width ) ;
2022-12-21 07:33:20 -06:00
shared - > output_data . front ( ) . second . emplace ( output_id , data ) ;
}
trace_mem_database [ memid ] . emplace ( index , make_pair ( output_id , data ) ) ;
}
2022-03-02 08:23:07 -06:00
void register_output_step_values ( std : : map < int , Const > * data )
2017-08-16 06:05:21 -05:00
{
2022-02-28 11:22:39 -06:00
for ( auto & it : signal_database )
2017-08-16 06:05:21 -05:00
{
Wire * wire = it . first ;
Const value = get_state ( wire ) ;
2017-08-17 05:27:08 -05:00
int id = it . second . first ;
if ( it . second . second = = value )
continue ;
it . second . second = value ;
2022-03-02 08:23:07 -06:00
data - > emplace ( id , value ) ;
2022-01-26 02:26:19 -06:00
}
2022-12-21 07:33:20 -06:00
for ( auto & trace_mem : trace_mem_database )
{
auto memid = trace_mem . first ;
auto & mdb = mem_database . at ( memid ) ;
auto & mem = * mdb . mem ;
for ( auto & trace_index : trace_mem . second )
{
int output_id = trace_index . second . first ;
int index = trace_index . first ;
auto value = mdb . data . extract ( index * mem . width , mem . width ) ;
if ( trace_index . second . second = = value )
continue ;
trace_index . second . second = value ;
data - > emplace ( output_id , value ) ;
}
}
2022-01-26 02:26:19 -06:00
for ( auto child : children )
2022-03-02 08:23:07 -06:00
child . second - > register_output_step_values ( data ) ;
2022-01-26 02:26:19 -06:00
}
2022-01-28 06:24:38 -06:00
2022-04-02 03:34:11 -05:00
bool setInitState ( )
2022-01-28 08:59:13 -06:00
{
2022-04-02 03:34:11 -05:00
bool did_something = false ;
2022-04-22 04:57:39 -05:00
for ( auto & item : fst_handles ) {
if ( item . second = = 0 ) continue ; // Ignore signals not found
std : : string v = shared - > fst - > valueOf ( item . second ) ;
did_something | = set_state ( item . first , Const : : from_string ( v ) ) ;
}
2022-05-04 03:41:04 -05:00
for ( auto cell : module - > cells ( ) )
{
if ( cell - > is_mem_cell ( ) ) {
std : : string memid = cell - > parameters . at ( ID : : MEMID ) . decode_string ( ) ;
for ( auto & data : fst_memories [ memid ] )
{
std : : string v = shared - > fst - > valueOf ( data . second ) ;
set_memory_state ( memid , Const ( data . first ) , Const : : from_string ( v ) ) ;
}
}
}
2022-01-28 08:59:13 -06:00
for ( auto child : children )
2022-04-02 03:34:11 -05:00
did_something | = child . second - > setInitState ( ) ;
return did_something ;
2022-01-28 08:59:13 -06:00
}
2022-07-22 07:47:00 -05:00
void addAdditionalInputs ( )
2022-04-22 09:23:39 -05:00
{
for ( auto cell : module - > cells ( ) )
{
if ( cell - > type . in ( ID ( $ anyseq ) ) ) {
2022-04-22 10:20:17 -05:00
SigSpec sig_y = sigmap ( cell - > getPort ( ID : : Y ) ) ;
2022-04-22 09:23:39 -05:00
if ( sig_y . is_wire ( ) ) {
2022-04-22 10:20:17 -05:00
bool found = false ;
for ( auto & item : fst_handles ) {
if ( item . second = = 0 ) continue ; // Ignore signals not found
if ( sig_y = = sigmap ( item . first ) ) {
2022-07-22 07:47:00 -05:00
fst_inputs [ sig_y . as_wire ( ) ] = item . second ;
2022-04-22 10:20:17 -05:00
found = true ;
break ;
}
}
if ( ! found )
log_error ( " Unable to find required '%s' signal in file \n " , ( scope + " . " + RTLIL : : unescape_id ( sig_y . as_wire ( ) - > name ) ) . c_str ( ) ) ;
2022-04-22 09:23:39 -05:00
}
}
}
for ( auto child : children )
2022-07-22 07:47:00 -05:00
child . second - > addAdditionalInputs ( ) ;
}
bool setInputs ( )
{
bool did_something = false ;
for ( auto & item : fst_inputs ) {
std : : string v = shared - > fst - > valueOf ( item . second ) ;
did_something | = set_state ( item . first , Const : : from_string ( v ) ) ;
}
for ( auto child : children )
did_something | = child . second - > setInputs ( ) ;
return did_something ;
2022-04-22 09:23:39 -05:00
}
2022-02-25 08:50:46 -06:00
void setState ( dict < int , std : : pair < SigBit , bool > > bits , std : : string values )
2022-02-18 08:04:02 -06:00
{
2022-02-25 08:50:46 -06:00
for ( auto bit : bits ) {
if ( bit . first > = GetSize ( values ) )
log_error ( " Too few input data bits in file. \n " ) ;
switch ( values . at ( bit . first ) ) {
case ' 0 ' : set_state ( bit . second . first , bit . second . second ? State : : S1 : State : : S0 ) ; break ;
case ' 1 ' : set_state ( bit . second . first , bit . second . second ? State : : S0 : State : : S1 ) ; break ;
default : set_state ( bit . second . first , State : : Sx ) ; break ;
2022-02-18 08:04:02 -06:00
}
}
}
2022-03-31 06:10:13 -05:00
void setMemState ( dict < int , std : : pair < std : : string , int > > bits , std : : string values )
{
for ( auto bit : bits ) {
if ( bit . first > = GetSize ( values ) )
log_error ( " Too few input data bits in file. \n " ) ;
switch ( values . at ( bit . first ) ) {
case ' 0 ' : set_memory_state_bit ( bit . second . first , bit . second . second , State : : S0 ) ; break ;
case ' 1 ' : set_memory_state_bit ( bit . second . first , bit . second . second , State : : S1 ) ; break ;
default : set_memory_state_bit ( bit . second . first , bit . second . second , State : : Sx ) ; break ;
}
}
}
2022-02-15 02:30:42 -06:00
bool checkSignals ( )
2022-01-28 06:24:38 -06:00
{
bool retVal = false ;
for ( auto & item : fst_handles ) {
if ( item . second = = 0 ) continue ; // Ignore signals not found
2022-02-15 02:30:42 -06:00
Const fst_val = Const : : from_string ( shared - > fst - > valueOf ( item . second ) ) ;
2022-01-28 06:24:38 -06:00
Const sim_val = get_state ( item . first ) ;
2022-03-18 08:47:35 -05:00
if ( sim_val . size ( ) ! = fst_val . size ( ) ) {
log_warning ( " Signal '%s.%s' size is different in gold and gate. \n " , scope . c_str ( ) , log_id ( item . first ) ) ;
continue ;
}
2022-02-02 02:37:32 -06:00
if ( shared - > sim_mode = = SimulationMode : : sim ) {
// No checks performed when using stimulus
} else if ( shared - > sim_mode = = SimulationMode : : gate & & ! fst_val . is_fully_def ( ) ) { // FST data contains X
2022-01-31 06:41:02 -06:00
for ( int i = 0 ; i < fst_val . size ( ) ; i + + ) {
if ( fst_val [ i ] ! = State : : Sx & & fst_val [ i ] ! = sim_val [ i ] ) {
2022-03-18 08:47:35 -05:00
log_warning ( " Signal '%s.%s' in file %s in simulation %s \n " , scope . c_str ( ) , log_id ( item . first ) , log_signal ( fst_val ) , log_signal ( sim_val ) ) ;
2022-01-31 06:41:02 -06:00
retVal = true ;
break ;
}
}
2022-01-28 06:24:38 -06:00
} else if ( shared - > sim_mode = = SimulationMode : : gold & & ! sim_val . is_fully_def ( ) ) { // sim data contains X
2022-01-31 06:41:02 -06:00
for ( int i = 0 ; i < sim_val . size ( ) ; i + + ) {
if ( sim_val [ i ] ! = State : : Sx & & fst_val [ i ] ! = sim_val [ i ] ) {
2022-03-18 08:47:35 -05:00
log_warning ( " Signal '%s.%s' in file %s in simulation %s \n " , scope . c_str ( ) , log_id ( item . first ) , log_signal ( fst_val ) , log_signal ( sim_val ) ) ;
2022-01-31 06:41:02 -06:00
retVal = true ;
break ;
}
}
2022-01-28 06:24:38 -06:00
} else {
if ( fst_val ! = sim_val ) {
2022-03-18 08:47:35 -05:00
log_warning ( " Signal '%s.%s' in file %s in simulation '%s' \n " , scope . c_str ( ) , log_id ( item . first ) , log_signal ( fst_val ) , log_signal ( sim_val ) ) ;
2022-01-28 06:24:38 -06:00
retVal = true ;
}
}
}
for ( auto child : children )
2022-02-15 02:30:42 -06:00
retVal | = child . second - > checkSignals ( ) ;
2022-01-28 06:24:38 -06:00
return retVal ;
}
2017-08-16 06:05:21 -05:00
} ;
2017-08-17 05:27:08 -05:00
struct SimWorker : SimShared
2017-08-16 06:05:21 -05:00
{
SimInstance * top = nullptr ;
2017-08-17 05:27:08 -05:00
pool < IdString > clock , clockn , reset , resetn ;
2020-10-16 11:19:58 -05:00
std : : string timescale ;
2022-01-26 08:50:38 -06:00
std : : string sim_filename ;
2022-02-18 08:04:02 -06:00
std : : string map_filename ;
2023-01-10 10:04:06 -06:00
std : : string summary_filename ;
2022-01-26 08:50:38 -06:00
std : : string scope ;
2017-08-16 06:05:21 -05:00
2017-08-17 05:27:08 -05:00
~ SimWorker ( )
2017-08-16 06:05:21 -05:00
{
2022-02-28 11:22:39 -06:00
outputfiles . clear ( ) ;
2017-08-17 05:27:08 -05:00
delete top ;
2017-08-16 06:05:21 -05:00
}
2022-03-02 08:23:07 -06:00
void register_signals ( )
2022-01-26 02:26:19 -06:00
{
2022-12-21 07:33:20 -06:00
next_output_id = 1 ;
top - > register_signals ( top - > shared - > next_output_id ) ;
2022-01-26 02:26:19 -06:00
}
2022-03-02 08:23:07 -06:00
void register_output_step ( int t )
2022-01-26 02:26:19 -06:00
{
2022-03-02 08:23:07 -06:00
std : : map < int , Const > data ;
top - > register_output_step_values ( & data ) ;
output_data . emplace_back ( t , data ) ;
2022-01-26 02:26:19 -06:00
}
2022-03-02 08:23:07 -06:00
void write_output_files ( )
{
2022-03-02 09:02:13 -06:00
std : : map < int , bool > use_signal ;
bool first = ignore_x ;
for ( auto & d : output_data )
{
if ( first ) {
for ( auto & data : d . second )
use_signal [ data . first ] = ! data . second . is_fully_undef ( ) ;
first = false ;
} else {
for ( auto & data : d . second )
use_signal [ data . first ] = true ;
}
if ( ! ignore_x ) break ;
}
2022-03-02 08:23:07 -06:00
for ( auto & writer : outputfiles )
2022-03-02 09:02:13 -06:00
writer - > write ( use_signal ) ;
2023-05-07 20:13:09 -05:00
if ( writeback ) {
pool < Module * > wbmods ;
top - > writeback ( wbmods ) ;
}
2022-03-02 08:23:07 -06:00
}
2022-02-28 11:22:39 -06:00
2022-11-25 10:43:51 -06:00
void update ( bool gclk )
2017-08-17 05:27:08 -05:00
{
2023-01-10 10:04:06 -06:00
if ( gclk )
step + = 1 ;
2017-08-18 03:24:14 -05:00
while ( 1 )
2017-08-17 05:27:08 -05:00
{
if ( debug )
log ( " \n -- ph1 -- \n " ) ;
top - > update_ph1 ( ) ;
if ( debug )
log ( " \n -- ph2 -- \n " ) ;
2017-08-18 03:24:14 -05:00
2022-11-25 10:43:51 -06:00
if ( ! top - > update_ph2 ( gclk ) )
2017-08-18 03:24:14 -05:00
break ;
2017-08-17 05:27:08 -05:00
}
if ( debug )
log ( " \n -- ph3 -- \n " ) ;
2022-12-21 07:40:58 -06:00
top - > update_ph3 ( gclk ) ;
2017-08-17 05:27:08 -05:00
}
2022-11-07 07:09:33 -06:00
void initialize_stable_past ( )
{
2023-05-25 05:46:16 -05:00
while ( 1 )
{
if ( debug )
log ( " \n -- ph1 (initialize) -- \n " ) ;
top - > update_ph1 ( ) ;
if ( debug )
log ( " \n -- ph2 (initialize) -- \n " ) ;
if ( ! top - > update_ph2 ( false , true ) )
break ;
}
2022-11-07 07:09:33 -06:00
if ( debug )
log ( " \n -- ph3 (initialize) -- \n " ) ;
2023-01-10 10:04:06 -06:00
top - > update_ph3 ( true ) ;
2022-11-07 07:09:33 -06:00
}
2017-08-17 05:27:08 -05:00
void set_inports ( pool < IdString > ports , State value )
{
for ( auto portname : ports )
{
Wire * w = top - > module - > wire ( portname ) ;
if ( w = = nullptr )
log_error ( " Can't find port %s on module %s. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
top - > set_state ( w , value ) ;
}
}
void run ( Module * topmod , int numcycles )
{
log_assert ( top = = nullptr ) ;
2022-01-26 08:50:38 -06:00
top = new SimInstance ( this , scope , topmod ) ;
2022-03-02 08:23:07 -06:00
register_signals ( ) ;
2017-08-17 05:27:08 -05:00
if ( debug )
log ( " \n ===== 0 ===== \n " ) ;
2022-03-11 09:26:11 -06:00
else if ( verbose )
2017-08-18 03:24:14 -05:00
log ( " Simulating cycle 0. \n " ) ;
2017-08-17 05:27:08 -05:00
set_inports ( reset , State : : S1 ) ;
set_inports ( resetn , State : : S0 ) ;
2017-08-18 05:54:17 -05:00
set_inports ( clock , State : : Sx ) ;
set_inports ( clockn , State : : Sx ) ;
2022-11-25 10:43:51 -06:00
update ( false ) ;
2017-08-17 05:27:08 -05:00
2022-03-02 08:23:07 -06:00
register_output_step ( 0 ) ;
2017-08-17 05:27:08 -05:00
for ( int cycle = 0 ; cycle < numcycles ; cycle + + )
{
if ( debug )
log ( " \n ===== %d ===== \n " , 10 * cycle + 5 ) ;
2022-03-11 09:26:11 -06:00
else if ( verbose )
2022-02-02 03:08:23 -06:00
log ( " Simulating cycle %d. \n " , ( cycle * 2 ) + 1 ) ;
2017-08-17 05:27:08 -05:00
set_inports ( clock , State : : S0 ) ;
set_inports ( clockn , State : : S1 ) ;
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * cycle + 5 ) ;
2017-08-17 05:27:08 -05:00
if ( debug )
log ( " \n ===== %d ===== \n " , 10 * cycle + 10 ) ;
2022-03-11 09:26:11 -06:00
else if ( verbose )
2022-02-02 03:08:23 -06:00
log ( " Simulating cycle %d. \n " , ( cycle * 2 ) + 2 ) ;
2017-08-17 05:27:08 -05:00
set_inports ( clock , State : : S1 ) ;
set_inports ( clockn , State : : S0 ) ;
2017-08-18 05:54:17 -05:00
if ( cycle + 1 = = rstlen ) {
2017-08-17 05:27:08 -05:00
set_inports ( reset , State : : S0 ) ;
set_inports ( resetn , State : : S1 ) ;
}
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * cycle + 10 ) ;
2017-08-17 05:27:08 -05:00
}
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * numcycles + 2 ) ;
write_output_files ( ) ;
2017-08-17 05:27:08 -05:00
}
2022-01-26 08:50:38 -06:00
2022-03-07 06:59:36 -06:00
void run_cosim_fst ( Module * topmod , int numcycles )
2022-01-26 08:50:38 -06:00
{
log_assert ( top = = nullptr ) ;
fst = new FstData ( sim_filename ) ;
2022-02-04 04:11:36 -06:00
if ( scope . empty ( ) )
log_error ( " Scope must be defined for co-simulation. \n " ) ;
2022-01-28 06:24:38 -06:00
top = new SimInstance ( this , scope , topmod ) ;
2022-03-02 08:23:07 -06:00
register_signals ( ) ;
2022-01-28 06:24:38 -06:00
2022-01-26 08:50:38 -06:00
std : : vector < fstHandle > fst_clock ;
for ( auto portname : clock )
{
Wire * w = topmod - > wire ( portname ) ;
if ( ! w )
log_error ( " Can't find port %s on module %s. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
if ( ! w - > port_input )
log_error ( " Clock port %s on module %s is not input. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( portname ) ) ;
if ( id = = 0 )
log_error ( " Can't find port %s.%s in FST. \n " , scope . c_str ( ) , log_id ( portname ) ) ;
fst_clock . push_back ( id ) ;
}
for ( auto portname : clockn )
{
Wire * w = topmod - > wire ( portname ) ;
if ( ! w )
log_error ( " Can't find port %s on module %s. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
if ( ! w - > port_input )
log_error ( " Clock port %s on module %s is not input. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( portname ) ) ;
if ( id = = 0 )
log_error ( " Can't find port %s.%s in FST. \n " , scope . c_str ( ) , log_id ( portname ) ) ;
fst_clock . push_back ( id ) ;
}
SigMap sigmap ( topmod ) ;
for ( auto wire : topmod - > wires ( ) ) {
if ( wire - > port_input ) {
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) ;
2022-01-31 10:41:50 -06:00
if ( id = = 0 )
log_error ( " Unable to find required '%s' signal in file \n " , ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) . c_str ( ) ) ;
2022-07-22 07:47:00 -05:00
top - > fst_inputs [ wire ] = id ;
2022-01-26 08:50:38 -06:00
}
}
2022-07-22 07:47:00 -05:00
top - > addAdditionalInputs ( ) ;
2022-04-22 09:23:39 -05:00
2022-01-28 03:18:02 -06:00
uint64_t startCount = 0 ;
uint64_t stopCount = 0 ;
if ( start_time = = 0 ) {
if ( start_time < fst - > getStartTime ( ) )
log_warning ( " Start time is before simulation file start time \n " ) ;
startCount = fst - > getStartTime ( ) ;
} else if ( start_time = = - 1 )
startCount = fst - > getEndTime ( ) ;
else {
startCount = start_time / fst - > getTimescale ( ) ;
if ( startCount > fst - > getEndTime ( ) ) {
startCount = fst - > getEndTime ( ) ;
log_warning ( " Start time is after simulation file end time \n " ) ;
}
}
if ( stop_time = = 0 ) {
if ( stop_time < fst - > getStartTime ( ) )
log_warning ( " Stop time is before simulation file start time \n " ) ;
stopCount = fst - > getStartTime ( ) ;
} else if ( stop_time = = - 1 )
stopCount = fst - > getEndTime ( ) ;
else {
stopCount = stop_time / fst - > getTimescale ( ) ;
if ( stopCount > fst - > getEndTime ( ) ) {
stopCount = fst - > getEndTime ( ) ;
log_warning ( " Stop time is after simulation file end time \n " ) ;
}
}
2022-01-28 12:41:43 -06:00
if ( stopCount < startCount ) {
log_error ( " Stop time is before start time \n " ) ;
}
2022-02-02 03:08:23 -06:00
bool initial = true ;
int cycle = 0 ;
2022-02-15 02:30:42 -06:00
log ( " Co-simulation from %lu%s to %lu%s " , ( unsigned long ) startCount , fst - > getTimescaleString ( ) , ( unsigned long ) stopCount , fst - > getTimescaleString ( ) ) ;
if ( cycles_set )
log ( " for %d clock cycle(s) " , numcycles ) ;
log ( " \n " ) ;
bool all_samples = fst_clock . empty ( ) ;
try {
fst - > reconstructAllAtTimes ( fst_clock , startCount , stopCount , [ & ] ( uint64_t time ) {
2022-03-11 09:26:11 -06:00
if ( verbose )
log ( " Co-simulating %s %d [%lu%s]. \n " , ( all_samples ? " sample " : " cycle " ) , cycle , ( unsigned long ) time , fst - > getTimescaleString ( ) ) ;
2022-07-22 07:47:00 -05:00
bool did_something = top - > setInputs ( ) ;
2022-02-02 03:08:23 -06:00
2022-02-15 02:30:42 -06:00
if ( initial ) {
2022-04-02 03:34:11 -05:00
did_something | = top - > setInitState ( ) ;
2022-11-07 07:09:33 -06:00
initialize_stable_past ( ) ;
2022-02-15 02:30:42 -06:00
initial = false ;
}
2022-02-25 08:50:46 -06:00
if ( did_something )
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-02 08:23:07 -06:00
register_output_step ( time ) ;
2022-02-15 02:30:42 -06:00
bool status = top - > checkSignals ( ) ;
if ( status )
log_error ( " Signal difference \n " ) ;
cycle + + ;
// Limit to number of cycles if provided
if ( cycles_set & & cycle > numcycles * 2 )
throw fst_end_of_data_exception ( ) ;
if ( time = = stopCount )
throw fst_end_of_data_exception ( ) ;
} ) ;
} catch ( fst_end_of_data_exception ) {
// end of data detected
2022-02-02 03:08:23 -06:00
}
2022-02-15 02:30:42 -06:00
2022-03-02 08:23:07 -06:00
write_output_files ( ) ;
2022-02-28 02:09:07 -06:00
delete fst ;
2022-01-26 08:51:43 -06:00
}
2022-02-18 08:04:02 -06:00
2022-03-31 06:10:13 -05:00
std : : string cell_name ( std : : string const & name )
{
size_t pos = name . find_last_of ( " [ " ) ;
if ( pos ! = std : : string : : npos )
return name . substr ( 0 , pos ) ;
return name ;
}
int mem_cell_addr ( std : : string const & name )
{
size_t pos = name . find_last_of ( " [ " ) ;
return atoi ( name . substr ( pos + 1 ) . c_str ( ) ) ;
}
2022-03-07 06:59:36 -06:00
void run_cosim_aiger_witness ( Module * topmod )
2022-02-18 08:04:02 -06:00
{
log_assert ( top = = nullptr ) ;
2022-03-31 06:10:13 -05:00
if ( ! multiclock & & ( clock . size ( ) + clockn . size ( ) ) = = 0 )
2022-03-09 02:48:29 -06:00
log_error ( " Clock signal must be specified. \n " ) ;
2022-03-31 06:10:13 -05:00
if ( multiclock & & ( clock . size ( ) + clockn . size ( ) ) > 0 )
log_error ( " For multiclock witness there should be no clock signal. \n " ) ;
top = new SimInstance ( this , scope , topmod ) ;
register_signals ( ) ;
2022-02-18 08:04:02 -06:00
std : : ifstream mf ( map_filename ) ;
std : : string type , symbol ;
int variable , index ;
2022-02-25 08:50:46 -06:00
dict < int , std : : pair < SigBit , bool > > inputs , inits , latches ;
2022-03-31 06:10:13 -05:00
dict < int , std : : pair < std : : string , int > > mem_inits , mem_latches ;
2022-03-07 08:00:14 -06:00
if ( mf . fail ( ) )
log_cmd_error ( " Not able to read AIGER witness map file. \n " ) ;
2022-02-18 08:04:02 -06:00
while ( mf > > type > > variable > > index > > symbol ) {
RTLIL : : IdString escaped_s = RTLIL : : escape_id ( symbol ) ;
Wire * w = topmod - > wire ( escaped_s ) ;
2022-03-31 06:10:13 -05:00
if ( ! w ) {
escaped_s = RTLIL : : escape_id ( cell_name ( symbol ) ) ;
Cell * c = topmod - > cell ( escaped_s ) ;
if ( ! c )
log_warning ( " Wire/cell %s not present in module %s \n " , symbol . c_str ( ) , log_id ( topmod ) ) ;
if ( c - > is_mem_cell ( ) ) {
std : : string memid = c - > parameters . at ( ID : : MEMID ) . decode_string ( ) ;
auto & state = top - > mem_database [ memid ] ;
int offset = ( mem_cell_addr ( symbol ) - state . mem - > start_offset ) * state . mem - > width + index ;
if ( type = = " init " )
mem_inits [ variable ] = { memid , offset } ;
else if ( type = = " latch " )
mem_latches [ variable ] = { memid , offset } ;
else
log_error ( " Map file addressing cell %s as type %s \n " , symbol . c_str ( ) , type . c_str ( ) ) ;
} else {
log_error ( " Cell %s in map file is not memory cell \n " , symbol . c_str ( ) ) ;
}
} else {
if ( index < w - > start_offset | | index > w - > start_offset + w - > width )
log_error ( " Index %d for wire %s is out of range \n " , index , log_signal ( w ) ) ;
if ( type = = " input " ) {
inputs [ variable ] = { SigBit ( w , index - w - > start_offset ) , false } ;
} else if ( type = = " init " ) {
inits [ variable ] = { SigBit ( w , index - w - > start_offset ) , false } ;
} else if ( type = = " latch " ) {
latches [ variable ] = { SigBit ( w , index - w - > start_offset ) , false } ;
} else if ( type = = " invlatch " ) {
latches [ variable ] = { SigBit ( w , index - w - > start_offset ) , true } ;
}
2022-02-18 08:04:02 -06:00
}
}
std : : ifstream f ;
f . open ( sim_filename . c_str ( ) ) ;
if ( f . fail ( ) | | GetSize ( sim_filename ) = = 0 )
log_error ( " Can not open file `%s` \n " , sim_filename . c_str ( ) ) ;
2022-02-27 09:37:40 -06:00
int state = 0 ;
std : : string status ;
2022-02-18 08:04:02 -06:00
int cycle = 0 ;
2022-03-02 08:23:07 -06:00
2022-02-18 08:04:02 -06:00
while ( ! f . eof ( ) )
{
std : : string line ;
std : : getline ( f , line ) ;
2022-04-15 04:45:16 -05:00
if ( line . size ( ) = = 0 | | line [ 0 ] = = ' # ' | | line [ 0 ] = = ' c ' | | line [ 0 ] = = ' f ' | | line [ 0 ] = = ' u ' ) continue ;
2022-02-27 09:37:40 -06:00
if ( line [ 0 ] = = ' . ' ) break ;
if ( state = = 0 & & line . size ( ) ! = 1 ) {
// old format detected, latch data
state = 2 ;
}
2022-04-15 04:45:16 -05:00
if ( state = = 1 & & line [ 0 ] ! = ' b ' & & line [ 0 ] ! = ' j ' ) {
2022-02-27 09:37:40 -06:00
// was old format but with 1 bit latch
top - > setState ( latches , status ) ;
state = 3 ;
}
switch ( state )
{
case 0 :
status = line ;
state = 1 ;
break ;
case 1 :
state = 2 ;
break ;
case 2 :
top - > setState ( latches , line ) ;
2022-03-31 06:10:13 -05:00
top - > setMemState ( mem_latches , line ) ;
2022-02-28 03:41:44 -06:00
state = 3 ;
2022-02-27 09:37:40 -06:00
break ;
default :
2022-03-11 09:26:11 -06:00
if ( verbose )
log ( " Simulating cycle %d. \n " , cycle ) ;
2022-02-28 04:40:06 -06:00
top - > setState ( inputs , line ) ;
2022-02-27 09:37:40 -06:00
if ( cycle ) {
set_inports ( clock , State : : S1 ) ;
set_inports ( clockn , State : : S0 ) ;
} else {
top - > setState ( inits , line ) ;
2022-03-31 06:10:13 -05:00
top - > setMemState ( mem_inits , line ) ;
2022-02-27 09:37:40 -06:00
set_inports ( clock , State : : S0 ) ;
set_inports ( clockn , State : : S1 ) ;
}
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * cycle ) ;
2022-03-31 06:10:13 -05:00
if ( ! multiclock & & cycle ) {
2022-02-27 09:37:40 -06:00
set_inports ( clock , State : : S0 ) ;
set_inports ( clockn , State : : S1 ) ;
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * cycle + 5 ) ;
2022-02-27 09:37:40 -06:00
}
cycle + + ;
break ;
2022-02-18 08:04:02 -06:00
}
}
2022-03-02 08:23:07 -06:00
register_output_step ( 10 * cycle ) ;
write_output_files ( ) ;
2022-02-18 08:04:02 -06:00
}
2022-03-07 06:59:36 -06:00
std : : vector < std : : string > split ( std : : string text , const char * delim )
{
std : : vector < std : : string > list ;
char * p = strdup ( text . c_str ( ) ) ;
char * t = strtok ( p , delim ) ;
while ( t ! = NULL ) {
list . push_back ( t ) ;
t = strtok ( NULL , delim ) ;
}
free ( p ) ;
return list ;
}
std : : string signal_name ( std : : string const & name )
{
size_t pos = name . find_first_of ( " @ " ) ;
if ( pos = = std : : string : : npos ) {
pos = name . find_first_of ( " # " ) ;
if ( pos = = std : : string : : npos )
log_error ( " Line does not contain proper signal name `%s` \n " , name . c_str ( ) ) ;
}
return name . substr ( 0 , pos ) ;
}
void run_cosim_btor2_witness ( Module * topmod )
{
log_assert ( top = = nullptr ) ;
2022-04-22 04:53:41 -05:00
if ( ! multiclock & & ( clock . size ( ) + clockn . size ( ) ) = = 0 )
2022-03-09 02:48:29 -06:00
log_error ( " Clock signal must be specified. \n " ) ;
2022-04-22 04:53:41 -05:00
if ( multiclock & & ( clock . size ( ) + clockn . size ( ) ) > 0 )
log_error ( " For multiclock witness there should be no clock signal. \n " ) ;
2022-03-07 06:59:36 -06:00
std : : ifstream f ;
f . open ( sim_filename . c_str ( ) ) ;
if ( f . fail ( ) | | GetSize ( sim_filename ) = = 0 )
log_error ( " Can not open file `%s` \n " , sim_filename . c_str ( ) ) ;
int state = 0 ;
int cycle = 0 ;
top = new SimInstance ( this , scope , topmod ) ;
register_signals ( ) ;
int prev_cycle = 0 ;
int curr_cycle = 0 ;
std : : vector < std : : string > parts ;
2022-03-09 11:34:02 -06:00
size_t len = 0 ;
2022-03-07 06:59:36 -06:00
while ( ! f . eof ( ) )
{
std : : string line ;
std : : getline ( f , line ) ;
if ( line . size ( ) = = 0 ) continue ;
if ( line [ 0 ] = = ' # ' | | line [ 0 ] = = ' @ ' | | line [ 0 ] = = ' . ' ) {
if ( line [ 0 ] ! = ' . ' )
curr_cycle = atoi ( line . c_str ( ) + 1 ) ;
else
curr_cycle = - 1 ; // force detect change
if ( curr_cycle ! = prev_cycle ) {
2022-03-11 09:26:11 -06:00
if ( verbose )
log ( " Simulating cycle %d. \n " , cycle ) ;
2022-03-07 06:59:36 -06:00
set_inports ( clock , State : : S1 ) ;
set_inports ( clockn , State : : S0 ) ;
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-03-07 06:59:36 -06:00
register_output_step ( 10 * cycle + 0 ) ;
2022-04-22 04:53:41 -05:00
if ( ! multiclock ) {
set_inports ( clock , State : : S0 ) ;
set_inports ( clockn , State : : S1 ) ;
2022-11-25 10:43:51 -06:00
update ( true ) ;
2022-04-22 04:53:41 -05:00
register_output_step ( 10 * cycle + 5 ) ;
}
2022-03-07 06:59:36 -06:00
cycle + + ;
prev_cycle = curr_cycle ;
}
if ( line [ 0 ] = = ' . ' ) break ;
continue ;
}
switch ( state )
{
case 0 :
if ( line = = " sat " )
state = 1 ;
break ;
case 1 :
if ( line [ 0 ] = = ' b ' | | line [ 0 ] = = ' j ' )
state = 2 ;
else
log_error ( " Line does not contain property. \n " ) ;
break ;
default : // set state or inputs
parts = split ( line , " " ) ;
2022-03-09 11:34:02 -06:00
len = parts . size ( ) ;
if ( len < 3 | | len > 4 )
2022-03-07 06:59:36 -06:00
log_error ( " Invalid set state line content. \n " ) ;
2022-03-09 11:34:02 -06:00
RTLIL : : IdString escaped_s = RTLIL : : escape_id ( signal_name ( parts [ len - 1 ] ) ) ;
if ( len = = 3 ) {
Wire * w = topmod - > wire ( escaped_s ) ;
2022-03-11 08:11:14 -06:00
if ( ! w ) {
Cell * c = topmod - > cell ( escaped_s ) ;
if ( ! c )
log_warning ( " Wire/cell %s not present in module %s \n " , log_id ( escaped_s ) , log_id ( topmod ) ) ;
else if ( c - > type . in ( ID ( $ anyconst ) , ID ( $ anyseq ) ) ) {
SigSpec sig_y = c - > getPort ( ID : : Y ) ;
if ( ( int ) parts [ 1 ] . size ( ) ! = GetSize ( sig_y ) )
log_error ( " Size of wire %s is different than provided data. \n " , log_signal ( sig_y ) ) ;
top - > set_state ( sig_y , Const : : from_string ( parts [ 1 ] ) ) ;
}
} else {
if ( ( int ) parts [ 1 ] . size ( ) ! = w - > width )
log_error ( " Size of wire %s is different than provided data. \n " , log_signal ( w ) ) ;
2022-03-09 11:34:02 -06:00
top - > set_state ( w , Const : : from_string ( parts [ 1 ] ) ) ;
2022-03-11 08:11:14 -06:00
}
2022-03-09 11:34:02 -06:00
} else {
Cell * c = topmod - > cell ( escaped_s ) ;
if ( ! c )
log_error ( " Cell %s not present in module %s \n " , log_id ( escaped_s ) , log_id ( topmod ) ) ;
if ( ! c - > is_mem_cell ( ) )
log_error ( " Cell %s is not memory cell in module %s \n " , log_id ( escaped_s ) , log_id ( topmod ) ) ;
2022-03-11 04:19:53 -06:00
Const addr = Const : : from_string ( parts [ 1 ] . substr ( 1 , parts [ 1 ] . size ( ) - 2 ) ) ;
Const data = Const : : from_string ( parts [ 2 ] ) ;
top - > set_memory_state ( c - > parameters . at ( ID : : MEMID ) . decode_string ( ) , addr , data ) ;
2022-03-09 11:34:02 -06:00
}
2022-03-07 06:59:36 -06:00
break ;
}
}
2022-03-07 09:32:32 -06:00
register_output_step ( 10 * cycle ) ;
2022-03-07 06:59:36 -06:00
write_output_files ( ) ;
}
2022-03-14 13:06:29 -05:00
2022-12-21 07:44:15 -06:00
struct FoundYWPath
{
SimInstance * instance ;
Wire * wire ;
IdString memid ;
int addr ;
} ;
struct YwHierarchy {
2023-01-11 10:52:25 -06:00
dict < IdPath , FoundYWPath > paths ;
2022-12-21 07:44:15 -06:00
} ;
YwHierarchy prepare_yw_hierarchy ( const ReadWitness & yw )
{
2023-01-11 10:52:25 -06:00
YwHierarchy hierarchy ;
2022-12-21 07:44:15 -06:00
pool < IdPath > paths ;
dict < IdPath , pool < IdString > > mem_paths ;
for ( auto & signal : yw . signals )
paths . insert ( signal . path ) ;
2023-01-11 10:52:25 -06:00
for ( auto & clock : yw . clocks )
2022-12-21 07:44:15 -06:00
paths . insert ( clock . path ) ;
2023-01-11 10:52:25 -06:00
2022-12-21 07:44:15 -06:00
for ( auto & path : paths )
if ( path . has_address ( ) )
mem_paths [ path . prefix ( ) ] . insert ( path . back ( ) ) ;
witness_hierarchy ( top - > module , top , [ & ] ( IdPath const & path , WitnessHierarchyItem item , SimInstance * instance ) {
if ( item . cell ! = nullptr )
return instance - > children . at ( item . cell ) ;
if ( item . wire ! = nullptr ) {
if ( paths . count ( path ) ) {
if ( debug )
log ( " witness hierarchy: found wire %s \n " , path . str ( ) . c_str ( ) ) ;
2023-01-11 10:52:25 -06:00
bool inserted = hierarchy . paths . emplace ( path , { instance , item . wire , { } , INT_MIN } ) . second ;
2022-12-21 07:44:15 -06:00
if ( ! inserted )
log_warning ( " Yosys witness path `%s` is ambiguous in this design \n " , path . str ( ) . c_str ( ) ) ;
}
} else if ( item . mem ) {
auto it = mem_paths . find ( path ) ;
if ( it ! = mem_paths . end ( ) ) {
if ( debug )
log ( " witness hierarchy: found mem %s \n " , path . str ( ) . c_str ( ) ) ;
IdPath word_path = path ;
word_path . emplace_back ( ) ;
for ( auto addr_part : it - > second ) {
word_path . back ( ) = addr_part ;
int addr ;
word_path . get_address ( addr ) ;
if ( addr < item . mem - > start_offset | | ( addr - item . mem - > start_offset ) > = item . mem - > size )
continue ;
2023-01-11 10:52:25 -06:00
bool inserted = hierarchy . paths . emplace ( word_path , { instance , nullptr , item . mem - > memid , addr } ) . second ;
2022-12-21 07:44:15 -06:00
if ( ! inserted )
log_warning ( " Yosys witness path `%s` is ambiguous in this design \n " , path . str ( ) . c_str ( ) ) ;
}
}
}
return instance ;
} ) ;
for ( auto & path : paths )
2023-01-11 10:52:25 -06:00
if ( ! hierarchy . paths . count ( path ) )
2022-12-21 07:44:15 -06:00
log_warning ( " Yosys witness path `%s` was not found in this design, ignoring \n " , path . str ( ) . c_str ( ) ) ;
2023-01-11 10:52:25 -06:00
dict < IdPath , dict < int , bool > > clock_inputs ;
2022-12-21 07:44:15 -06:00
for ( auto & clock : yw . clocks ) {
2023-01-11 10:52:25 -06:00
if ( clock . is_negedge = = clock . is_posedge )
2022-12-21 07:44:15 -06:00
continue ;
2023-01-11 10:52:25 -06:00
clock_inputs [ clock . path ] . emplace ( clock . offset , clock . is_posedge ) ;
2022-12-21 07:44:15 -06:00
}
2023-01-11 10:52:25 -06:00
for ( auto & signal : yw . signals ) {
auto it = clock_inputs . find ( signal . path ) ;
if ( it = = clock_inputs . end ( ) )
continue ;
2022-12-21 07:44:15 -06:00
2023-01-11 10:52:25 -06:00
for ( auto & clock_input : it - > second ) {
int offset = clock_input . first ;
if ( offset > = signal . offset & & ( offset - signal . offset ) < signal . width ) {
int clock_bits_offset = signal . bits_offset + ( offset - signal . offset ) ;
2022-12-21 07:44:15 -06:00
2023-01-11 10:52:25 -06:00
State expected = clock_input . second ? State : : S0 : State : : S1 ;
for ( int t = 0 ; t < GetSize ( yw . steps ) ; t + + ) {
if ( yw . get_bits ( t , clock_bits_offset , 1 ) ! = expected )
log_warning ( " Yosys witness trace has an unexpected value for the clock input `%s` in step %d. \n " , signal . path . str ( ) . c_str ( ) , t ) ;
}
}
}
}
2022-12-21 07:44:15 -06:00
// TODO add checks and warnings for witness signals (toplevel inputs, $any*) not present in the witness file
return hierarchy ;
}
void set_yw_state ( const ReadWitness & yw , const YwHierarchy & hierarchy , int t )
{
log_assert ( t > = 0 & & t < GetSize ( yw . steps ) ) ;
for ( auto & signal : yw . signals ) {
if ( signal . init_only & & t > = 1 )
continue ;
2023-01-11 10:52:25 -06:00
auto found_path_it = hierarchy . paths . find ( signal . path ) ;
if ( found_path_it = = hierarchy . paths . end ( ) )
2022-12-21 07:44:15 -06:00
continue ;
auto & found_path = found_path_it - > second ;
Const value = yw . get_bits ( t , signal . bits_offset , signal . width ) ;
if ( debug )
log ( " yw: set %s to %s \n " , signal . path . str ( ) . c_str ( ) , log_const ( value ) ) ;
if ( found_path . wire ! = nullptr ) {
2023-02-13 05:26:06 -06:00
found_path . instance - > set_state_parent_drivers (
2022-12-21 07:44:15 -06:00
SigChunk ( found_path . wire , signal . offset , signal . width ) ,
value ) ;
} else if ( ! found_path . memid . empty ( ) ) {
2023-01-10 10:04:06 -06:00
if ( t > = 1 )
found_path . instance - > register_memory_addr ( found_path . memid , found_path . addr ) ;
else
found_path . instance - > trace_mem_init_database . emplace ( make_pair ( found_path . memid , found_path . addr ) , value ) ;
2022-12-21 07:44:15 -06:00
found_path . instance - > set_memory_state (
found_path . memid , found_path . addr ,
value ) ;
}
}
}
void set_yw_clocks ( const ReadWitness & yw , const YwHierarchy & hierarchy , bool active_edge )
{
for ( auto & clock : yw . clocks ) {
if ( clock . is_negedge = = clock . is_posedge )
continue ;
2023-01-11 10:52:25 -06:00
auto found_path_it = hierarchy . paths . find ( clock . path ) ;
if ( found_path_it = = hierarchy . paths . end ( ) )
2022-12-21 07:44:15 -06:00
continue ;
auto & found_path = found_path_it - > second ;
if ( found_path . wire ! = nullptr ) {
found_path . instance - > set_state (
SigChunk ( found_path . wire , clock . offset , 1 ) ,
active_edge = = clock . is_posedge ? State : : S1 : State : : S0 ) ;
}
}
}
2022-12-21 07:59:29 -06:00
void run_cosim_yw_witness ( Module * topmod , int append )
2022-12-21 07:44:15 -06:00
{
if ( ! clock . empty ( ) )
log_cmd_error ( " The -clock option is not required nor supported when reading a Yosys witness file. \n " ) ;
if ( ! reset . empty ( ) )
log_cmd_error ( " The -reset option is not required nor supported when reading a Yosys witness file. \n " ) ;
if ( multiclock )
log_warning ( " The -multiclock option is not required and ignored when reading a Yosys witness file. \n " ) ;
ReadWitness yw ( sim_filename ) ;
top = new SimInstance ( this , scope , topmod ) ;
register_signals ( ) ;
YwHierarchy hierarchy = prepare_yw_hierarchy ( yw ) ;
if ( yw . steps . empty ( ) ) {
log_warning ( " Yosys witness file `%s` contains no time steps \n " , yw . filename . c_str ( ) ) ;
} else {
top - > set_initstate_outputs ( State : : S1 ) ;
set_yw_state ( yw , hierarchy , 0 ) ;
set_yw_clocks ( yw , hierarchy , true ) ;
initialize_stable_past ( ) ;
register_output_step ( 0 ) ;
if ( ! yw . clocks . empty ( ) ) {
if ( debug )
log ( " Simulating non-active clock edge. \n " ) ;
set_yw_clocks ( yw , hierarchy , false ) ;
update ( false ) ;
register_output_step ( 5 ) ;
}
top - > set_initstate_outputs ( State : : S0 ) ;
}
2022-12-21 07:59:29 -06:00
for ( int cycle = 1 ; cycle < GetSize ( yw . steps ) + append ; cycle + + )
2022-12-21 07:44:15 -06:00
{
if ( verbose )
log ( " Simulating cycle %d. \n " , cycle ) ;
2022-12-21 07:59:29 -06:00
if ( cycle < GetSize ( yw . steps ) )
set_yw_state ( yw , hierarchy , cycle ) ;
2022-12-21 07:44:15 -06:00
set_yw_clocks ( yw , hierarchy , true ) ;
update ( true ) ;
register_output_step ( 10 * cycle ) ;
if ( ! yw . clocks . empty ( ) ) {
if ( debug )
log ( " Simulating non-active clock edge. \n " ) ;
set_yw_clocks ( yw , hierarchy , false ) ;
update ( false ) ;
register_output_step ( 5 + 10 * cycle ) ;
}
}
2022-12-21 07:59:29 -06:00
register_output_step ( 10 * ( GetSize ( yw . steps ) + append ) ) ;
2022-12-21 07:44:15 -06:00
write_output_files ( ) ;
}
2023-01-10 10:04:06 -06:00
void write_summary ( )
{
if ( summary_filename . empty ( ) )
return ;
PrettyJson json ;
if ( ! json . write_to_file ( summary_filename ) )
log_error ( " Can't open file `%s' for writing: %s \n " , summary_filename . c_str ( ) , strerror ( errno ) ) ;
json . begin_object ( ) ;
json . entry ( " version " , " Yosys sim summary " ) ;
json . entry ( " generator " , yosys_version_str ) ;
json . entry ( " steps " , step ) ;
json . entry ( " top " , log_id ( top - > module - > name ) ) ;
json . name ( " assertions " ) ;
json . begin_array ( ) ;
for ( auto & assertion : triggered_assertions ) {
json . begin_object ( ) ;
json . entry ( " step " , assertion . step ) ;
json . entry ( " type " , log_id ( assertion . cell - > type ) ) ;
json . entry ( " path " , assertion . instance - > witness_full_path ( assertion . cell ) ) ;
auto src = assertion . cell - > get_string_attribute ( ID : : src ) ;
if ( ! src . empty ( ) ) {
json . entry ( " src " , src ) ;
}
json . end_object ( ) ;
}
json . end_array ( ) ;
json . end_object ( ) ;
}
2022-03-14 13:06:29 -05:00
std : : string define_signal ( Wire * wire )
{
std : : stringstream f ;
if ( wire - > width = = 1 )
f < < stringf ( " %s " , RTLIL : : unescape_id ( wire - > name ) . c_str ( ) ) ;
else
if ( wire - > upto )
f < < stringf ( " [%d:%d] %s " , wire - > start_offset , wire - > width - 1 + wire - > start_offset , RTLIL : : unescape_id ( wire - > name ) . c_str ( ) ) ;
else
f < < stringf ( " [%d:%d] %s " , wire - > width - 1 + wire - > start_offset , wire - > start_offset , RTLIL : : unescape_id ( wire - > name ) . c_str ( ) ) ;
return f . str ( ) ;
}
std : : string signal_list ( std : : map < Wire * , fstHandle > & signals )
{
std : : stringstream f ;
for ( auto item = signals . begin ( ) ; item ! = signals . end ( ) ; item + + )
f < < stringf ( " %c%s " , ( item = = signals . begin ( ) ? ' ' : ' , ' ) , RTLIL : : unescape_id ( item - > first - > name ) . c_str ( ) ) ;
return f . str ( ) ;
}
void generate_tb ( Module * topmod , std : : string tb_filename , int numcycles )
{
fst = new FstData ( sim_filename ) ;
if ( scope . empty ( ) )
log_error ( " Scope must be defined for co-simulation. \n " ) ;
if ( ( clock . size ( ) + clockn . size ( ) ) = = 0 )
log_error ( " Clock signal must be specified. \n " ) ;
std : : vector < fstHandle > fst_clock ;
std : : map < Wire * , fstHandle > clocks ;
for ( auto portname : clock )
{
Wire * w = topmod - > wire ( portname ) ;
if ( ! w )
log_error ( " Can't find port %s on module %s. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
if ( ! w - > port_input )
log_error ( " Clock port %s on module %s is not input. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( portname ) ) ;
if ( id = = 0 )
log_error ( " Can't find port %s.%s in FST. \n " , scope . c_str ( ) , log_id ( portname ) ) ;
fst_clock . push_back ( id ) ;
clocks [ w ] = id ;
}
for ( auto portname : clockn )
{
Wire * w = topmod - > wire ( portname ) ;
if ( ! w )
log_error ( " Can't find port %s on module %s. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
if ( ! w - > port_input )
log_error ( " Clock port %s on module %s is not input. \n " , log_id ( portname ) , log_id ( top - > module ) ) ;
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( portname ) ) ;
if ( id = = 0 )
log_error ( " Can't find port %s.%s in FST. \n " , scope . c_str ( ) , log_id ( portname ) ) ;
fst_clock . push_back ( id ) ;
clocks [ w ] = id ;
}
SigMap sigmap ( topmod ) ;
std : : map < Wire * , fstHandle > inputs ;
std : : map < Wire * , fstHandle > outputs ;
for ( auto wire : topmod - > wires ( ) ) {
fstHandle id = fst - > getHandle ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) ;
if ( id = = 0 & & ( wire - > port_input | | wire - > port_output ) )
log_error ( " Unable to find required '%s' signal in file \n " , ( scope + " . " + RTLIL : : unescape_id ( wire - > name ) ) . c_str ( ) ) ;
if ( wire - > port_input )
if ( clocks . find ( wire ) = = clocks . end ( ) )
inputs [ wire ] = id ;
if ( wire - > port_output )
outputs [ wire ] = id ;
}
uint64_t startCount = 0 ;
uint64_t stopCount = 0 ;
if ( start_time = = 0 ) {
if ( start_time < fst - > getStartTime ( ) )
log_warning ( " Start time is before simulation file start time \n " ) ;
startCount = fst - > getStartTime ( ) ;
} else if ( start_time = = - 1 )
startCount = fst - > getEndTime ( ) ;
else {
startCount = start_time / fst - > getTimescale ( ) ;
if ( startCount > fst - > getEndTime ( ) ) {
startCount = fst - > getEndTime ( ) ;
log_warning ( " Start time is after simulation file end time \n " ) ;
}
}
if ( stop_time = = 0 ) {
if ( stop_time < fst - > getStartTime ( ) )
log_warning ( " Stop time is before simulation file start time \n " ) ;
stopCount = fst - > getStartTime ( ) ;
} else if ( stop_time = = - 1 )
stopCount = fst - > getEndTime ( ) ;
else {
stopCount = stop_time / fst - > getTimescale ( ) ;
if ( stopCount > fst - > getEndTime ( ) ) {
stopCount = fst - > getEndTime ( ) ;
log_warning ( " Stop time is after simulation file end time \n " ) ;
}
}
if ( stopCount < startCount ) {
log_error ( " Stop time is before start time \n " ) ;
}
int cycle = 0 ;
log ( " Generate testbench data from %lu%s to %lu%s " , ( unsigned long ) startCount , fst - > getTimescaleString ( ) , ( unsigned long ) stopCount , fst - > getTimescaleString ( ) ) ;
if ( cycles_set )
log ( " for %d clock cycle(s) " , numcycles ) ;
log ( " \n " ) ;
std : : stringstream f ;
f < < stringf ( " `timescale 1%s/1%s \n " , fst - > getTimescaleString ( ) , fst - > getTimescaleString ( ) ) ;
f < < stringf ( " module %s(); \n " , tb_filename . c_str ( ) ) ;
int clk_len = 0 ;
int inputs_len = 0 ;
int outputs_len = 0 ;
for ( auto & item : clocks ) {
clk_len + = item . first - > width ;
f < < " \t reg " < < define_signal ( item . first ) < < " ; \n " ;
}
for ( auto & item : inputs ) {
inputs_len + = item . first - > width ;
f < < " \t reg " < < define_signal ( item . first ) < < " ; \n " ;
}
for ( auto & item : outputs ) {
outputs_len + = item . first - > width ;
f < < " \t wire " < < define_signal ( item . first ) < < " ; \n " ;
}
int data_len = clk_len + inputs_len + outputs_len + 32 ;
f < < " \n " ;
f < < stringf ( " \t %s uut( " , RTLIL : : unescape_id ( topmod - > name ) . c_str ( ) ) ;
for ( auto item = clocks . begin ( ) ; item ! = clocks . end ( ) ; item + + )
f < < stringf ( " %c.%s(%s) " , ( item = = clocks . begin ( ) ? ' ' : ' , ' ) , RTLIL : : unescape_id ( item - > first - > name ) . c_str ( ) , RTLIL : : unescape_id ( item - > first - > name ) . c_str ( ) ) ;
for ( auto & item : inputs )
f < < stringf ( " ,.%s(%s) " , RTLIL : : unescape_id ( item . first - > name ) . c_str ( ) , RTLIL : : unescape_id ( item . first - > name ) . c_str ( ) ) ;
for ( auto & item : outputs )
f < < stringf ( " ,.%s(%s) " , RTLIL : : unescape_id ( item . first - > name ) . c_str ( ) , RTLIL : : unescape_id ( item . first - > name ) . c_str ( ) ) ;
f < < " ); \n " ;
f < < " \n " ;
f < < " \t integer i; \n " ;
uint64_t prev_time = startCount ;
log ( " Writing data to `%s` \n " , ( tb_filename + " .txt " ) . c_str ( ) ) ;
std : : ofstream data_file ( tb_filename + " .txt " ) ;
2022-03-16 08:35:39 -05:00
std : : stringstream initstate ;
2022-03-14 13:06:29 -05:00
try {
fst - > reconstructAllAtTimes ( fst_clock , startCount , stopCount , [ & ] ( uint64_t time ) {
for ( auto & item : clocks )
data_file < < stringf ( " %s " , fst - > valueOf ( item . second ) . c_str ( ) ) ;
for ( auto & item : inputs )
data_file < < stringf ( " %s " , fst - > valueOf ( item . second ) . c_str ( ) ) ;
for ( auto & item : outputs )
data_file < < stringf ( " %s " , fst - > valueOf ( item . second ) . c_str ( ) ) ;
data_file < < stringf ( " %s \n " , Const ( time - prev_time ) . as_string ( ) . c_str ( ) ) ;
2022-03-16 08:35:39 -05:00
if ( time = = startCount ) {
// initial state
for ( auto var : fst - > getVars ( ) ) {
if ( var . is_reg & & ! Const : : from_string ( fst - > valueOf ( var . id ) . c_str ( ) ) . is_fully_undef ( ) ) {
if ( var . scope = = scope ) {
initstate < < stringf ( " \t \t uut.%s = %d'b%s; \n " , var . name . c_str ( ) , var . width , fst - > valueOf ( var . id ) . c_str ( ) ) ;
} else if ( var . scope . find ( scope + " . " ) = = 0 ) {
initstate < < stringf ( " \t \t uut.%s.%s = %d'b%s; \n " , var . scope . substr ( scope . size ( ) + 1 ) . c_str ( ) , var . name . c_str ( ) , var . width , fst - > valueOf ( var . id ) . c_str ( ) ) ;
}
}
}
}
2022-03-14 13:06:29 -05:00
cycle + + ;
prev_time = time ;
// Limit to number of cycles if provided
if ( cycles_set & & cycle > numcycles * 2 )
throw fst_end_of_data_exception ( ) ;
if ( time = = stopCount )
throw fst_end_of_data_exception ( ) ;
} ) ;
} catch ( fst_end_of_data_exception ) {
// end of data detected
}
f < < stringf ( " \t reg [0:%d] data [0:%d]; \n " , data_len - 1 , cycle - 1 ) ;
f < < " \t initial begin; \n " ;
f < < stringf ( " \t \t $dumpfile( \" %s \" ); \n " , tb_filename . c_str ( ) ) ;
f < < stringf ( " \t \t $dumpvars(0,%s); \n " , tb_filename . c_str ( ) ) ;
2022-03-16 08:35:39 -05:00
f < < initstate . str ( ) ;
2022-03-14 13:06:29 -05:00
f < < stringf ( " \t \t $readmemb( \" %s.txt \" , data); \n " , tb_filename . c_str ( ) ) ;
f < < stringf ( " \t \t #(data[0][%d:%d]); \n " , data_len - 32 , data_len - 1 ) ;
f < < stringf ( " \t \t {%s } = data[0][%d:%d]; \n " , signal_list ( clocks ) . c_str ( ) , 0 , clk_len - 1 ) ;
f < < stringf ( " \t \t {%s } <= data[0][%d:%d]; \n " , signal_list ( inputs ) . c_str ( ) , clk_len , clk_len + inputs_len - 1 ) ;
f < < stringf ( " \t \t for (i = 1; i < %d; i++) begin \n " , cycle ) ;
f < < stringf ( " \t \t \t #(data[i][%d:%d]); \n " , data_len - 32 , data_len - 1 ) ;
f < < stringf ( " \t \t \t {%s } = data[i][%d:%d]; \n " , signal_list ( clocks ) . c_str ( ) , 0 , clk_len - 1 ) ;
f < < stringf ( " \t \t \t {%s } <= data[i][%d:%d]; \n " , signal_list ( inputs ) . c_str ( ) , clk_len , clk_len + inputs_len - 1 ) ;
f < < stringf ( " \t \t \t if ({%s } != data[i-1][%d:%d]) begin \n " , signal_list ( outputs ) . c_str ( ) , clk_len + inputs_len , clk_len + inputs_len + outputs_len - 1 ) ;
f < < " \t \t \t \t $error( \" Signal difference detected \\ n \" ); \n " ;
f < < " \t \t \t end \n " ;
f < < " \t \t end \n " ;
f < < " \t \t $finish; \n " ;
f < < " \t end \n " ;
f < < " endmodule \n " ;
log ( " Writing testbench to `%s` \n " , ( tb_filename + " .v " ) . c_str ( ) ) ;
std : : ofstream tb_file ( tb_filename + " .v " ) ;
tb_file < < f . str ( ) ;
delete fst ;
}
2017-08-16 06:05:21 -05:00
} ;
2022-02-28 11:22:39 -06:00
struct VCDWriter : public OutputWriter
{
VCDWriter ( SimWorker * worker , std : : string filename ) : OutputWriter ( worker ) {
vcdfile . open ( filename . c_str ( ) ) ;
}
2022-03-02 09:02:13 -06:00
void write ( std : : map < int , bool > & use_signal ) override
2022-02-28 11:22:39 -06:00
{
if ( ! vcdfile . is_open ( ) ) return ;
2022-03-11 09:01:59 -06:00
vcdfile < < stringf ( " $version %s $end \n " , worker - > date ? yosys_version_str : " Yosys " ) ;
2022-02-28 11:22:39 -06:00
2022-03-11 09:01:59 -06:00
if ( worker - > date ) {
std : : time_t t = std : : time ( nullptr ) ;
char mbstr [ 255 ] ;
if ( std : : strftime ( mbstr , sizeof ( mbstr ) , " %c " , std : : localtime ( & t ) ) ) {
vcdfile < < stringf ( " $date " ) < < mbstr < < stringf ( " $end \n " ) ;
}
2022-02-28 11:22:39 -06:00
}
if ( ! worker - > timescale . empty ( ) )
vcdfile < < stringf ( " $timescale %s $end \n " , worker - > timescale . c_str ( ) ) ;
2022-03-02 08:23:07 -06:00
worker - > top - > write_output_header (
[ this ] ( IdString name ) { vcdfile < < stringf ( " $scope module %s $end \n " , log_id ( name ) ) ; } ,
[ this ] ( ) { vcdfile < < stringf ( " $upscope $end \n " ) ; } ,
2022-12-21 07:33:20 -06:00
[ this , use_signal ] ( const char * name , int size , Wire * , int id , bool is_reg ) {
2022-08-09 08:43:26 -05:00
if ( use_signal . at ( id ) ) {
2022-12-21 07:33:20 -06:00
// Works around gtkwave trying to parse everything past the last [ in a signal
// name. While the emitted range doesn't necessarily match the wire's range,
// this is consistent with the range gtkwave makes up if it doesn't find a
// range
std : : string range = strchr ( name , ' [ ' ) ? stringf ( " [%d:0] " , size - 1 ) : std : : string ( ) ;
vcdfile < < stringf ( " $var %s %d n%d %s%s%s $end \n " , is_reg ? " reg " : " wire " , size , id , name [ 0 ] = = ' $ ' ? " \\ " : " " , name , range . c_str ( ) ) ;
2022-08-09 08:43:26 -05:00
}
}
2022-03-02 08:23:07 -06:00
) ;
2022-02-28 11:22:39 -06:00
vcdfile < < stringf ( " $enddefinitions $end \n " ) ;
2022-03-02 08:23:07 -06:00
for ( auto & d : worker - > output_data )
{
vcdfile < < stringf ( " #%d \n " , d . first ) ;
for ( auto & data : d . second )
{
2022-03-02 09:02:13 -06:00
if ( ! use_signal . at ( data . first ) ) continue ;
2022-03-02 08:23:07 -06:00
Const value = data . second ;
vcdfile < < " b " ;
for ( int i = GetSize ( value ) - 1 ; i > = 0 ; i - - ) {
switch ( value [ i ] ) {
case State : : S0 : vcdfile < < " 0 " ; break ;
case State : : S1 : vcdfile < < " 1 " ; break ;
case State : : Sx : vcdfile < < " x " ; break ;
default : vcdfile < < " z " ;
}
}
vcdfile < < stringf ( " n%d \n " , data . first ) ;
2022-02-28 11:22:39 -06:00
}
}
}
std : : ofstream vcdfile ;
} ;
struct FSTWriter : public OutputWriter
{
FSTWriter ( SimWorker * worker , std : : string filename ) : OutputWriter ( worker ) {
fstfile = ( struct fstContext * ) fstWriterCreate ( filename . c_str ( ) , 1 ) ;
}
virtual ~ FSTWriter ( )
{
fstWriterClose ( fstfile ) ;
}
2022-03-02 09:02:13 -06:00
void write ( std : : map < int , bool > & use_signal ) override
2022-02-28 11:22:39 -06:00
{
if ( ! fstfile ) return ;
std : : time_t t = std : : time ( nullptr ) ;
2022-03-11 09:01:59 -06:00
fstWriterSetVersion ( fstfile , worker - > date ? yosys_version_str : " Yosys " ) ;
if ( worker - > date )
fstWriterSetDate ( fstfile , asctime ( std : : localtime ( & t ) ) ) ;
else
fstWriterSetDate ( fstfile , " " ) ;
2022-02-28 11:22:39 -06:00
if ( ! worker - > timescale . empty ( ) )
fstWriterSetTimescaleFromString ( fstfile , worker - > timescale . c_str ( ) ) ;
fstWriterSetPackType ( fstfile , FST_WR_PT_FASTLZ ) ;
fstWriterSetRepackOnClose ( fstfile , 1 ) ;
2022-03-02 08:23:07 -06:00
worker - > top - > write_output_header (
[ this ] ( IdString name ) { fstWriterSetScope ( fstfile , FST_ST_VCD_MODULE , stringf ( " %s " , log_id ( name ) ) . c_str ( ) , nullptr ) ; } ,
[ this ] ( ) { fstWriterSetUpscope ( fstfile ) ; } ,
2022-12-21 07:33:20 -06:00
[ this , use_signal ] ( const char * name , int size , Wire * , int id , bool is_reg ) {
2022-03-02 09:02:13 -06:00
if ( ! use_signal . at ( id ) ) return ;
2022-12-21 07:33:20 -06:00
fstHandle fst_id = fstWriterCreateVar ( fstfile , is_reg ? FST_VT_VCD_REG : FST_VT_VCD_WIRE , FST_VD_IMPLICIT , size ,
2022-08-09 08:43:26 -05:00
name , 0 ) ;
2022-03-02 08:23:07 -06:00
mapping . emplace ( id , fst_id ) ;
}
) ;
2022-03-02 02:39:22 -06:00
2022-03-02 08:23:07 -06:00
for ( auto & d : worker - > output_data )
{
fstWriterEmitTimeChange ( fstfile , d . first ) ;
for ( auto & data : d . second )
{
2022-03-02 09:02:13 -06:00
if ( ! use_signal . at ( data . first ) ) continue ;
2022-03-02 08:23:07 -06:00
Const value = data . second ;
std : : stringstream ss ;
for ( int i = GetSize ( value ) - 1 ; i > = 0 ; i - - ) {
switch ( value [ i ] ) {
case State : : S0 : ss < < " 0 " ; break ;
case State : : S1 : ss < < " 1 " ; break ;
case State : : Sx : ss < < " x " ; break ;
default : ss < < " z " ;
}
}
fstWriterEmitValueChange ( fstfile , mapping [ data . first ] , ss . str ( ) . c_str ( ) ) ;
2022-02-28 11:22:39 -06:00
}
}
}
2022-03-02 02:39:22 -06:00
2022-02-28 11:22:39 -06:00
struct fstContext * fstfile = nullptr ;
std : : map < int , fstHandle > mapping ;
} ;
struct AIWWriter : public OutputWriter
{
AIWWriter ( SimWorker * worker , std : : string filename ) : OutputWriter ( worker ) {
aiwfile . open ( filename . c_str ( ) ) ;
}
virtual ~ AIWWriter ( )
{
aiwfile < < ' . ' < < ' \n ' ;
}
2022-03-02 09:02:13 -06:00
void write ( std : : map < int , bool > & ) override
2022-02-28 11:22:39 -06:00
{
if ( ! aiwfile . is_open ( ) ) return ;
2022-03-07 08:00:14 -06:00
if ( worker - > map_filename . empty ( ) )
log_cmd_error ( " For AIGER witness file map parameter is mandatory. \n " ) ;
2022-02-28 11:22:39 -06:00
std : : ifstream mf ( worker - > map_filename ) ;
std : : string type , symbol ;
int variable , index ;
2022-05-02 04:18:30 -05:00
int max_input = 0 ;
2022-03-07 08:00:14 -06:00
if ( mf . fail ( ) )
log_cmd_error ( " Not able to read AIGER witness map file. \n " ) ;
2022-02-28 11:22:39 -06:00
while ( mf > > type > > variable > > index > > symbol ) {
RTLIL : : IdString escaped_s = RTLIL : : escape_id ( symbol ) ;
Wire * w = worker - > top - > module - > wire ( escaped_s ) ;
if ( ! w )
2022-03-07 06:59:36 -06:00
log_error ( " Wire %s not present in module %s \n " , log_id ( escaped_s ) , log_id ( worker - > top - > module ) ) ;
2022-02-28 11:22:39 -06:00
if ( index < w - > start_offset | | index > w - > start_offset + w - > width )
log_error ( " Index %d for wire %s is out of range \n " , index , log_signal ( w ) ) ;
if ( type = = " input " ) {
2022-03-22 08:43:18 -05:00
aiw_inputs [ variable ] = SigBit ( w , index - w - > start_offset ) ;
2022-04-22 05:03:39 -05:00
if ( worker - > clock . count ( escaped_s ) ) {
clocks [ variable ] = true ;
}
if ( worker - > clockn . count ( escaped_s ) ) {
clocks [ variable ] = false ;
}
2022-05-02 04:18:30 -05:00
max_input = max ( max_input , variable ) ;
2022-02-28 11:22:39 -06:00
} else if ( type = = " init " ) {
2022-03-22 08:43:18 -05:00
aiw_inits [ variable ] = SigBit ( w , index - w - > start_offset ) ;
2022-05-02 04:18:30 -05:00
max_input = max ( max_input , variable ) ;
2022-02-28 11:22:39 -06:00
} else if ( type = = " latch " ) {
2022-03-22 08:43:18 -05:00
aiw_latches [ variable ] = { SigBit ( w , index - w - > start_offset ) , false } ;
2022-02-28 11:22:39 -06:00
} else if ( type = = " invlatch " ) {
2022-03-22 08:43:18 -05:00
aiw_latches [ variable ] = { SigBit ( w , index - w - > start_offset ) , true } ;
2022-02-28 11:22:39 -06:00
}
}
2022-03-02 08:23:07 -06:00
worker - > top - > write_output_header (
[ ] ( IdString ) { } ,
[ ] ( ) { } ,
2022-12-21 07:33:20 -06:00
[ this ] ( const char */ * name */ , int /*size*/ , Wire * wire , int id , bool ) { if ( wire ! = nullptr ) mapping [ wire ] = id ; }
2022-03-02 08:23:07 -06:00
) ;
2022-02-28 11:22:39 -06:00
2022-03-02 08:23:07 -06:00
std : : map < int , Yosys : : RTLIL : : Const > current ;
bool first = true ;
2022-04-22 06:46:11 -05:00
for ( auto iter = worker - > output_data . begin ( ) ; iter ! = std : : prev ( worker - > output_data . end ( ) ) ; + + iter )
2022-02-28 11:22:39 -06:00
{
2022-04-22 06:46:11 -05:00
auto & d = * iter ;
2022-03-02 08:23:07 -06:00
for ( auto & data : d . second )
{
current [ data . first ] = data . second ;
2022-02-28 11:22:39 -06:00
}
2022-03-02 08:23:07 -06:00
if ( first ) {
for ( int i = 0 ; ; i + + )
{
if ( aiw_latches . count ( i ) ) {
2022-04-22 05:04:05 -05:00
aiwfile < < ' 0 ' ;
2022-03-02 08:23:07 -06:00
continue ;
}
aiwfile < < ' \n ' ;
break ;
}
first = false ;
2022-02-28 11:22:39 -06:00
}
2022-03-02 08:23:07 -06:00
2022-04-22 05:03:39 -05:00
bool skip = false ;
for ( auto it : clocks )
{
auto val = it . second ? State : : S1 : State : : S0 ;
SigBit bit = aiw_inputs . at ( it . first ) ;
auto v = current [ mapping [ bit . wire ] ] . bits . at ( bit . offset ) ;
if ( v = = val )
skip = true ;
}
if ( skip )
continue ;
2022-05-02 04:18:30 -05:00
for ( int i = 0 ; i < = max_input ; i + + )
2022-03-02 08:23:07 -06:00
{
if ( aiw_inputs . count ( i ) ) {
SigBit bit = aiw_inputs . at ( i ) ;
auto v = current [ mapping [ bit . wire ] ] . bits . at ( bit . offset ) ;
if ( v = = State : : S1 )
aiwfile < < ' 1 ' ;
else
aiwfile < < ' 0 ' ;
continue ;
}
if ( aiw_inits . count ( i ) ) {
SigBit bit = aiw_inits . at ( i ) ;
auto v = current [ mapping [ bit . wire ] ] . bits . at ( bit . offset ) ;
if ( v = = State : : S1 )
aiwfile < < ' 1 ' ;
else
aiwfile < < ' 0 ' ;
continue ;
}
2022-05-02 04:18:30 -05:00
aiwfile < < ' 0 ' ;
2022-03-02 08:23:07 -06:00
}
2022-05-02 04:18:30 -05:00
aiwfile < < ' \n ' ;
2022-03-02 08:23:07 -06:00
}
2022-02-28 11:22:39 -06:00
}
std : : ofstream aiwfile ;
dict < int , std : : pair < SigBit , bool > > aiw_latches ;
dict < int , SigBit > aiw_inputs , aiw_inits ;
2022-04-22 05:03:39 -05:00
dict < int , bool > clocks ;
2022-03-02 08:23:07 -06:00
std : : map < Wire * , int > mapping ;
2022-02-28 11:22:39 -06:00
} ;
2017-08-16 06:05:21 -05:00
struct SimPass : public Pass {
SimPass ( ) : Pass ( " sim " , " simulate the circuit " ) { }
2020-06-18 18:34:52 -05:00
void help ( ) override
2017-08-16 06:05:21 -05:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " sim [options] [top-level] \n " ) ;
log ( " \n " ) ;
log ( " This command simulates the circuit using the given top-level module. \n " ) ;
log ( " \n " ) ;
log ( " -vcd <filename> \n " ) ;
log ( " write the simulation results to the given VCD file \n " ) ;
log ( " \n " ) ;
2022-01-26 02:26:19 -06:00
log ( " -fst <filename> \n " ) ;
log ( " write the simulation results to the given FST file \n " ) ;
log ( " \n " ) ;
2022-02-28 03:50:08 -06:00
log ( " -aiw <filename> \n " ) ;
log ( " write the simulation results to an AIGER witness file \n " ) ;
log ( " (requires a *.aim file via -map) \n " ) ;
log ( " \n " ) ;
2022-08-09 08:43:26 -05:00
log ( " -hdlname \n " ) ;
log ( " use the hdlname attribute when writing simulation results \n " ) ;
log ( " (preserves hierarchy in a flattened design) \n " ) ;
log ( " \n " ) ;
2022-03-02 09:02:13 -06:00
log ( " -x \n " ) ;
log ( " ignore constant x outputs in simulation file. \n " ) ;
log ( " \n " ) ;
2022-03-11 09:01:59 -06:00
log ( " -date \n " ) ;
log ( " include date and full version info in output. \n " ) ;
log ( " \n " ) ;
2017-08-17 05:27:08 -05:00
log ( " -clock <portname> \n " ) ;
log ( " name of top-level clock input \n " ) ;
log ( " \n " ) ;
log ( " -clockn <portname> \n " ) ;
log ( " name of top-level clock input (inverse polarity) \n " ) ;
log ( " \n " ) ;
2022-03-31 06:10:13 -05:00
log ( " -multiclock \n " ) ;
log ( " mark that witness file is multiclock. \n " ) ;
log ( " \n " ) ;
2017-08-17 05:27:08 -05:00
log ( " -reset <portname> \n " ) ;
log ( " name of top-level reset input (active high) \n " ) ;
log ( " \n " ) ;
log ( " -resetn <portname> \n " ) ;
log ( " name of top-level inverted reset input (active low) \n " ) ;
log ( " \n " ) ;
2017-08-18 05:54:17 -05:00
log ( " -rstlen <integer> \n " ) ;
log ( " number of cycles reset should stay active (default: 1) \n " ) ;
log ( " \n " ) ;
log ( " -zinit \n " ) ;
log ( " zero-initialize all uninitialized regs and memories \n " ) ;
log ( " \n " ) ;
2020-10-16 11:19:58 -05:00
log ( " -timescale <string> \n " ) ;
log ( " include the specified timescale declaration in the vcd \n " ) ;
log ( " \n " ) ;
2017-08-16 06:05:21 -05:00
log ( " -n <integer> \n " ) ;
2022-02-02 02:37:32 -06:00
log ( " number of clock cycles to simulate (default: 20) \n " ) ;
2017-08-17 05:27:08 -05:00
log ( " \n " ) ;
log ( " -a \n " ) ;
2022-02-02 02:37:32 -06:00
log ( " use all nets in VCD/FST operations, not just those with public names \n " ) ;
2017-08-17 05:27:08 -05:00
log ( " \n " ) ;
2017-08-17 08:54:51 -05:00
log ( " -w \n " ) ;
log ( " writeback mode: use final simulation state as new init state \n " ) ;
log ( " \n " ) ;
2022-12-21 07:44:15 -06:00
log ( " -r <filename> \n " ) ;
log ( " read simulation or formal results file \n " ) ;
log ( " File formats supported: FST, VCD, AIW, WIT and .yw \n " ) ;
2022-11-15 05:55:22 -06:00
log ( " VCD support requires vcd2fst external tool to be present \n " ) ;
2022-01-26 08:50:38 -06:00
log ( " \n " ) ;
2022-12-21 07:59:29 -06:00
log ( " -append <integer> \n " ) ;
log ( " number of extra clock cycles to simulate for a Yosys witness input \n " ) ;
log ( " \n " ) ;
2023-01-10 10:04:06 -06:00
log ( " -summary <filename> \n " ) ;
log ( " write a JSON summary to the given file \n " ) ;
log ( " \n " ) ;
2022-02-18 08:04:02 -06:00
log ( " -map <filename> \n " ) ;
log ( " read file with port and latch symbols, needed for AIGER witness input \n " ) ;
log ( " \n " ) ;
2022-03-11 08:36:23 -06:00
log ( " -scope <name> \n " ) ;
2022-01-26 08:50:38 -06:00
log ( " scope of simulation top model \n " ) ;
log ( " \n " ) ;
2022-02-02 02:37:32 -06:00
log ( " -at <time> \n " ) ;
log ( " sets start and stop time \n " ) ;
log ( " \n " ) ;
2022-01-28 03:18:02 -06:00
log ( " -start <time> \n " ) ;
log ( " start co-simulation in arbitary time (default 0) \n " ) ;
log ( " \n " ) ;
log ( " -stop <time> \n " ) ;
log ( " stop co-simulation in arbitary time (default END) \n " ) ;
log ( " \n " ) ;
2022-02-02 02:37:32 -06:00
log ( " -sim \n " ) ;
log ( " simulation with stimulus from FST (default) \n " ) ;
log ( " \n " ) ;
2022-01-28 03:18:02 -06:00
log ( " -sim-cmp \n " ) ;
2022-02-02 02:37:32 -06:00
log ( " co-simulation expect exact match \n " ) ;
2022-01-28 03:18:02 -06:00
log ( " \n " ) ;
log ( " -sim-gold \n " ) ;
log ( " co-simulation, x in simulation can match any value in FST \n " ) ;
log ( " \n " ) ;
log ( " -sim-gate \n " ) ;
log ( " co-simulation, x in FST can match any value in simulation \n " ) ;
log ( " \n " ) ;
2022-03-11 09:26:11 -06:00
log ( " -q \n " ) ;
log ( " disable per-cycle/sample log message \n " ) ;
log ( " \n " ) ;
2017-08-17 05:27:08 -05:00
log ( " -d \n " ) ;
log ( " enable debug output \n " ) ;
2017-08-16 06:05:21 -05:00
log ( " \n " ) ;
}
2022-03-07 06:59:36 -06:00
static std : : string file_base_name ( std : : string const & path )
{
return path . substr ( path . find_last_of ( " / \\ " ) + 1 ) ;
}
2020-06-18 18:34:52 -05:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
2017-08-16 06:05:21 -05:00
{
SimWorker worker ;
2017-08-17 05:27:08 -05:00
int numcycles = 20 ;
2022-12-21 07:59:29 -06:00
int append = 0 ;
2022-02-02 02:37:32 -06:00
bool start_set = false , stop_set = false , at_set = false ;
2017-08-16 06:05:21 -05:00
log_header ( design , " Executing SIM pass (simulate the circuit). \n " ) ;
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
if ( args [ argidx ] = = " -vcd " & & argidx + 1 < args . size ( ) ) {
2020-11-24 14:17:16 -06:00
std : : string vcd_filename = args [ + + argidx ] ;
rewrite_filename ( vcd_filename ) ;
2022-02-28 11:22:39 -06:00
worker . outputfiles . emplace_back ( std : : unique_ptr < VCDWriter > ( new VCDWriter ( & worker , vcd_filename . c_str ( ) ) ) ) ;
2017-08-16 06:05:21 -05:00
continue ;
}
2022-01-26 02:26:19 -06:00
if ( args [ argidx ] = = " -fst " & & argidx + 1 < args . size ( ) ) {
std : : string fst_filename = args [ + + argidx ] ;
rewrite_filename ( fst_filename ) ;
2022-02-28 11:22:39 -06:00
worker . outputfiles . emplace_back ( std : : unique_ptr < FSTWriter > ( new FSTWriter ( & worker , fst_filename . c_str ( ) ) ) ) ;
2022-01-26 02:26:19 -06:00
continue ;
}
2022-02-28 03:50:08 -06:00
if ( args [ argidx ] = = " -aiw " & & argidx + 1 < args . size ( ) ) {
std : : string aiw_filename = args [ + + argidx ] ;
rewrite_filename ( aiw_filename ) ;
2022-02-28 11:22:39 -06:00
worker . outputfiles . emplace_back ( std : : unique_ptr < AIWWriter > ( new AIWWriter ( & worker , aiw_filename . c_str ( ) ) ) ) ;
2022-02-28 03:50:08 -06:00
continue ;
}
2022-08-09 08:43:26 -05:00
if ( args [ argidx ] = = " -hdlname " ) {
worker . hdlname = true ;
continue ;
}
2017-08-16 06:05:21 -05:00
if ( args [ argidx ] = = " -n " & & argidx + 1 < args . size ( ) ) {
2017-08-17 05:27:08 -05:00
numcycles = atoi ( args [ + + argidx ] . c_str ( ) ) ;
2022-01-31 02:38:25 -06:00
worker . cycles_set = true ;
2017-08-17 05:27:08 -05:00
continue ;
}
2017-08-18 05:54:17 -05:00
if ( args [ argidx ] = = " -rstlen " & & argidx + 1 < args . size ( ) ) {
worker . rstlen = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2017-08-17 05:27:08 -05:00
if ( args [ argidx ] = = " -clock " & & argidx + 1 < args . size ( ) ) {
worker . clock . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
if ( args [ argidx ] = = " -clockn " & & argidx + 1 < args . size ( ) ) {
worker . clockn . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
if ( args [ argidx ] = = " -reset " & & argidx + 1 < args . size ( ) ) {
worker . reset . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
if ( args [ argidx ] = = " -resetn " & & argidx + 1 < args . size ( ) ) {
worker . resetn . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
2020-10-16 11:19:58 -05:00
if ( args [ argidx ] = = " -timescale " & & argidx + 1 < args . size ( ) ) {
worker . timescale = args [ + + argidx ] ;
continue ;
}
2017-08-17 05:27:08 -05:00
if ( args [ argidx ] = = " -a " ) {
worker . hide_internal = false ;
continue ;
}
2022-03-11 09:26:11 -06:00
if ( args [ argidx ] = = " -q " ) {
worker . verbose = false ;
continue ;
}
2017-08-17 05:27:08 -05:00
if ( args [ argidx ] = = " -d " ) {
worker . debug = true ;
2017-08-16 06:05:21 -05:00
continue ;
}
2017-08-17 08:54:51 -05:00
if ( args [ argidx ] = = " -w " ) {
worker . writeback = true ;
continue ;
}
2017-08-18 05:54:17 -05:00
if ( args [ argidx ] = = " -zinit " ) {
worker . zinit = true ;
continue ;
}
2022-01-26 08:50:38 -06:00
if ( args [ argidx ] = = " -r " & & argidx + 1 < args . size ( ) ) {
std : : string sim_filename = args [ + + argidx ] ;
rewrite_filename ( sim_filename ) ;
worker . sim_filename = sim_filename ;
continue ;
}
2022-12-21 07:59:29 -06:00
if ( args [ argidx ] = = " -append " & & argidx + 1 < args . size ( ) ) {
append = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2022-02-18 08:04:02 -06:00
if ( args [ argidx ] = = " -map " & & argidx + 1 < args . size ( ) ) {
std : : string map_filename = args [ + + argidx ] ;
rewrite_filename ( map_filename ) ;
worker . map_filename = map_filename ;
continue ;
}
2023-01-10 10:04:06 -06:00
if ( args [ argidx ] = = " -summary " & & argidx + 1 < args . size ( ) ) {
std : : string summary_filename = args [ + + argidx ] ;
rewrite_filename ( summary_filename ) ;
worker . summary_filename = summary_filename ;
continue ;
}
2022-01-26 08:50:38 -06:00
if ( args [ argidx ] = = " -scope " & & argidx + 1 < args . size ( ) ) {
worker . scope = args [ + + argidx ] ;
continue ;
}
2022-01-28 03:18:02 -06:00
if ( args [ argidx ] = = " -start " & & argidx + 1 < args . size ( ) ) {
worker . start_time = stringToTime ( args [ + + argidx ] ) ;
2022-02-02 02:37:32 -06:00
start_set = true ;
2022-01-28 03:18:02 -06:00
continue ;
}
if ( args [ argidx ] = = " -stop " & & argidx + 1 < args . size ( ) ) {
worker . stop_time = stringToTime ( args [ + + argidx ] ) ;
2022-02-02 02:37:32 -06:00
stop_set = true ;
continue ;
}
if ( args [ argidx ] = = " -at " & & argidx + 1 < args . size ( ) ) {
worker . start_time = stringToTime ( args [ + + argidx ] ) ;
worker . stop_time = worker . start_time ;
at_set = true ;
continue ;
}
if ( args [ argidx ] = = " -sim " ) {
worker . sim_mode = SimulationMode : : sim ;
2022-01-28 03:18:02 -06:00
continue ;
}
if ( args [ argidx ] = = " -sim-cmp " ) {
worker . sim_mode = SimulationMode : : cmp ;
continue ;
}
if ( args [ argidx ] = = " -sim-gold " ) {
worker . sim_mode = SimulationMode : : gold ;
continue ;
}
if ( args [ argidx ] = = " -sim-gate " ) {
worker . sim_mode = SimulationMode : : gate ;
continue ;
}
2022-03-02 09:02:13 -06:00
if ( args [ argidx ] = = " -x " ) {
worker . ignore_x = true ;
continue ;
}
2022-03-11 09:01:59 -06:00
if ( args [ argidx ] = = " -date " ) {
worker . date = true ;
continue ;
}
2022-03-31 06:10:13 -05:00
if ( args [ argidx ] = = " -multiclock " ) {
worker . multiclock = true ;
continue ;
}
2017-08-16 06:05:21 -05:00
break ;
}
extra_args ( args , argidx , design ) ;
2022-02-02 02:37:32 -06:00
if ( at_set & & ( start_set | | stop_set | | worker . cycles_set ) )
log_error ( " 'at' option can only be defined separate of 'start','stop' and 'n' \n " ) ;
if ( stop_set & & worker . cycles_set )
log_error ( " 'stop' and 'n' can only be used exclusively' \n " ) ;
2017-08-16 06:05:21 -05:00
Module * top_mod = nullptr ;
if ( design - > full_selection ( ) ) {
top_mod = design - > top_module ( ) ;
2019-06-05 16:16:24 -05:00
if ( ! top_mod )
log_cmd_error ( " Design has no top module, use the 'hierarchy' command to specify one. \n " ) ;
2017-08-16 06:05:21 -05:00
} else {
auto mods = design - > selected_whole_modules ( ) ;
if ( GetSize ( mods ) ! = 1 )
log_cmd_error ( " Only one top module must be selected. \n " ) ;
top_mod = mods . front ( ) ;
}
2022-01-26 08:50:38 -06:00
if ( worker . sim_filename . empty ( ) )
worker . run ( top_mod , numcycles ) ;
2022-03-07 06:59:36 -06:00
else {
std : : string filename_trim = file_base_name ( worker . sim_filename ) ;
2022-03-11 08:21:36 -06:00
if ( filename_trim . size ( ) > 4 & & ( ( filename_trim . compare ( filename_trim . size ( ) - 4 , std : : string : : npos , " .fst " ) = = 0 ) | |
filename_trim . compare ( filename_trim . size ( ) - 4 , std : : string : : npos , " .vcd " ) = = 0 ) ) {
2022-03-07 06:59:36 -06:00
worker . run_cosim_fst ( top_mod , numcycles ) ;
} else if ( filename_trim . size ( ) > 4 & & filename_trim . compare ( filename_trim . size ( ) - 4 , std : : string : : npos , " .aiw " ) = = 0 ) {
if ( worker . map_filename . empty ( ) )
log_cmd_error ( " For AIGER witness file map parameter is mandatory. \n " ) ;
worker . run_cosim_aiger_witness ( top_mod ) ;
} else if ( filename_trim . size ( ) > 4 & & filename_trim . compare ( filename_trim . size ( ) - 4 , std : : string : : npos , " .wit " ) = = 0 ) {
worker . run_cosim_btor2_witness ( top_mod ) ;
2022-12-21 07:44:15 -06:00
} else if ( filename_trim . size ( ) > 3 & & filename_trim . compare ( filename_trim . size ( ) - 3 , std : : string : : npos , " .yw " ) = = 0 ) {
2022-12-21 07:59:29 -06:00
worker . run_cosim_yw_witness ( top_mod , append ) ;
2022-03-07 06:59:36 -06:00
} else {
log_cmd_error ( " Unhandled extension for simulation input file `%s`. \n " , worker . sim_filename . c_str ( ) ) ;
}
}
2023-01-10 10:04:06 -06:00
worker . write_summary ( ) ;
2017-08-16 06:05:21 -05:00
}
} SimPass ;
2022-03-14 13:06:29 -05:00
struct Fst2TbPass : public Pass {
Fst2TbPass ( ) : Pass ( " fst2tb " , " generate testbench out of fst file " ) { }
void help ( ) override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
log ( " fst2tb [options] [top-level] \n " ) ;
log ( " \n " ) ;
2022-08-23 17:28:27 -05:00
log ( " This command generates testbench for the circuit using the given top-level \n " ) ;
log ( " module and simulus signal from FST file \n " ) ;
2022-03-14 13:06:29 -05:00
log ( " \n " ) ;
log ( " -tb <name> \n " ) ;
log ( " generated testbench name. \n " ) ;
log ( " files <name>.v and <name>.txt are created as result. \n " ) ;
log ( " \n " ) ;
log ( " -r <filename> \n " ) ;
log ( " read simulation FST file \n " ) ;
log ( " \n " ) ;
log ( " -clock <portname> \n " ) ;
log ( " name of top-level clock input \n " ) ;
log ( " \n " ) ;
log ( " -clockn <portname> \n " ) ;
log ( " name of top-level clock input (inverse polarity) \n " ) ;
log ( " \n " ) ;
log ( " -scope <name> \n " ) ;
log ( " scope of simulation top model \n " ) ;
log ( " \n " ) ;
log ( " -start <time> \n " ) ;
log ( " start co-simulation in arbitary time (default 0) \n " ) ;
log ( " \n " ) ;
log ( " -stop <time> \n " ) ;
log ( " stop co-simulation in arbitary time (default END) \n " ) ;
log ( " \n " ) ;
log ( " -n <integer> \n " ) ;
log ( " number of clock cycles to simulate (default: 20) \n " ) ;
log ( " \n " ) ;
}
void execute ( std : : vector < std : : string > args , RTLIL : : Design * design ) override
{
SimWorker worker ;
int numcycles = 20 ;
bool stop_set = false ;
std : : string tb_filename ;
log_header ( design , " Executing FST2FB pass. \n " ) ;
size_t argidx ;
for ( argidx = 1 ; argidx < args . size ( ) ; argidx + + ) {
if ( args [ argidx ] = = " -clock " & & argidx + 1 < args . size ( ) ) {
worker . clock . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
if ( args [ argidx ] = = " -clockn " & & argidx + 1 < args . size ( ) ) {
worker . clockn . insert ( RTLIL : : escape_id ( args [ + + argidx ] ) ) ;
continue ;
}
if ( args [ argidx ] = = " -r " & & argidx + 1 < args . size ( ) ) {
std : : string sim_filename = args [ + + argidx ] ;
rewrite_filename ( sim_filename ) ;
worker . sim_filename = sim_filename ;
continue ;
}
if ( args [ argidx ] = = " -n " & & argidx + 1 < args . size ( ) ) {
numcycles = atoi ( args [ + + argidx ] . c_str ( ) ) ;
worker . cycles_set = true ;
continue ;
}
if ( args [ argidx ] = = " -scope " & & argidx + 1 < args . size ( ) ) {
worker . scope = args [ + + argidx ] ;
continue ;
}
if ( args [ argidx ] = = " -start " & & argidx + 1 < args . size ( ) ) {
worker . start_time = stringToTime ( args [ + + argidx ] ) ;
continue ;
}
if ( args [ argidx ] = = " -stop " & & argidx + 1 < args . size ( ) ) {
worker . stop_time = stringToTime ( args [ + + argidx ] ) ;
stop_set = true ;
continue ;
}
if ( args [ argidx ] = = " -tb " & & argidx + 1 < args . size ( ) ) {
tb_filename = args [ + + argidx ] ;
continue ;
}
break ;
}
extra_args ( args , argidx , design ) ;
if ( stop_set & & worker . cycles_set )
log_error ( " 'stop' and 'n' can only be used exclusively' \n " ) ;
Module * top_mod = nullptr ;
if ( design - > full_selection ( ) ) {
top_mod = design - > top_module ( ) ;
if ( ! top_mod )
log_cmd_error ( " Design has no top module, use the 'hierarchy' command to specify one. \n " ) ;
} else {
auto mods = design - > selected_whole_modules ( ) ;
if ( GetSize ( mods ) ! = 1 )
log_cmd_error ( " Only one top module must be selected. \n " ) ;
top_mod = mods . front ( ) ;
}
if ( tb_filename . empty ( ) )
log_cmd_error ( " Testbench name must be defined. \n " ) ;
if ( worker . sim_filename . empty ( ) )
log_cmd_error ( " Stimulus FST file must be defined. \n " ) ;
worker . generate_tb ( top_mod , tb_filename , numcycles ) ;
}
} Fst2TbPass ;
2017-08-16 06:05:21 -05:00
PRIVATE_NAMESPACE_END