2014-07-29 15:05:00 -05:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2014 Clifford Wolf < clifford @ clifford . at >
* 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"
2014-09-06 08:47:46 -05:00
# include "kernel/macc.h"
2014-07-30 08:59:38 -05:00
# include <algorithm>
2014-07-29 15:05:00 -05:00
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
}
2014-09-08 04:12:39 -05:00
static void create_gold_module ( RTLIL : : Design * design , RTLIL : : IdString cell_type , std : : string cell_type_flags , bool constmode )
2014-07-29 15:05:00 -05:00
{
RTLIL : : Module * module = design - > addModule ( " \\ gold " ) ;
RTLIL : : Cell * cell = module - > addCell ( " \\ UUT " , cell_type ) ;
2014-08-31 10:06:36 -05:00
RTLIL : : Wire * wire ;
2014-09-08 05:15:39 -05:00
if ( cell_type = = " $fa " )
{
int width = 1 + xorshift32 ( 8 ) ;
wire = module - > addWire ( " \\ A " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ A " , wire ) ;
wire = module - > addWire ( " \\ B " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ B " , wire ) ;
wire = module - > addWire ( " \\ C " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ C " , wire ) ;
wire = module - > addWire ( " \\ X " ) ;
wire - > width = width ;
wire - > port_output = true ;
cell - > setPort ( " \\ X " , wire ) ;
wire = module - > addWire ( " \\ Y " ) ;
wire - > width = width ;
wire - > port_output = true ;
cell - > setPort ( " \\ Y " , wire ) ;
}
2014-09-08 06:28:23 -05:00
if ( cell_type = = " $lcu " )
{
int width = 1 + xorshift32 ( 8 ) ;
wire = module - > addWire ( " \\ P " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ P " , wire ) ;
wire = module - > addWire ( " \\ G " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ G " , wire ) ;
wire = module - > addWire ( " \\ CI " ) ;
wire - > port_input = true ;
cell - > setPort ( " \\ CI " , wire ) ;
wire = module - > addWire ( " \\ CO " ) ;
wire - > width = width ;
wire - > port_output = true ;
cell - > setPort ( " \\ CO " , wire ) ;
}
2014-09-06 08:47:46 -05:00
if ( cell_type = = " $macc " )
{
Macc macc ;
2014-09-06 12:44:11 -05:00
int width = 1 + xorshift32 ( 8 ) ;
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
RTLIL : : Wire * wire_a = module - > addWire ( " \\ A " ) ;
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 ) ;
}
wire = module - > addWire ( " \\ 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 ;
wire = module - > addWire ( " \\ Y " ) ;
wire - > width = width ;
wire - > port_output = true ;
cell - > setPort ( " \\ Y " , wire ) ;
macc . to_cell ( cell ) ;
}
2014-08-31 10:06:36 -05:00
if ( cell_type = = " $lut " )
{
int width = 1 + xorshift32 ( 6 ) ;
wire = module - > addWire ( " \\ A " ) ;
wire - > width = width ;
wire - > port_input = true ;
cell - > setPort ( " \\ A " , wire ) ;
wire = module - > addWire ( " \\ Y " ) ;
wire - > port_output = true ;
cell - > setPort ( " \\ Y " , wire ) ;
RTLIL : : SigSpec config ;
for ( int i = 0 ; i < ( 1 < < width ) ; i + + )
config . append ( xorshift32 ( 2 ) ? RTLIL : : S1 : RTLIL : : S0 ) ;
cell - > setParam ( " \\ LUT " , config . as_const ( ) ) ;
}
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' A ' ) ! = std : : string : : npos ) {
2014-08-31 10:06:36 -05:00
wire = module - > addWire ( " \\ A " ) ;
2014-07-29 15:05:00 -05:00
wire - > width = 1 + xorshift32 ( 8 ) ;
wire - > port_input = true ;
2014-07-31 09:38:54 -05:00
cell - > setPort ( " \\ A " , wire ) ;
2014-07-29 15:05:00 -05:00
}
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos ) {
2014-08-31 10:06:36 -05:00
wire = module - > addWire ( " \\ B " ) ;
2014-07-29 15:05:00 -05:00
if ( cell_type_flags . find ( ' h ' ) ! = std : : string : : npos )
wire - > width = 1 + xorshift32 ( 6 ) ;
else
wire - > width = 1 + xorshift32 ( 8 ) ;
wire - > port_input = true ;
2014-07-31 09:38:54 -05:00
cell - > setPort ( " \\ 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 )
cell - > parameters [ " \\ A_SIGNED " ] = true ;
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos )
cell - > parameters [ " \\ B_SIGNED " ] = true ;
}
if ( cell_type_flags . find ( ' s ' ) ! = std : : string : : npos ) {
if ( cell_type_flags . find ( ' A ' ) ! = std : : string : : npos & & xorshift32 ( 2 ) )
cell - > parameters [ " \\ A_SIGNED " ] = true ;
if ( cell_type_flags . find ( ' B ' ) ! = std : : string : : npos & & xorshift32 ( 2 ) )
cell - > parameters [ " \\ B_SIGNED " ] = true ;
}
if ( cell_type_flags . find ( ' Y ' ) ! = std : : string : : npos ) {
2014-08-31 10:06:36 -05:00
wire = module - > addWire ( " \\ Y " ) ;
2014-07-29 15:05:00 -05:00
wire - > width = 1 + xorshift32 ( 8 ) ;
wire - > port_output = true ;
2014-07-31 09:38:54 -05:00
cell - > setPort ( " \\ Y " , wire ) ;
2014-07-29 15:05:00 -05:00
}
2014-09-01 09:36:04 -05:00
if ( cell_type = = " $alu " )
{
wire = module - > addWire ( " \\ CI " ) ;
wire - > port_input = true ;
cell - > setPort ( " \\ CI " , wire ) ;
wire = module - > addWire ( " \\ BI " ) ;
wire - > port_input = true ;
cell - > setPort ( " \\ BI " , wire ) ;
wire = module - > addWire ( " \\ X " ) ;
wire - > width = SIZE ( cell - > getPort ( " \\ Y " ) ) ;
wire - > port_output = true ;
cell - > setPort ( " \\ X " , wire ) ;
wire = module - > addWire ( " \\ CO " ) ;
wire - > width = SIZE ( cell - > getPort ( " \\ Y " ) ) ;
wire - > port_output = true ;
cell - > setPort ( " \\ CO " , wire ) ;
}
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 ;
if ( SIZE ( sig ) = = 0 | | sig [ 0 ] . wire = = nullptr | | sig [ 0 ] . wire - > port_output )
continue ;
int n , m ;
switch ( xorshift32 ( 5 ) )
{
case 0 :
n = xorshift32 ( SIZE ( sig ) + 1 ) ;
for ( int i = 0 ; i < n ; i + + )
sig [ i ] = xorshift32 ( 2 ) = = 1 ? RTLIL : : S1 : RTLIL : : S0 ;
break ;
case 1 :
n = xorshift32 ( SIZE ( sig ) + 1 ) ;
for ( int i = n ; i < SIZE ( sig ) ; i + + )
sig [ i ] = xorshift32 ( 2 ) = = 1 ? RTLIL : : S1 : RTLIL : : S0 ;
break ;
case 2 :
n = xorshift32 ( SIZE ( sig ) ) ;
m = xorshift32 ( SIZE ( sig ) ) ;
for ( int i = std : : min ( n , m ) ; i < std : : max ( n , m ) ; i + + )
sig [ i ] = xorshift32 ( 2 ) = = 1 ? RTLIL : : S1 : RTLIL : : S0 ;
break ;
}
cell - > setPort ( conn . first , sig ) ;
}
}
2014-07-29 15:05:00 -05:00
module - > fixup_ports ( ) ;
cell - > fixup_parameters ( ) ;
cell - > check ( ) ;
}
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 ' : ' ' ) ;
2014-08-31 11:08:42 -05:00
RTLIL : : Module * gold_mod = design - > module ( " \\ gold " ) ;
RTLIL : : Module * gate_mod = design - > module ( " \\ gate " ) ;
ConstEval gold_ce ( gold_mod ) , gate_ce ( gate_mod ) ;
2014-09-02 10:28:13 -05:00
ezDefaultSAT ez1 , ez2 ;
SigMap sigmap ( gold_mod ) ;
SatGen satgen1 ( & ez1 , & sigmap ) ;
SatGen satgen2 ( & ez2 , & sigmap ) ;
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 )
vlog_file < < stringf ( " reg [%d:0] %s; \n " , SIZE ( wire ) - 1 , log_id ( wire ) ) ;
else
vlog_file < < stringf ( " wire [%d:0] %s_expr, %s_noexpr; \n " , SIZE ( wire ) - 1 , log_id ( wire ) , log_id ( wire ) ) ;
}
vlog_file < < stringf ( " %s_expr uut_expr( " , uut_name . c_str ( ) ) ;
for ( int i = 0 ; i < SIZE ( gold_mod - > ports ) ; i + + )
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 ( ) ) ;
for ( int i = 0 ; i < SIZE ( gold_mod - > ports ) ; i + + )
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 ) ;
log_assert ( SIZE ( gold_wire ) = = SIZE ( gate_wire ) ) ;
if ( ! gold_wire - > port_input )
continue ;
RTLIL : : Const in_value ;
for ( int i = 0 ; i < SIZE ( gold_wire ) ; i + + )
in_value . bits . push_back ( xorshift32 ( 2 ) ? RTLIL : : S1 : RTLIL : : S0 ) ;
if ( xorshift32 ( 4 ) = = 0 ) {
int inv_chance = 1 + xorshift32 ( 8 ) ;
for ( int i = 0 ; i < SIZE ( gold_wire ) ; i + + )
if ( xorshift32 ( inv_chance ) = = 0 )
in_value . bits [ i ] = RTLIL : : Sx ;
}
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-09-06 13:30:46 -05:00
if ( vlog_file . is_open ( ) & & SIZE ( 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 ) ;
log_assert ( SIZE ( gold_wire ) = = SIZE ( gate_wire ) ) ;
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 ;
for ( int i = 0 ; i < SIZE ( gold_wire ) ; i + + ) {
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 " ,
vlog_pattern_info . c_str ( ) , log_id ( gold_wire ) , SIZE ( gold_outval ) , gold_outval . as_string ( ) . c_str ( ) , log_id ( gold_wire ) , log_id ( gold_wire ) ) ;
2014-09-02 15:49:43 -05:00
vlog_file < < stringf ( " if (%s_expr !== %d'b%s) begin $display( \" ERROR \" ); $finish; end \n " , log_id ( gold_wire ) , SIZE ( 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 ) , SIZE ( gold_outval ) , gold_outval . as_string ( ) . c_str ( ) ) ;
}
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
2014-09-07 10:05:41 -05:00
if ( ! ez1 . solve ( sat1_model , sat1_model_value , ez1 . vec_eq ( sat1_in_sig , sat1_in_val ) ) )
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: " ) ;
for ( int i = SIZE ( out_sig ) - 1 ; i > = 0 ; i - - )
log ( " %c " , sat1_model_value . at ( i ) ? ' 1 ' : ' 0 ' ) ;
log ( " \n " ) ;
}
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
for ( int i = 0 ; i < SIZE ( out_sig ) ; i + + ) {
if ( out_val [ i ] ! = RTLIL : : S0 & & out_val [ i ] ! = RTLIL : : S1 )
continue ;
if ( out_val [ i ] = = RTLIL : : S0 & & sat1_model_value . at ( i ) = = false )
continue ;
if ( out_val [ i ] = = RTLIL : : S1 & & sat1_model_value . at ( i ) = = true )
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
2014-09-07 10:05:41 -05: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 ) ) )
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: " ) ;
for ( int i = SIZE ( out_sig ) - 1 ; i > = 0 ; i - - )
log ( " %c " , sat2_model_value . at ( SIZE ( out_sig ) + i ) ? ' x ' : sat2_model_value . at ( i ) ? ' 1 ' : ' 0 ' ) ;
log ( " \n " ) ;
}
2014-09-02 10:28:13 -05:00
2014-09-07 10:05:41 -05:00
for ( int i = 0 ; i < SIZE ( out_sig ) ; i + + ) {
if ( sat2_model_value . at ( SIZE ( out_sig ) + i ) ) {
if ( out_val [ i ] ! = RTLIL : : S0 & & out_val [ i ] ! = RTLIL : : S1 )
continue ;
} else {
if ( out_val [ i ] = = RTLIL : : S0 & & sat2_model_value . at ( i ) = = false )
continue ;
if ( out_val [ i ] = = RTLIL : : S1 & & sat2_model_value . at ( i ) = = true )
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 " ) { }
virtual void help ( )
{
// |---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-07-29 15:05:00 -05:00
log ( " cell types. \n " ) ;
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 " ) ;
2014-07-30 08:59:38 -05:00
log ( " -f {ilang_file} \n " ) ;
log ( " don't generate circuits. instead load the specified ilang file. \n " ) ;
log ( " \n " ) ;
log ( " -map {filename} \n " ) ;
log ( " pass this option to techmap. \n " ) ;
log ( " \n " ) ;
2014-09-01 08:37:21 -05:00
log ( " -simplib \n " ) ;
log ( " use \" techmap -map +/simlib.v -max_iter 2 -autoproc \" \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 " ) ;
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 " ) ;
log ( " create a verilog test bench to test simlib and write_verilog \n " ) ;
log ( " \n " ) ;
2014-07-29 15:05:00 -05:00
}
2014-07-30 08:59:38 -05:00
virtual void execute ( std : : vector < std : : string > args , RTLIL : : Design * )
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 " ;
2014-07-30 08:59:38 -05:00
std : : string ilang_file ;
2014-08-16 12:44:31 -05:00
xorshift32_state = 0 ;
2014-09-02 15:49:43 -05:00
std : : ofstream vlog_file ;
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 ;
2014-07-30 08:59:38 -05:00
int argidx ;
for ( argidx = 1 ; argidx < SIZE ( args ) ; argidx + + )
{
if ( args [ argidx ] = = " -n " & & argidx + 1 < SIZE ( args ) ) {
num_iter = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2014-08-16 12:44:31 -05:00
if ( args [ argidx ] = = " -s " & & argidx + 1 < SIZE ( args ) ) {
xorshift32_state = atoi ( args [ + + argidx ] . c_str ( ) ) ;
continue ;
}
2014-07-30 08:59:38 -05:00
if ( args [ argidx ] = = " -map " & & argidx + 1 < SIZE ( args ) ) {
techmap_cmd + = " -map " + args [ + + argidx ] ;
continue ;
}
if ( args [ argidx ] = = " -f " & & argidx + 1 < SIZE ( args ) ) {
ilang_file = args [ + + argidx ] ;
num_iter = 1 ;
continue ;
}
2014-09-06 04:46:07 -05:00
if ( args [ argidx ] = = " -script " & & argidx + 1 < SIZE ( args ) ) {
techmap_cmd = " script " + args [ + + argidx ] ;
continue ;
}
2014-09-01 08:37:21 -05:00
if ( args [ argidx ] = = " -simlib " ) {
techmap_cmd = " techmap -map +/simlib.v -max_iter 2 -autoproc " ;
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 ;
}
2014-09-01 08:37:21 -05:00
if ( args [ argidx ] = = " -v " ) {
verbose = true ;
continue ;
}
2014-09-02 15:49:43 -05:00
if ( args [ argidx ] = = " -vlog " & & argidx + 1 < SIZE ( args ) ) {
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 ;
}
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
2014-07-29 15:05:00 -05:00
std : : map < std : : string , std : : string > cell_types ;
2014-07-30 08:59:38 -05:00
std : : vector < std : : string > selected_cell_types ;
2014-07-29 15:05:00 -05:00
cell_types [ " $not " ] = " ASY " ;
cell_types [ " $pos " ] = " ASY " ;
cell_types [ " $neg " ] = " ASY " ;
cell_types [ " $and " ] = " ABSY " ;
cell_types [ " $or " ] = " ABSY " ;
cell_types [ " $xor " ] = " ABSY " ;
cell_types [ " $xnor " ] = " ABSY " ;
cell_types [ " $reduce_and " ] = " ASY " ;
cell_types [ " $reduce_or " ] = " ASY " ;
cell_types [ " $reduce_xor " ] = " ASY " ;
cell_types [ " $reduce_xnor " ] = " ASY " ;
cell_types [ " $reduce_bool " ] = " ASY " ;
cell_types [ " $shl " ] = " ABshY " ;
cell_types [ " $shr " ] = " ABshY " ;
cell_types [ " $sshl " ] = " ABshY " ;
cell_types [ " $sshr " ] = " ABshY " ;
2014-07-30 08:59:38 -05:00
cell_types [ " $shift " ] = " ABshY " ;
cell_types [ " $shiftx " ] = " ABshY " ;
2014-07-29 15:05:00 -05:00
cell_types [ " $lt " ] = " ABSY " ;
cell_types [ " $le " ] = " ABSY " ;
cell_types [ " $eq " ] = " ABSY " ;
cell_types [ " $ne " ] = " ABSY " ;
// cell_types["$eqx"] = "ABSY";
// cell_types["$nex"] = "ABSY";
cell_types [ " $ge " ] = " ABSY " ;
cell_types [ " $gt " ] = " ABSY " ;
cell_types [ " $add " ] = " ABSY " ;
cell_types [ " $sub " ] = " ABSY " ;
cell_types [ " $mul " ] = " ABSY " ;
cell_types [ " $div " ] = " ABSY " ;
cell_types [ " $mod " ] = " ABSY " ;
// cell_types["$pow"] = "ABsY";
cell_types [ " $logic_not " ] = " ASY " ;
cell_types [ " $logic_and " ] = " ABSY " ;
cell_types [ " $logic_or " ] = " ABSY " ;
// cell_types["$mux"] = "A";
// cell_types["$pmux"] = "A";
// cell_types["$slice"] = "A";
// cell_types["$concat"] = "A";
// cell_types["$assert"] = "A";
2014-08-31 10:06:36 -05:00
cell_types [ " $lut " ] = " * " ;
2014-09-01 09:36:04 -05:00
cell_types [ " $alu " ] = " ABSY " ;
2014-09-08 06:28:23 -05:00
cell_types [ " $lcu " ] = " * " ;
2014-09-06 08:47:46 -05:00
cell_types [ " $macc " ] = " * " ;
2014-09-08 05:15:39 -05:00
cell_types [ " $fa " ] = " * " ;
2014-08-31 10:06:36 -05:00
2014-07-30 08:59:38 -05:00
for ( ; argidx < SIZE ( args ) ; argidx + + )
{
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
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 ) {
cell_type_list + = " \n " + it . first ;
charcount = 0 ;
} else
cell_type_list + = " " + it . first ;
charcount + = SIZE ( it . first ) ;
}
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
}
2014-07-30 08:59:38 -05:00
if ( ! ilang_file . empty ( ) ) {
if ( ! selected_cell_types . empty ( ) )
log_cmd_error ( " Do not specify any cell types when using -f. \n " ) ;
selected_cell_types . push_back ( " ilang " ) ;
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
2014-07-30 08:59:38 -05:00
for ( auto cell_type : selected_cell_types )
for ( int i = 0 ; i < num_iter ; i + + )
{
RTLIL : : Design * design = new RTLIL : : Design ;
if ( cell_type = = " ilang " )
Frontend : : frontend_call ( design , NULL , std : : string ( ) , " ilang " + ilang_file ) ;
else
2014-09-08 04:12:39 -05:00
create_gold_module ( design , cell_type , cell_types . at ( cell_type ) , constmode ) ;
2014-09-06 04:46:07 -05:00
Pass : : call ( design , stringf ( " copy gold gate; cd gate; %s; cd ..; opt -fast gate " , techmap_cmd . c_str ( ) ) ) ;
2014-09-07 10:05:41 -05:00
if ( ! nosat )
Pass : : call ( design , " miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter " ) ;
2014-09-01 08:37:21 -05:00
if ( verbose )
Pass : : call ( design , " dump gate " ) ;
Pass : : call ( design , " dump gold " ) ;
2014-09-07 10:05:41 -05:00
if ( ! nosat )
Pass : : call ( design , " sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter " ) ;
2014-09-02 15:49:43 -05:00
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 " ) ;
2014-09-03 06:43:37 -05:00
uut_names . push_back ( uut_name ) ;
2014-09-02 15:49:43 -05:00
}
2014-09-07 10:05:41 -05:00
run_eval_test ( design , verbose , nosat , uut_name , vlog_file ) ;
2014-07-30 08:59:38 -05:00
delete design ;
}
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 ;