2014-07-29 15:05:00 -05:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2014 Claire Xenia Wolf < claire @ yosyshq . com >
2014-07-29 15:05:00 -05:00
* Copyright ( C ) 2014 Johann Glaser < Johann . Glaser @ gmx . at >
*
* 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 .
*
*/
2014-07-30 08:59:38 -05:00
# include "kernel/yosys.h"
2014-09-02 10:28:13 -05:00
# include "kernel/satgen.h"
2014-08-31 11:08:42 -05:00
# include "kernel/consteval.h"
2016-07-24 06:59:57 -05:00
# include "kernel/celledges.h"
2014-09-06 08:47:46 -05:00
# include "kernel/macc.h"
2024-07-29 03:26:02 -05:00
# include "kernel/cost.h"
2014-07-30 08:59:38 -05:00
# include <algorithm>
2014-07-29 15:05:00 -05:00
2014-09-27 09:17:53 -05:00
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2024-07-29 03:26:02 -05:00
static int bloat_factor = 1 ;
2014-08-16 12:44:31 -05:00
static uint32_t xorshift32_state = 123456789 ;
2014-07-29 15:05:00 -05:00
static uint32_t xorshift32 ( uint32_t limit ) {
2014-08-16 12:44:31 -05:00
xorshift32_state ^ = xorshift32_state < < 13 ;
xorshift32_state ^ = xorshift32_state > > 17 ;
xorshift32_state ^ = xorshift32_state < < 5 ;
return xorshift32_state % limit ;
2014-07-29 15:05:00 -05:00
}
2024-07-29 03:26:02 -05:00
static RTLIL : : Cell * create_gold_module ( RTLIL : : Design * design , RTLIL : : IdString cell_type , std : : string cell_type_flags , bool constmode , bool muxdiv )
2014-07-29 15:05:00 -05:00
{
2020-04-02 11:51:32 -05:00
RTLIL : : Module * module = design - > addModule ( ID ( gold ) ) ;
RTLIL : : Cell * cell = module - > addCell ( ID ( UUT ) , cell_type ) ;
2014-08-31 10:06:36 -05:00
RTLIL : : Wire * wire ;
2020-04-02 11:51:32 -05:00
if ( cell_type . in ( ID ( $ mux ) , ID ( $ pmux ) ) )
2016-07-24 10:21:53 -05:00
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2020-04-02 11:51:32 -05:00
int swidth = cell_type = = ID ( $ mux ) ? 1 : 1 + xorshift32 ( 8 ) ;
2016-07-24 10:21:53 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : A ) ;
2016-07-24 10:21:53 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , wire ) ;
2016-07-24 10:21:53 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : B ) ;
2016-07-24 10:21:53 -05:00
wire - > width = width * swidth ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : B , wire ) ;
2016-07-24 10:21:53 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : S ) ;
2016-07-24 10:21:53 -05:00
wire - > width = swidth ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : S , wire ) ;
2016-07-24 10:21:53 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2016-07-24 10:21:53 -05:00
wire - > width = width ;
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2016-07-24 10:21:53 -05:00
}
2022-01-24 09:02:29 -06:00
if ( cell_type = = ID ( $ bmux ) )
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
int swidth = 1 + xorshift32 ( 4 * bloat_factor ) ;
2022-01-24 09:02:29 -06:00
wire = module - > addWire ( ID : : A ) ;
wire - > width = width < < swidth ;
wire - > port_input = true ;
cell - > setPort ( ID : : A , wire ) ;
wire = module - > addWire ( ID : : S ) ;
wire - > width = swidth ;
wire - > port_input = true ;
cell - > setPort ( ID : : S , wire ) ;
wire = module - > addWire ( ID : : Y ) ;
wire - > width = width ;
wire - > port_output = true ;
cell - > setPort ( ID : : Y , wire ) ;
}
if ( cell_type = = ID ( $ demux ) )
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
int swidth = 1 + xorshift32 ( 6 * bloat_factor ) ;
2022-01-24 09:02:29 -06:00
wire = module - > addWire ( ID : : A ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( ID : : A , wire ) ;
wire = module - > addWire ( ID : : S ) ;
wire - > width = swidth ;
wire - > port_input = true ;
cell - > setPort ( ID : : S , wire ) ;
wire = module - > addWire ( ID : : Y ) ;
wire - > width = width < < swidth ;
wire - > port_output = true ;
cell - > setPort ( ID : : Y , wire ) ;
}
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ fa ) )
2014-09-08 05:15:39 -05:00
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-09-08 05:15:39 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : A ) ;
2014-09-08 05:15:39 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , wire ) ;
2014-09-08 05:15:39 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : B ) ;
2014-09-08 05:15:39 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : B , wire ) ;
2014-09-08 05:15:39 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : C ) ;
2014-09-08 05:15:39 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : C , wire ) ;
2014-09-08 05:15:39 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : X ) ;
2014-09-08 05:15:39 -05:00
wire - > width = width ;
wire - > port_output = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : X , wire ) ;
2014-09-08 05:15:39 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2014-09-08 05:15:39 -05:00
wire - > width = width ;
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-09-08 05:15:39 -05:00
}
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ lcu ) )
2014-09-08 06:28:23 -05:00
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-09-08 06:28:23 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : P ) ;
2014-09-08 06:28:23 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : P , wire ) ;
2014-09-08 06:28:23 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : G ) ;
2014-09-08 06:28:23 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : G , wire ) ;
2014-09-08 06:28:23 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : CI ) ;
2014-09-08 06:28:23 -05:00
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CI , wire ) ;
2014-09-08 06:28:23 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : CO ) ;
2014-09-08 06:28:23 -05:00
wire - > width = width ;
wire - > port_output = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CO , wire ) ;
2014-09-08 06:28:23 -05:00
}
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ macc ) )
2014-09-06 08:47:46 -05:00
{
Macc macc ;
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-09-06 08:47:46 -05:00
int depth = 1 + xorshift32 ( 6 ) ;
2014-09-06 12:44:11 -05:00
int mulbits_a = 0 , mulbits_b = 0 ;
2014-09-06 08:47:46 -05:00
2020-03-12 14:57:01 -05:00
RTLIL : : Wire * wire_a = module - > addWire ( ID : : A ) ;
2014-09-06 08:47:46 -05:00
wire_a - > width = 0 ;
wire_a - > port_input = true ;
for ( int i = 0 ; i < depth ; i + + )
{
int size_a = xorshift32 ( width ) + 1 ;
2014-09-07 10:05:41 -05:00
int size_b = depth > 4 ? 0 : xorshift32 ( width ) + 1 ;
2014-09-06 08:47:46 -05:00
2014-09-06 12:44:11 -05:00
if ( mulbits_a + size_a * size_b < = 96 & & mulbits_b + size_a + size_b < = 16 & & xorshift32 ( 2 ) = = 1 ) {
mulbits_a + = size_a * size_b ;
mulbits_b + = size_a + size_b ;
} else
2014-09-06 08:47:46 -05:00
size_b = 0 ;
Macc : : port_t this_port ;
wire_a - > width + = size_a ;
this_port . in_a = RTLIL : : SigSpec ( wire_a , wire_a - > width - size_a , size_a ) ;
wire_a - > width + = size_b ;
this_port . in_b = RTLIL : : SigSpec ( wire_a , wire_a - > width - size_b , size_b ) ;
this_port . is_signed = xorshift32 ( 2 ) = = 1 ;
this_port . do_subtract = xorshift32 ( 2 ) = = 1 ;
macc . ports . push_back ( this_port ) ;
}
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : B ) ;
2014-09-07 10:05:41 -05:00
wire - > width = xorshift32 ( mulbits_a ? xorshift32 ( 4 ) + 1 : xorshift32 ( 16 ) + 1 ) ;
2014-09-06 08:47:46 -05:00
wire - > port_input = true ;
macc . bit_ports = wire ;
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2014-09-06 08:47:46 -05:00
wire - > width = width ;
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-09-06 08:47:46 -05:00
macc . to_cell ( cell ) ;
}
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ lut ) )
2014-08-31 10:06:36 -05:00
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 6 * bloat_factor ) ;
2014-08-31 10:06:36 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : A ) ;
2014-08-31 10:06:36 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , wire ) ;
2014-08-31 10:06:36 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2014-08-31 10:06:36 -05:00
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-08-31 10:06:36 -05:00
RTLIL : : SigSpec config ;
for ( int i = 0 ; i < ( 1 < < width ) ; i + + )
2019-08-07 13:12:38 -05:00
config . append ( xorshift32 ( 2 ) ? State : : S1 : State : : S0 ) ;
2014-08-31 10:06:36 -05:00
2020-04-02 11:51:32 -05:00
cell - > setParam ( ID : : LUT , config . as_const ( ) ) ;
2014-08-31 10:06:36 -05:00
}
2014-07-29 15:05:00 -05:00
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ sop ) )
2016-06-17 09:31:16 -05:00
{
2024-07-29 03:26:02 -05:00
int width = 1 + xorshift32 ( 8 * bloat_factor ) ;
int depth = 1 + xorshift32 ( 8 * bloat_factor ) ;
2016-06-17 09:31:16 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : A ) ;
2016-06-17 09:31:16 -05:00
wire - > width = width ;
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , wire ) ;
2016-06-17 09:31:16 -05:00
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2016-06-17 09:31:16 -05:00
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2016-06-17 09:31:16 -05:00
RTLIL : : SigSpec config ;
for ( int i = 0 ; i < width * depth ; i + + )
switch ( xorshift32 ( 3 ) ) {
case 0 :
2019-08-07 13:12:38 -05:00
config . append ( State : : S1 ) ;
config . append ( State : : S0 ) ;
2016-06-17 09:31:16 -05:00
break ;
case 1 :
2019-08-07 13:12:38 -05:00
config . append ( State : : S0 ) ;
config . append ( State : : S1 ) ;
2016-06-17 09:31:16 -05:00
break ;
case 2 :
2019-08-07 13:12:38 -05:00
config . append ( State : : S0 ) ;
config . append ( State : : S0 ) ;
2016-06-17 09:31:16 -05:00
break ;
}
2020-04-02 11:51:32 -05:00
cell - > setParam ( ID : : DEPTH , depth ) ;
cell - > setParam ( ID : : TABLE , config . as_const ( ) ) ;
2016-06-17 09:31:16 -05:00
}
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' A ' ) ! = std : : string : : npos ) {
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : A ) ;
2024-07-29 03:26:02 -05:00
wire - > width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-07-29 15:05:00 -05:00
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , wire ) ;
2014-07-29 15:05:00 -05:00
}
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos ) {
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : B ) ;
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' h ' ) ! = std : : string : : npos )
2024-07-29 03:26:02 -05:00
wire - > width = 1 + xorshift32 ( 6 * bloat_factor ) ;
2014-07-29 15:05:00 -05:00
else
2024-07-29 03:26:02 -05:00
wire - > width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-07-29 15:05:00 -05:00
wire - > port_input = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : B , wire ) ;
2014-07-29 15:05:00 -05:00
}
if ( cell_type_flags . find ( ' S ' ) ! = std : : string : : npos & & xorshift32 ( 2 ) ) {
if ( cell_type_flags . find ( ' A ' ) ! = std : : string : : npos )
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_SIGNED ] = true ;
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos )
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : B_SIGNED ] = true ;
2014-07-29 15:05:00 -05:00
}
if ( cell_type_flags . find ( ' s ' ) ! = std : : string : : npos ) {
if ( cell_type_flags . find ( ' A ' ) ! = std : : string : : npos & & xorshift32 ( 2 ) )
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_SIGNED ] = true ;
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos & & xorshift32 ( 2 ) )
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : B_SIGNED ] = true ;
2014-07-29 15:05:00 -05:00
}
if ( cell_type_flags . find ( ' Y ' ) ! = std : : string : : npos ) {
2020-03-12 14:57:01 -05:00
wire = module - > addWire ( ID : : Y ) ;
2024-07-29 03:26:02 -05:00
wire - > width = 1 + xorshift32 ( 8 * bloat_factor ) ;
2014-07-29 15:05:00 -05:00
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-29 15:05:00 -05:00
}
2020-07-03 06:13:21 -05:00
if ( cell_type . in ( ID ( $ shiftx ) ) ) {
cell - > parameters [ ID : : A_SIGNED ] = false ;
}
2020-06-28 14:30:16 -05:00
if ( cell_type . in ( ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) ) ) {
cell - > parameters [ ID : : B_SIGNED ] = false ;
}
2020-04-21 05:51:58 -05:00
if ( muxdiv & & cell_type . in ( ID ( $ div ) , ID ( $ mod ) , ID ( $ divfloor ) , ID ( $ modfloor ) ) ) {
2020-03-12 14:57:01 -05:00
auto b_not_zero = module - > ReduceBool ( NEW_ID , cell - > getPort ( ID : : B ) ) ;
auto div_out = module - > addWire ( NEW_ID , GetSize ( cell - > getPort ( ID : : Y ) ) ) ;
module - > addMux ( NEW_ID , RTLIL : : SigSpec ( 0 , GetSize ( div_out ) ) , div_out , b_not_zero , cell - > getPort ( ID : : Y ) ) ;
cell - > setPort ( ID : : Y , div_out ) ;
2014-12-25 12:22:39 -06:00
}
2020-04-02 11:51:32 -05:00
if ( cell_type = = ID ( $ alu ) )
2014-09-01 09:36:04 -05:00
{
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : CI ) ;
2014-09-01 09:36:04 -05:00
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CI , wire ) ;
2014-09-01 09:36:04 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : BI ) ;
2014-09-01 09:36:04 -05:00
wire - > port_input = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : BI , wire ) ;
2014-09-01 09:36:04 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : X ) ;
2020-03-12 14:57:01 -05:00
wire - > width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2014-09-01 09:36:04 -05:00
wire - > port_output = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : X , wire ) ;
2014-09-01 09:36:04 -05:00
2020-04-02 11:51:32 -05:00
wire = module - > addWire ( ID : : CO ) ;
2020-03-12 14:57:01 -05:00
wire - > width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2014-09-01 09:36:04 -05:00
wire - > port_output = true ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CO , wire ) ;
2014-09-01 09:36:04 -05:00
}
2014-09-08 04:12:39 -05:00
if ( constmode )
{
auto conn_list = cell - > connections ( ) ;
for ( auto & conn : conn_list )
{
RTLIL : : SigSpec sig = conn . second ;
2014-10-10 09:59:44 -05:00
if ( GetSize ( sig ) = = 0 | | sig [ 0 ] . wire = = nullptr | | sig [ 0 ] . wire - > port_output )
2014-09-08 04:12:39 -05:00
continue ;
int n , m ;
switch ( xorshift32 ( 5 ) )
{
case 0 :
2014-10-10 09:59:44 -05:00
n = xorshift32 ( GetSize ( sig ) + 1 ) ;
2014-09-08 04:12:39 -05:00
for ( int i = 0 ; i < n ; i + + )
2019-08-07 13:12:38 -05:00
sig [ i ] = xorshift32 ( 2 ) = = 1 ? State : : S1 : State : : S0 ;
2014-09-08 04:12:39 -05:00
break ;
case 1 :
2014-10-10 09:59:44 -05:00
n = xorshift32 ( GetSize ( sig ) + 1 ) ;
for ( int i = n ; i < GetSize ( sig ) ; i + + )
2019-08-07 13:12:38 -05:00
sig [ i ] = xorshift32 ( 2 ) = = 1 ? State : : S1 : State : : S0 ;
2014-09-08 04:12:39 -05:00
break ;
case 2 :
2014-10-10 09:59:44 -05:00
n = xorshift32 ( GetSize ( sig ) ) ;
m = xorshift32 ( GetSize ( sig ) ) ;
2015-10-25 13:30:49 -05:00
for ( int i = min ( n , m ) ; i < max ( n , m ) ; i + + )
2019-08-07 13:12:38 -05:00
sig [ i ] = xorshift32 ( 2 ) = = 1 ? State : : S1 : State : : S0 ;
2014-09-08 04:12:39 -05:00
break ;
}
cell - > setPort ( conn . first , sig ) ;
}
}
2014-07-29 15:05:00 -05:00
module - > fixup_ports ( ) ;
cell - > fixup_parameters ( ) ;
cell - > check ( ) ;
2024-07-29 03:26:02 -05:00
return cell ;
2014-07-29 15:05:00 -05:00
}
2016-07-24 06:59:57 -05:00
static void run_edges_test ( RTLIL : : Design * design , bool verbose )
{
Module * module = * design - > modules ( ) . begin ( ) ;
Cell * cell = * module - > cells ( ) . begin ( ) ;
ezSatPtr ezptr ;
ezSAT & ez = * ezptr . get ( ) ;
SigMap sigmap ( module ) ;
SatGen satgen ( & ez , & sigmap ) ;
FwdCellEdgesDatabase edges_db ( sigmap ) ;
2016-07-25 09:39:25 -05:00
if ( ! edges_db . add_edges_from_cell ( cell ) )
2016-07-24 10:21:53 -05:00
log_error ( " Creating edge database failed for this cell! \n " ) ;
2016-07-24 06:59:57 -05:00
dict < SigBit , pool < SigBit > > satgen_db ;
satgen . setContext ( & sigmap , " X: " ) ;
satgen . importCell ( cell ) ;
satgen . setContext ( & sigmap , " Y: " ) ;
satgen . importCell ( cell ) ;
vector < tuple < SigBit , int , int > > input_db , output_db ;
for ( auto & conn : cell - > connections ( ) )
{
SigSpec bits = sigmap ( conn . second ) ;
satgen . setContext ( & sigmap , " X: " ) ;
std : : vector < int > xbits = satgen . importSigSpec ( bits ) ;
satgen . setContext ( & sigmap , " Y: " ) ;
std : : vector < int > ybits = satgen . importSigSpec ( bits ) ;
for ( int i = 0 ; i < GetSize ( bits ) ; i + + )
if ( cell - > input ( conn . first ) )
input_db . emplace_back ( bits [ i ] , xbits [ i ] , ybits [ i ] ) ;
else
output_db . emplace_back ( bits [ i ] , xbits [ i ] , ybits [ i ] ) ;
}
if ( verbose )
log ( " \n SAT solving for all edges: \n " ) ;
for ( int i = 0 ; i < GetSize ( input_db ) ; i + + )
{
SigBit inbit = std : : get < 0 > ( input_db [ i ] ) ;
if ( verbose )
log ( " Testing input signal %s: \n " , log_signal ( inbit ) ) ;
vector < int > xinbits , yinbits ;
for ( int k = 0 ; k < GetSize ( input_db ) ; k + + )
if ( k ! = i ) {
xinbits . push_back ( std : : get < 1 > ( input_db [ k ] ) ) ;
yinbits . push_back ( std : : get < 2 > ( input_db [ k ] ) ) ;
}
int xyinbit_ok = ez . vec_eq ( xinbits , yinbits ) ;
for ( int k = 0 ; k < GetSize ( output_db ) ; k + + )
{
SigBit outbit = std : : get < 0 > ( output_db [ k ] ) ;
int xoutbit = std : : get < 1 > ( output_db [ k ] ) ;
int youtbit = std : : get < 2 > ( output_db [ k ] ) ;
bool is_edge = ez . solve ( xyinbit_ok , ez . XOR ( xoutbit , youtbit ) ) ;
if ( is_edge )
satgen_db [ inbit ] . insert ( outbit ) ;
if ( verbose ) {
bool is_ref_edge = edges_db . db . count ( inbit ) & & edges_db . db . at ( inbit ) . count ( outbit ) ;
log ( " %c %s %s \n " , is_edge ? ' x ' : ' o ' , log_signal ( outbit ) , is_edge = = is_ref_edge ? " OK " : " ERROR " ) ;
}
}
}
if ( satgen_db = = edges_db . db )
log ( " PASS. \n " ) ;
else
log_error ( " SAT-based edge table does not match the database! \n " ) ;
}
2014-09-07 10:05:41 -05:00
static void run_eval_test ( RTLIL : : Design * design , bool verbose , bool nosat , std : : string uut_name , std : : ofstream & vlog_file )
2014-08-31 11:08:42 -05:00
{
2014-09-02 10:28:13 -05:00
log ( " Eval testing:%c " , verbose ? ' \n ' : ' ' ) ;
2020-04-02 11:51:32 -05:00
RTLIL : : Module * gold_mod = design - > module ( ID ( gold ) ) ;
RTLIL : : Module * gate_mod = design - > module ( ID ( gate ) ) ;
2014-08-31 11:08:42 -05:00
ConstEval gold_ce ( gold_mod ) , gate_ce ( gate_mod ) ;
2015-02-21 05:15:41 -06:00
ezSatPtr ez1 , ez2 ;
2014-09-02 10:28:13 -05:00
SigMap sigmap ( gold_mod ) ;
2015-02-21 05:15:41 -06:00
SatGen satgen1 ( ez1 . get ( ) , & sigmap ) ;
SatGen satgen2 ( ez2 . get ( ) , & sigmap ) ;
2014-09-02 10:28:13 -05:00
satgen2 . model_undef = true ;
2014-09-07 10:05:41 -05:00
if ( ! nosat )
for ( auto cell : gold_mod - > cells ( ) ) {
satgen1 . importCell ( cell ) ;
satgen2 . importCell ( cell ) ;
}
2014-08-31 11:08:42 -05:00
2014-09-02 15:49:43 -05:00
if ( vlog_file . is_open ( ) )
{
vlog_file < < stringf ( " \n module %s; \n " , uut_name . c_str ( ) ) ;
for ( auto port : gold_mod - > ports ) {
RTLIL : : Wire * wire = gold_mod - > wire ( port ) ;
if ( wire - > port_input )
2014-10-10 09:59:44 -05:00
vlog_file < < stringf ( " reg [%d:0] %s; \n " , GetSize ( wire ) - 1 , log_id ( wire ) ) ;
2014-09-02 15:49:43 -05:00
else
2014-10-10 09:59:44 -05:00
vlog_file < < stringf ( " wire [%d:0] %s_expr, %s_noexpr; \n " , GetSize ( wire ) - 1 , log_id ( wire ) , log_id ( wire ) ) ;
2014-09-02 15:49:43 -05:00
}
vlog_file < < stringf ( " %s_expr uut_expr( " , uut_name . c_str ( ) ) ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( gold_mod - > ports ) ; i + + )
2014-09-02 15:49:43 -05:00
vlog_file < < stringf ( " %s.%s(%s%s) " , i ? " , " : " " , log_id ( gold_mod - > ports [ i ] ) , log_id ( gold_mod - > ports [ i ] ) ,
gold_mod - > wire ( gold_mod - > ports [ i ] ) - > port_input ? " " : " _expr " ) ;
vlog_file < < stringf ( " ); \n " ) ;
vlog_file < < stringf ( " %s_expr uut_noexpr( " , uut_name . c_str ( ) ) ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( gold_mod - > ports ) ; i + + )
2014-09-02 15:49:43 -05:00
vlog_file < < stringf ( " %s.%s(%s%s) " , i ? " , " : " " , log_id ( gold_mod - > ports [ i ] ) , log_id ( gold_mod - > ports [ i ] ) ,
gold_mod - > wire ( gold_mod - > ports [ i ] ) - > port_input ? " " : " _noexpr " ) ;
vlog_file < < stringf ( " ); \n " ) ;
vlog_file < < stringf ( " task run; \n " ) ;
vlog_file < < stringf ( " begin \n " ) ;
vlog_file < < stringf ( " $display( \" %s \" ); \n " , uut_name . c_str ( ) ) ;
}
2014-08-31 11:08:42 -05:00
for ( int i = 0 ; i < 64 ; i + + )
{
2014-09-01 08:37:21 -05:00
log ( verbose ? " \n " : " . " ) ;
2014-08-31 11:08:42 -05:00
gold_ce . clear ( ) ;
gate_ce . clear ( ) ;
2014-09-02 10:28:13 -05:00
RTLIL : : SigSpec in_sig , in_val ;
RTLIL : : SigSpec out_sig , out_val ;
2014-09-02 16:21:15 -05:00
std : : string vlog_pattern_info ;
2014-09-02 10:28:13 -05:00
2014-08-31 11:08:42 -05:00
for ( auto port : gold_mod - > ports )
{
RTLIL : : Wire * gold_wire = gold_mod - > wire ( port ) ;
RTLIL : : Wire * gate_wire = gate_mod - > wire ( port ) ;
log_assert ( gold_wire ! = nullptr ) ;
log_assert ( gate_wire ! = nullptr ) ;
log_assert ( gold_wire - > port_input = = gate_wire - > port_input ) ;
2014-10-10 09:59:44 -05:00
log_assert ( GetSize ( gold_wire ) = = GetSize ( gate_wire ) ) ;
2014-08-31 11:08:42 -05:00
if ( ! gold_wire - > port_input )
continue ;
RTLIL : : Const in_value ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( gold_wire ) ; i + + )
2024-10-09 12:39:45 -05:00
in_value . bits ( ) . push_back ( xorshift32 ( 2 ) ? State : : S1 : State : : S0 ) ;
2014-08-31 11:08:42 -05:00
if ( xorshift32 ( 4 ) = = 0 ) {
int inv_chance = 1 + xorshift32 ( 8 ) ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( gold_wire ) ; i + + )
2014-08-31 11:08:42 -05:00
if ( xorshift32 ( inv_chance ) = = 0 )
2024-10-09 12:39:45 -05:00
in_value . bits ( ) [ i ] = RTLIL : : Sx ;
2014-08-31 11:08:42 -05:00
}
2014-09-01 08:37:21 -05:00
if ( verbose )
log ( " %s: %s \n " , log_id ( gold_wire ) , log_signal ( in_value ) ) ;
2014-08-31 11:08:42 -05:00
2014-09-02 10:28:13 -05:00
in_sig . append ( gold_wire ) ;
in_val . append ( in_value ) ;
2014-08-31 11:08:42 -05:00
gold_ce . set ( gold_wire , in_value ) ;
gate_ce . set ( gate_wire , in_value ) ;
2014-09-02 15:49:43 -05:00
2014-10-10 09:59:44 -05:00
if ( vlog_file . is_open ( ) & & GetSize ( in_value ) > 0 ) {
2014-09-02 15:49:43 -05:00
vlog_file < < stringf ( " %s = 'b%s; \n " , log_id ( gold_wire ) , in_value . as_string ( ) . c_str ( ) ) ;
2014-09-02 16:21:15 -05:00
if ( ! vlog_pattern_info . empty ( ) )
vlog_pattern_info + = " " ;
vlog_pattern_info + = stringf ( " %s=%s " , log_id ( gold_wire ) , log_signal ( in_value ) ) ;
}
2014-08-31 11:08:42 -05:00
}
2014-09-02 15:49:43 -05:00
if ( vlog_file . is_open ( ) )
vlog_file < < stringf ( " #1; \n " ) ;
2014-08-31 11:08:42 -05:00
for ( auto port : gold_mod - > ports )
{
RTLIL : : Wire * gold_wire = gold_mod - > wire ( port ) ;
RTLIL : : Wire * gate_wire = gate_mod - > wire ( port ) ;
log_assert ( gold_wire ! = nullptr ) ;
log_assert ( gate_wire ! = nullptr ) ;
log_assert ( gold_wire - > port_output = = gate_wire - > port_output ) ;
2014-10-10 09:59:44 -05:00
log_assert ( GetSize ( gold_wire ) = = GetSize ( gate_wire ) ) ;
2014-08-31 11:08:42 -05:00
if ( ! gold_wire - > port_output )
continue ;
RTLIL : : SigSpec gold_outval ( gold_wire ) ;
RTLIL : : SigSpec gate_outval ( gate_wire ) ;
if ( ! gold_ce . eval ( gold_outval ) )
log_error ( " Failed to eval %s in gold module. \n " , log_id ( gold_wire ) ) ;
if ( ! gate_ce . eval ( gate_outval ) )
log_error ( " Failed to eval %s in gate module. \n " , log_id ( gate_wire ) ) ;
bool gold_gate_mismatch = false ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( gold_wire ) ; i + + ) {
2014-08-31 11:08:42 -05:00
if ( gold_outval [ i ] = = RTLIL : : Sx )
continue ;
if ( gold_outval [ i ] = = gate_outval [ i ] )
continue ;
gold_gate_mismatch = true ;
break ;
}
if ( gold_gate_mismatch )
log_error ( " Mismatch in output %s: gold:%s != gate:%s \n " , log_id ( gate_wire ) , log_signal ( gold_outval ) , log_signal ( gate_outval ) ) ;
2014-09-01 08:37:21 -05:00
if ( verbose )
log ( " %s: %s \n " , log_id ( gold_wire ) , log_signal ( gold_outval ) ) ;
2014-09-02 10:28:13 -05:00
out_sig . append ( gold_wire ) ;
out_val . append ( gold_outval ) ;
2014-09-02 15:49:43 -05:00
if ( vlog_file . is_open ( ) ) {
2014-09-02 16:21:15 -05:00
vlog_file < < stringf ( " $display( \" [%s] %s expected: %%b, expr: %%b, noexpr: %%b \" , %d'b%s, %s_expr, %s_noexpr); \n " ,
2014-10-10 09:59:44 -05:00
vlog_pattern_info . c_str ( ) , log_id ( gold_wire ) , GetSize ( gold_outval ) , gold_outval . as_string ( ) . c_str ( ) , log_id ( gold_wire ) , log_id ( gold_wire ) ) ;
vlog_file < < stringf ( " if (%s_expr !== %d'b%s) begin $display( \" ERROR \" ); $finish; end \n " , log_id ( gold_wire ) , GetSize ( gold_outval ) , gold_outval . as_string ( ) . c_str ( ) ) ;
vlog_file < < stringf ( " if (%s_noexpr !== %d'b%s) begin $display( \" ERROR \" ); $finish; end \n " , log_id ( gold_wire ) , GetSize ( gold_outval ) , gold_outval . as_string ( ) . c_str ( ) ) ;
2014-09-02 15:49:43 -05:00
}
2014-09-02 10:28:13 -05:00
}
if ( verbose )
log ( " EVAL: %s \n " , out_val . as_string ( ) . c_str ( ) ) ;
2014-09-07 10:05:41 -05:00
if ( ! nosat )
{
std : : vector < int > sat1_in_sig = satgen1 . importSigSpec ( in_sig ) ;
std : : vector < int > sat1_in_val = satgen1 . importSigSpec ( in_val ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < int > sat1_model = satgen1 . importSigSpec ( out_sig ) ;
std : : vector < bool > sat1_model_value ;
2014-09-02 10:28:13 -05:00
2015-02-21 05:15:41 -06:00
if ( ! ez1 - > solve ( sat1_model , sat1_model_value , ez1 - > vec_eq ( sat1_in_sig , sat1_in_val ) ) )
2014-09-07 10:05:41 -05:00
log_error ( " Evaluating sat model 1 (no undef modeling) failed! \n " ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
if ( verbose ) {
log ( " SAT 1: " ) ;
2014-10-10 09:59:44 -05:00
for ( int i = GetSize ( out_sig ) - 1 ; i > = 0 ; i - - )
2014-09-07 10:05:41 -05:00
log ( " %c " , sat1_model_value . at ( i ) ? ' 1 ' : ' 0 ' ) ;
log ( " \n " ) ;
}
2014-09-02 10:28:13 -05:00
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( out_sig ) ; i + + ) {
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] ! = State : : S0 & & out_val [ i ] ! = State : : S1 )
2014-09-07 10:05:41 -05:00
continue ;
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] = = State : : S0 & & sat1_model_value . at ( i ) = = false )
2014-09-07 10:05:41 -05:00
continue ;
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] = = State : : S1 & & sat1_model_value . at ( i ) = = true )
2014-09-07 10:05:41 -05:00
continue ;
log_error ( " Mismatch in sat model 1 (no undef modeling) output! \n " ) ;
}
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < int > sat2_in_def_sig = satgen2 . importDefSigSpec ( in_sig ) ;
std : : vector < int > sat2_in_def_val = satgen2 . importDefSigSpec ( in_val ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < int > sat2_in_undef_sig = satgen2 . importUndefSigSpec ( in_sig ) ;
std : : vector < int > sat2_in_undef_val = satgen2 . importUndefSigSpec ( in_val ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < int > sat2_model_def_sig = satgen2 . importDefSigSpec ( out_sig ) ;
std : : vector < int > sat2_model_undef_sig = satgen2 . importUndefSigSpec ( out_sig ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < int > sat2_model ;
sat2_model . insert ( sat2_model . end ( ) , sat2_model_def_sig . begin ( ) , sat2_model_def_sig . end ( ) ) ;
sat2_model . insert ( sat2_model . end ( ) , sat2_model_undef_sig . begin ( ) , sat2_model_undef_sig . end ( ) ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
std : : vector < bool > sat2_model_value ;
2014-09-02 10:28:13 -05:00
2015-02-21 05:15:41 -06:00
if ( ! ez2 - > solve ( sat2_model , sat2_model_value , ez2 - > vec_eq ( sat2_in_def_sig , sat2_in_def_val ) , ez2 - > vec_eq ( sat2_in_undef_sig , sat2_in_undef_val ) ) )
2014-09-07 10:05:41 -05:00
log_error ( " Evaluating sat model 2 (undef modeling) failed! \n " ) ;
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
if ( verbose ) {
log ( " SAT 2: " ) ;
2014-10-10 09:59:44 -05:00
for ( int i = GetSize ( out_sig ) - 1 ; i > = 0 ; i - - )
log ( " %c " , sat2_model_value . at ( GetSize ( out_sig ) + i ) ? ' x ' : sat2_model_value . at ( i ) ? ' 1 ' : ' 0 ' ) ;
2014-09-07 10:05:41 -05:00
log ( " \n " ) ;
}
2014-09-02 10:28:13 -05:00
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( out_sig ) ; i + + ) {
if ( sat2_model_value . at ( GetSize ( out_sig ) + i ) ) {
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] ! = State : : S0 & & out_val [ i ] ! = State : : S1 )
2014-09-07 10:05:41 -05:00
continue ;
} else {
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] = = State : : S0 & & sat2_model_value . at ( i ) = = false )
2014-09-07 10:05:41 -05:00
continue ;
2019-08-07 13:12:38 -05:00
if ( out_val [ i ] = = State : : S1 & & sat2_model_value . at ( i ) = = true )
2014-09-07 10:05:41 -05:00
continue ;
}
log_error ( " Mismatch in sat model 2 (undef modeling) output! \n " ) ;
2014-09-02 10:28:13 -05:00
}
2014-08-31 11:08:42 -05:00
}
}
2014-09-02 15:49:43 -05:00
if ( vlog_file . is_open ( ) ) {
vlog_file < < stringf ( " end \n " ) ;
vlog_file < < stringf ( " endtask \n " ) ;
vlog_file < < stringf ( " endmodule \n " ) ;
}
2014-09-01 08:37:21 -05:00
if ( ! verbose )
log ( " ok. \n " ) ;
2014-08-31 11:08:42 -05:00
}
2014-07-29 15:05:00 -05:00
struct TestCellPass : public Pass {
TestCellPass ( ) : Pass ( " test_cell " , " automatically test the implementation of a cell type " ) { }
2020-06-18 18:34:52 -05:00
void help ( ) override
2014-07-29 15:05:00 -05:00
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log ( " \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " test_cell [options] {cell-types} \n " ) ;
2014-07-29 15:05:00 -05:00
log ( " \n " ) ;
2014-09-08 06:28:23 -05:00
log ( " Tests the internal implementation of the given cell type (for example '$add') \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " by comparing SAT solver, EVAL and TECHMAP implementations of the cell types.. \n " ) ;
2014-07-29 15:05:00 -05:00
log ( " \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " Run with 'all' instead of a cell type to run the test on all supported \n " ) ;
2014-12-25 10:04:13 -06:00
log ( " cell types. Use for example 'all /$add' for all cell types except $add. \n " ) ;
2014-07-29 15:05:00 -05:00
log ( " \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " -n {integer} \n " ) ;
log ( " create this number of cell instances and test them (default = 100). \n " ) ;
log ( " \n " ) ;
2014-08-16 12:44:31 -05:00
log ( " -s {positive_integer} \n " ) ;
log ( " use this value as rng seed value (default = unix time). \n " ) ;
log ( " \n " ) ;
2020-08-26 12:29:32 -05:00
log ( " -f {rtlil_file} \n " ) ;
log ( " don't generate circuits. instead load the specified RTLIL file. \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " \n " ) ;
2014-12-25 10:04:13 -06:00
log ( " -w {filename_prefix} \n " ) ;
log ( " don't test anything. just generate the circuits and write them \n " ) ;
2020-08-26 12:29:32 -05:00
log ( " to RTLIL files with the specified prefix \n " ) ;
2014-12-25 10:04:13 -06:00
log ( " \n " ) ;
2014-07-30 08:59:38 -05:00
log ( " -map {filename} \n " ) ;
log ( " pass this option to techmap. \n " ) ;
log ( " \n " ) ;
2014-10-18 10:52:06 -05:00
log ( " -simlib \n " ) ;
2016-06-17 09:31:16 -05:00
log ( " use \" techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc \" \n " ) ;
2014-09-01 08:37:21 -05:00
log ( " \n " ) ;
2015-06-10 00:24:26 -05:00
log ( " -aigmap \n " ) ;
log ( " instead of calling \" techmap \" , call \" aigmap \" \n " ) ;
2015-06-10 00:16:30 -05:00
log ( " \n " ) ;
2014-12-25 12:22:39 -06:00
log ( " -muxdiv \n " ) ;
log ( " when creating test benches with dividers, create an additional mux \n " ) ;
log ( " to mask out the division-by-zero case \n " ) ;
log ( " \n " ) ;
2014-09-06 04:46:07 -05:00
log ( " -script {script_file} \n " ) ;
log ( " instead of calling \" techmap \" , call \" script {script_file} \" . \n " ) ;
log ( " \n " ) ;
2014-09-08 04:12:39 -05:00
log ( " -const \n " ) ;
log ( " set some input bits to random constant values \n " ) ;
log ( " \n " ) ;
2014-09-07 10:05:41 -05:00
log ( " -nosat \n " ) ;
log ( " do not check SAT model or run SAT equivalence checking \n " ) ;
log ( " \n " ) ;
2015-09-25 10:27:18 -05:00
log ( " -noeval \n " ) ;
log ( " do not check const-eval models \n " ) ;
log ( " \n " ) ;
2024-07-29 03:26:02 -05:00
log ( " -noopt \n " ) ;
log ( " do not opt tecchmapped design \n " ) ;
log ( " \n " ) ;
2016-07-24 06:59:57 -05:00
log ( " -edges \n " ) ;
log ( " test cell edges db creator against sat-based implementation \n " ) ;
log ( " \n " ) ;
2014-09-01 08:37:21 -05:00
log ( " -v \n " ) ;
log ( " print additional debug information to the console \n " ) ;
log ( " \n " ) ;
2014-09-02 15:49:43 -05:00
log ( " -vlog {filename} \n " ) ;
2015-08-14 04:27:19 -05:00
log ( " create a Verilog test bench to test simlib and write_verilog \n " ) ;
2024-07-29 03:26:02 -05:00
log ( " -bloat {factor} \n " ) ;
log ( " increase cell size limits b{factor} times where possible \n " ) ;
log ( " -check_cost \n " ) ;
log ( " check if the estimated cell cost is a valid upper bound for \n " ) ;
log ( " the techmapped cell count \n " ) ;
2014-09-02 15:49:43 -05:00
log ( " \n " ) ;
2014-07-29 15:05:00 -05:00
}
2020-06-18 18:34:52 -05:00
void execute ( std : : vector < std : : string > args , RTLIL : : Design * ) override
2014-07-29 15:05:00 -05:00
{
2014-07-30 08:59:38 -05:00
int num_iter = 100 ;
2014-07-30 19:21:41 -05:00
std : : string techmap_cmd = " techmap -assert " ;
2020-08-26 12:29:32 -05:00
std : : string rtlil_file , write_prefix ;
2014-08-16 12:44:31 -05:00
xorshift32_state = 0 ;
2014-09-02 15:49:43 -05:00
std : : ofstream vlog_file ;
2014-12-25 12:22:39 -06:00
bool muxdiv = false ;
2014-09-01 08:37:21 -05:00
bool verbose = false ;
2014-09-08 04:12:39 -05:00
bool constmode = false ;
2014-09-07 10:05:41 -05:00
bool nosat = false ;
2015-09-25 10:27:18 -05:00
bool noeval = false ;
2024-07-29 03:26:02 -05:00
bool noopt = false ;
2016-07-24 06:59:57 -05:00
bool edges = false ;
2024-07-29 03:26:02 -05:00
bool check_cost = false ;
2014-07-30 08:59:38 -05:00
int argidx ;
2014-10-10 09:59:44 -05:00
for ( argidx = 1 ; argidx < GetSize ( args ) ; argidx + + )
2014-07-30 08:59:38 -05:00
{
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -n " & & argidx + 1 < GetSize ( args ) ) {
2019-08-07 13:09:17 -05:00
num_iter = atoi ( args [ + + argidx ] . c_str ( ) ) ;
2014-07-30 08:59:38 -05:00
continue ;
}
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -s " & & argidx + 1 < GetSize ( args ) ) {
2019-08-07 13:09:17 -05:00
xorshift32_state = atoi ( args [ + + argidx ] . c_str ( ) ) ;
2014-08-16 12:44:31 -05:00
continue ;
}
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -map " & & argidx + 1 < GetSize ( args ) ) {
2014-07-30 08:59:38 -05:00
techmap_cmd + = " -map " + args [ + + argidx ] ;
continue ;
}
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -f " & & argidx + 1 < GetSize ( args ) ) {
2020-08-26 12:29:32 -05:00
rtlil_file = args [ + + argidx ] ;
2014-07-30 08:59:38 -05:00
num_iter = 1 ;
continue ;
}
2014-12-25 10:04:13 -06:00
if ( args [ argidx ] = = " -w " & & argidx + 1 < GetSize ( args ) ) {
write_prefix = args [ + + argidx ] ;
continue ;
}
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -script " & & argidx + 1 < GetSize ( args ) ) {
2014-09-06 04:46:07 -05:00
techmap_cmd = " script " + args [ + + argidx ] ;
continue ;
}
2014-09-01 08:37:21 -05:00
if ( args [ argidx ] = = " -simlib " ) {
2016-06-17 09:31:16 -05:00
techmap_cmd = " techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc " ;
2014-09-01 08:37:21 -05:00
continue ;
}
2015-06-10 00:24:26 -05:00
if ( args [ argidx ] = = " -aigmap " ) {
techmap_cmd = " aigmap " ;
2015-06-10 00:16:30 -05:00
continue ;
}
2014-12-25 12:22:39 -06:00
if ( args [ argidx ] = = " -muxdiv " ) {
muxdiv = true ;
continue ;
}
2014-09-08 04:12:39 -05:00
if ( args [ argidx ] = = " -const " ) {
constmode = true ;
continue ;
}
2014-09-07 10:05:41 -05:00
if ( args [ argidx ] = = " -nosat " ) {
nosat = true ;
continue ;
}
2015-09-25 10:27:18 -05:00
if ( args [ argidx ] = = " -noeval " ) {
noeval = true ;
continue ;
}
2024-07-29 03:26:02 -05:00
if ( args [ argidx ] = = " -noopt " ) {
noopt = true ;
continue ;
}
2016-07-24 06:59:57 -05:00
if ( args [ argidx ] = = " -edges " ) {
edges = true ;
continue ;
}
2014-09-01 08:37:21 -05:00
if ( args [ argidx ] = = " -v " ) {
verbose = true ;
continue ;
}
2014-10-10 09:59:44 -05:00
if ( args [ argidx ] = = " -vlog " & & argidx + 1 < GetSize ( args ) ) {
2014-09-02 15:49:43 -05:00
vlog_file . open ( args [ + + argidx ] , std : : ios_base : : trunc ) ;
if ( ! vlog_file . is_open ( ) )
log_cmd_error ( " Failed to open output file `%s'. \n " , args [ argidx ] . c_str ( ) ) ;
continue ;
}
2024-07-29 03:26:02 -05:00
if ( args [ argidx ] = = " -bloat " & & argidx + 1 < GetSize ( args ) ) {
bloat_factor = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
if ( args [ argidx ] = = " -check_cost " ) {
check_cost = true ;
continue ;
}
2014-07-30 08:59:38 -05:00
break ;
}
2014-07-29 15:05:00 -05:00
2014-09-06 08:47:46 -05:00
if ( xorshift32_state = = 0 ) {
xorshift32_state = time ( NULL ) & 0x7fffffff ;
log ( " Rng seed value: %d \n " , int ( xorshift32_state ) ) ;
}
2014-08-16 12:44:31 -05:00
2020-04-02 11:51:32 -05:00
std : : map < IdString , std : : string > cell_types ;
std : : vector < IdString > selected_cell_types ;
cell_types [ ID ( $ not ) ] = " ASY " ;
cell_types [ ID ( $ pos ) ] = " ASY " ;
cell_types [ ID ( $ neg ) ] = " ASY " ;
cell_types [ ID ( $ and ) ] = " ABSY " ;
cell_types [ ID ( $ or ) ] = " ABSY " ;
cell_types [ ID ( $ xor ) ] = " ABSY " ;
cell_types [ ID ( $ xnor ) ] = " ABSY " ;
cell_types [ ID ( $ reduce_and ) ] = " ASY " ;
cell_types [ ID ( $ reduce_or ) ] = " ASY " ;
cell_types [ ID ( $ reduce_xor ) ] = " ASY " ;
cell_types [ ID ( $ reduce_xnor ) ] = " ASY " ;
cell_types [ ID ( $ reduce_bool ) ] = " ASY " ;
cell_types [ ID ( $ shl ) ] = " ABshY " ;
cell_types [ ID ( $ shr ) ] = " ABshY " ;
cell_types [ ID ( $ sshl ) ] = " ABshY " ;
cell_types [ ID ( $ sshr ) ] = " ABshY " ;
cell_types [ ID ( $ shift ) ] = " ABshY " ;
cell_types [ ID ( $ shiftx ) ] = " ABshY " ;
cell_types [ ID ( $ lt ) ] = " ABSY " ;
cell_types [ ID ( $ le ) ] = " ABSY " ;
cell_types [ ID ( $ eq ) ] = " ABSY " ;
cell_types [ ID ( $ ne ) ] = " ABSY " ;
// cell_types[ID($eqx)] = "ABSY";
// cell_types[ID($nex)] = "ABSY";
cell_types [ ID ( $ ge ) ] = " ABSY " ;
cell_types [ ID ( $ gt ) ] = " ABSY " ;
cell_types [ ID ( $ add ) ] = " ABSY " ;
cell_types [ ID ( $ sub ) ] = " ABSY " ;
cell_types [ ID ( $ mul ) ] = " ABSY " ;
cell_types [ ID ( $ div ) ] = " ABSY " ;
cell_types [ ID ( $ mod ) ] = " ABSY " ;
2020-04-21 05:51:58 -05:00
cell_types [ ID ( $ divfloor ) ] = " ABSY " ;
2020-04-08 12:30:47 -05:00
cell_types [ ID ( $ modfloor ) ] = " ABSY " ;
2020-04-02 11:51:32 -05:00
// cell_types[ID($pow)] = "ABsY";
cell_types [ ID ( $ logic_not ) ] = " ASY " ;
cell_types [ ID ( $ logic_and ) ] = " ABSY " ;
cell_types [ ID ( $ logic_or ) ] = " ABSY " ;
2014-07-29 15:05:00 -05:00
2022-01-24 09:02:29 -06:00
cell_types [ ID ( $ mux ) ] = " * " ;
cell_types [ ID ( $ bmux ) ] = " * " ;
cell_types [ ID ( $ demux ) ] = " * " ;
2016-07-24 10:21:53 -05:00
if ( edges ) {
2020-04-02 11:51:32 -05:00
cell_types [ ID ( $ pmux ) ] = " * " ;
2016-07-24 10:21:53 -05:00
}
2020-04-02 11:51:32 -05:00
// cell_types[ID($slice)] = "A";
// cell_types[ID($concat)] = "A";
2014-07-29 15:05:00 -05:00
2020-04-02 11:51:32 -05:00
cell_types [ ID ( $ lut ) ] = " * " ;
cell_types [ ID ( $ sop ) ] = " * " ;
cell_types [ ID ( $ alu ) ] = " ABSY " ;
cell_types [ ID ( $ lcu ) ] = " * " ;
cell_types [ ID ( $ macc ) ] = " * " ;
cell_types [ ID ( $ fa ) ] = " * " ;
2014-08-31 10:06:36 -05:00
2014-10-10 09:59:44 -05:00
for ( ; argidx < GetSize ( args ) ; argidx + + )
2014-07-30 08:59:38 -05:00
{
if ( args [ argidx ] . rfind ( " - " , 0 ) = = 0 )
log_cmd_error ( " Unexpected option: %s \n " , args [ argidx ] . c_str ( ) ) ;
if ( args [ argidx ] = = " all " ) {
for ( auto & it : cell_types )
if ( std : : count ( selected_cell_types . begin ( ) , selected_cell_types . end ( ) , it . first ) = = 0 )
selected_cell_types . push_back ( it . first ) ;
continue ;
}
2014-07-29 15:05:00 -05:00
2019-08-07 14:20:08 -05:00
if ( args [ argidx ] . compare ( 0 , 1 , " / " ) = = 0 ) {
2020-04-02 11:51:32 -05:00
std : : vector < IdString > new_selected_cell_types ;
2014-12-25 10:04:13 -06:00
for ( auto it : selected_cell_types )
if ( it ! = args [ argidx ] . substr ( 1 ) )
new_selected_cell_types . push_back ( it ) ;
new_selected_cell_types . swap ( selected_cell_types ) ;
continue ;
}
2014-07-30 08:59:38 -05:00
if ( cell_types . count ( args [ argidx ] ) = = 0 ) {
std : : string cell_type_list ;
int charcount = 100 ;
for ( auto & it : cell_types ) {
if ( charcount > 60 ) {
2020-04-02 11:51:32 -05:00
cell_type_list + = stringf ( " \n %s " , + log_id ( it . first ) ) ;
2014-07-30 08:59:38 -05:00
charcount = 0 ;
} else
2020-04-02 11:51:32 -05:00
cell_type_list + = stringf ( " %s " , log_id ( it . first ) ) ;
2014-10-10 09:59:44 -05:00
charcount + = GetSize ( it . first ) ;
2014-07-30 08:59:38 -05:00
}
log_cmd_error ( " The cell type `%s' is currently not supported. Try one of these:%s \n " ,
args [ argidx ] . c_str ( ) , cell_type_list . c_str ( ) ) ;
2014-07-29 15:05:00 -05:00
}
2014-07-30 08:59:38 -05:00
if ( std : : count ( selected_cell_types . begin ( ) , selected_cell_types . end ( ) , args [ argidx ] ) = = 0 )
selected_cell_types . push_back ( args [ argidx ] ) ;
2014-07-29 15:05:00 -05:00
}
2020-08-26 12:29:32 -05:00
if ( ! rtlil_file . empty ( ) ) {
2014-07-30 08:59:38 -05:00
if ( ! selected_cell_types . empty ( ) )
log_cmd_error ( " Do not specify any cell types when using -f. \n " ) ;
2020-08-26 12:29:32 -05:00
selected_cell_types . push_back ( ID ( rtlil ) ) ;
2014-07-29 15:05:00 -05:00
}
2014-07-30 08:59:38 -05:00
if ( selected_cell_types . empty ( ) )
log_cmd_error ( " No cell type to test specified. \n " ) ;
2014-09-03 06:43:37 -05:00
std : : vector < std : : string > uut_names ;
2014-09-02 15:49:43 -05:00
2024-07-29 03:26:02 -05:00
for ( auto cell_type : selected_cell_types ) {
// Cells that failed cell cost check
int failed = 0 ;
// How much bigger is the worst offender than estimated?
int worst_abs = 0 ;
// How many times is it bigger than estimated?
float worst_rel = 0.0 ;
2014-07-30 08:59:38 -05:00
for ( int i = 0 ; i < num_iter ; i + + )
{
2024-07-29 03:26:02 -05:00
Cell * uut = nullptr ;
2014-07-30 08:59:38 -05:00
RTLIL : : Design * design = new RTLIL : : Design ;
2020-08-26 12:29:32 -05:00
if ( cell_type = = ID ( rtlil ) )
Frontend : : frontend_call ( design , NULL , std : : string ( ) , " rtlil " + rtlil_file ) ;
2014-07-30 08:59:38 -05:00
else
2024-07-29 03:26:02 -05:00
uut = create_gold_module ( design , cell_type , cell_types . at ( cell_type ) , constmode , muxdiv ) ;
2014-12-25 10:04:13 -06:00
if ( ! write_prefix . empty ( ) ) {
2020-08-26 12:29:32 -05:00
Pass : : call ( design , stringf ( " write_rtlil %s_%s_%05d.il " , write_prefix . c_str ( ) , cell_type . c_str ( ) + 1 , i ) ) ;
2016-07-24 06:59:57 -05:00
} else if ( edges ) {
Pass : : call ( design , " dump gold " ) ;
run_edges_test ( design , verbose ) ;
2014-12-25 10:04:13 -06:00
} else {
2024-07-29 03:26:02 -05:00
Pass : : call ( design , stringf ( " copy gold gate; cd gate; %s; cd .. " , techmap_cmd . c_str ( ) ) ) ;
if ( ! noopt )
Pass : : call ( design , " opt -fast gate " ) ;
2014-12-25 10:04:13 -06:00
if ( ! nosat )
Pass : : call ( design , " miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter " ) ;
if ( verbose )
Pass : : call ( design , " dump gate " ) ;
Pass : : call ( design , " dump gold " ) ;
if ( ! nosat )
Pass : : call ( design , " sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter " ) ;
std : : string uut_name = stringf ( " uut_%s_%d " , cell_type . substr ( 1 ) . c_str ( ) , i ) ;
if ( vlog_file . is_open ( ) ) {
Pass : : call ( design , stringf ( " copy gold %s_expr; select %s_expr " , uut_name . c_str ( ) , uut_name . c_str ( ) ) ) ;
Backend : : backend_call ( design , & vlog_file , " <test_cell -vlog> " , " verilog -selected " ) ;
Pass : : call ( design , stringf ( " copy gold %s_noexpr; select %s_noexpr " , uut_name . c_str ( ) , uut_name . c_str ( ) ) ) ;
Backend : : backend_call ( design , & vlog_file , " <test_cell -vlog> " , " verilog -selected -noexpr " ) ;
uut_names . push_back ( uut_name ) ;
}
2015-09-25 10:27:18 -05:00
if ( ! noeval )
run_eval_test ( design , verbose , nosat , uut_name , vlog_file ) ;
2024-07-29 03:26:02 -05:00
if ( check_cost & & uut ) {
Pass : : call ( design , " select gate " ) ;
int num_cells = 0 ;
for ( auto mod : design - > selected_modules ( ) ) {
// Expected to run once
for ( auto cell : mod - > selected_cells ( ) ) {
( void ) cell ;
num_cells + + ;
}
}
CellCosts costs ( design ) ;
Pass : : call ( design , " select gold " ) ;
for ( auto mod : design - > selected_modules ( ) ) {
log_assert ( mod - > name . str ( ) = = " \\ gold " ) ;
// Expected to run once
int num_cells_estimate = costs . get ( uut ) ;
if ( num_cells < = num_cells_estimate ) {
log_debug ( " Correct upper bound for %s: %d <= %d \n " , cell_type . c_str ( ) , num_cells , num_cells_estimate ) ;
} else {
failed + + ;
if ( worst_abs < num_cells - num_cells_estimate ) {
worst_abs = num_cells - num_cells_estimate ;
worst_rel = ( float ) ( num_cells - num_cells_estimate ) / ( float ) num_cells_estimate ;
}
log_warning ( " Upper bound violated for %s: %d > %d \n " , cell_type . c_str ( ) , num_cells , num_cells_estimate ) ;
}
}
}
2014-09-02 15:49:43 -05:00
}
2014-07-30 08:59:38 -05:00
delete design ;
}
2024-07-29 03:26:02 -05:00
if ( check_cost & & failed ) {
log_warning ( " Cell type %s cost underestimated in %.1f%% cases "
" with worst offender being by %d (%.1f%%) \n " ,
cell_type . c_str ( ) , 100 * ( float ) failed / ( float ) num_iter ,
worst_abs , 100 * worst_rel ) ;
}
}
2014-09-02 15:49:43 -05:00
if ( vlog_file . is_open ( ) ) {
vlog_file < < " \n module testbench; \n " ;
2014-09-03 06:43:37 -05:00
for ( auto & uut : uut_names )
vlog_file < < stringf ( " %s %s (); \n " , uut . c_str ( ) , uut . c_str ( ) ) ;
2014-09-02 15:49:43 -05:00
vlog_file < < " initial begin \n " ;
2014-09-03 06:43:37 -05:00
for ( auto & uut : uut_names )
vlog_file < < " " < < uut < < " .run; \n " ;
2014-09-02 15:49:43 -05:00
vlog_file < < " end \n " ;
vlog_file < < " endmodule \n " ;
}
2014-07-29 15:05:00 -05:00
}
} TestCellPass ;
2014-09-27 09:17:53 -05:00
PRIVATE_NAMESPACE_END