2013-01-05 04:13:26 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2012 Clifford Wolf < clifford @ clifford . 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 .
*
* - - -
*
* This is the AST frontend library .
*
* The AST frontend library is not a frontend on it ' s own but provides a
* generic abstract syntax tree ( AST ) abstraction for HDL code and can be
* used by HDL frontends . See " ast.h " for an overview of the API and the
* Verilog frontend for an usage example .
*
*/
# include "kernel/log.h"
2013-02-27 02:32:19 -06:00
# include "libs/sha1/sha1.h"
2014-10-26 14:33:10 -05:00
# include "frontends/verilog/verilog_frontend.h"
2013-01-05 04:13:26 -06:00
# include "ast.h"
# include <sstream>
# include <stdarg.h>
2014-10-26 14:33:10 -05:00
# include <stdlib.h>
2014-06-14 01:51:22 -05:00
# include <math.h>
2013-01-05 04:13:26 -06:00
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_BEGIN
2013-01-05 04:13:26 -06:00
using namespace AST ;
using namespace AST_INTERNAL ;
// convert the AST into a simpler AST that has all parameters subsitited by their
// values, unrolled for-loops, expanded generate blocks, etc. when this function
// is done with an AST it can be converted into RTLIL using genRTLIL().
//
// this function also does all name resolving and sets the id2ast member of all
// nodes that link to a different node using names and lexical scoping.
2014-02-14 12:56:44 -06:00
bool AstNode : : simplify ( bool const_fold , bool at_zero , bool in_lvalue , int stage , int width_hint , bool sign_hint , bool in_param )
2013-01-05 04:13:26 -06:00
{
AstNode * newNode = NULL ;
bool did_something = false ;
2015-01-15 05:41:52 -06:00
static pair < string , int > last_blocking_assignment_warn ;
2013-01-05 04:13:26 -06:00
2014-06-14 05:00:47 -05:00
#if 0
log ( " ------------- \n " ) ;
log ( " const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d \n " ,
int ( const_fold ) , int ( at_zero ) , int ( in_lvalue ) , int ( stage ) , int ( width_hint ) , int ( sign_hint ) , int ( in_param ) ) ;
dumpAst ( NULL , " > " ) ;
# endif
2013-01-05 04:13:26 -06:00
if ( stage = = 0 )
{
2014-07-28 04:08:55 -05:00
log_assert ( type = = AST_MODULE ) ;
2015-01-15 05:41:52 -06:00
last_blocking_assignment_warn = pair < string , int > ( ) ;
2013-01-05 04:13:26 -06:00
2014-02-14 12:56:44 -06:00
while ( simplify ( const_fold , at_zero , in_lvalue , 1 , width_hint , sign_hint , in_param ) ) { }
2013-01-05 04:13:26 -06:00
2013-10-24 04:20:13 -05:00
if ( ! flag_nomem2reg & & ! get_bool_attribute ( " \\ nomem2reg " ) )
2013-01-05 04:13:26 -06:00
{
2014-12-28 20:11:50 -06:00
dict < AstNode * , pool < std : : string > > mem2reg_places ;
dict < AstNode * , uint32_t > mem2reg_candidates , dummy_proc_flags ;
2013-11-21 06:49:00 -06:00
uint32_t flags = flag_mem2reg ? AstNode : : MEM2REG_FL_ALL : 0 ;
mem2reg_as_needed_pass1 ( mem2reg_places , mem2reg_candidates , dummy_proc_flags , flags ) ;
2014-12-28 20:11:50 -06:00
pool < AstNode * > mem2reg_set ;
2013-11-21 06:49:00 -06:00
for ( auto & it : mem2reg_candidates )
{
AstNode * mem = it . first ;
uint32_t memflags = it . second ;
2014-07-28 04:08:55 -05:00
log_assert ( ( memflags & ~ 0x00ffff00 ) = = 0 ) ;
2013-11-21 06:49:00 -06:00
if ( mem - > get_bool_attribute ( " \\ nomem2reg " ) )
continue ;
if ( memflags & AstNode : : MEM2REG_FL_FORCED )
goto silent_activate ;
if ( memflags & AstNode : : MEM2REG_FL_EQ2 )
goto verbose_activate ;
2013-11-21 14:26:56 -06:00
if ( memflags & AstNode : : MEM2REG_FL_SET_ASYNC )
goto verbose_activate ;
2013-11-21 06:49:00 -06:00
if ( ( memflags & AstNode : : MEM2REG_FL_SET_INIT ) & & ( memflags & AstNode : : MEM2REG_FL_SET_ELSE ) )
goto verbose_activate ;
2014-06-17 14:39:25 -05:00
if ( memflags & AstNode : : MEM2REG_FL_CMPLX_LHS )
goto verbose_activate ;
2013-11-21 14:26:56 -06:00
// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
2013-11-21 06:49:00 -06:00
continue ;
verbose_activate :
if ( mem2reg_set . count ( mem ) = = 0 ) {
2014-12-26 20:26:30 -06:00
std : : string message = stringf ( " Replacing memory %s with list of registers. " , mem - > str . c_str ( ) ) ;
2013-11-21 06:49:00 -06:00
bool first_element = true ;
for ( auto & place : mem2reg_places [ it . first ] ) {
2014-12-26 20:26:30 -06:00
message + = stringf ( " %s%s " , first_element ? " See " : " , " , place . c_str ( ) ) ;
2013-11-21 06:49:00 -06:00
first_element = false ;
}
2014-12-26 20:26:30 -06:00
log_warning ( " %s \n " , message . c_str ( ) ) ;
2013-11-21 06:49:00 -06:00
}
silent_activate :
2013-11-21 14:26:56 -06:00
// log("Note: Replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
2013-11-21 06:49:00 -06:00
mem2reg_set . insert ( mem ) ;
}
2013-01-05 04:13:26 -06:00
for ( auto node : mem2reg_set )
{
int mem_width , mem_size , addr_bits ;
node - > meminfo ( mem_width , mem_size , addr_bits ) ;
for ( int i = 0 ; i < mem_size ; i + + ) {
AstNode * reg = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE ,
mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
reg - > str = stringf ( " %s[%d] " , node - > str . c_str ( ) , i ) ;
reg - > is_reg = true ;
reg - > is_signed = node - > is_signed ;
children . push_back ( reg ) ;
2014-02-14 12:56:44 -06:00
while ( reg - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
}
}
2013-03-25 11:13:14 -05:00
mem2reg_as_needed_pass2 ( mem2reg_set , this , NULL ) ;
2013-01-05 04:13:26 -06:00
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
if ( mem2reg_set . count ( children [ i ] ) > 0 ) {
delete children [ i ] ;
children . erase ( children . begin ( ) + ( i - - ) ) ;
}
}
}
2014-02-14 12:56:44 -06:00
while ( simplify ( const_fold , at_zero , in_lvalue , 2 , width_hint , sign_hint , in_param ) ) { }
2013-01-05 04:13:26 -06:00
return false ;
}
current_filename = filename ;
set_line_num ( linenum ) ;
// we do not look inside a task or function
// (but as soon as a task of function is instanciated we process the generated AST as usual)
if ( type = = AST_FUNCTION | | type = = AST_TASK )
return false ;
2014-06-06 10:40:45 -05:00
// deactivate all calls to non-synthesis system taks
2015-01-15 06:08:19 -06:00
if ( ( type = = AST_FCALL | | type = = AST_TCALL ) & & ( str = = " $display " | | str = = " $strobe " | | str = = " $monitor " | | str = = " $time " | | str = = " $stop " | | str = = " $finish " | |
str = = " $dumpfile " | | str = = " $dumpvars " | | str = = " $dumpon " | | str = = " $dumpoff " | | str = = " $dumpall " ) ) {
log_warning ( " Ignoring call to system %s %s at %s:%d. \n " , type = = AST_FCALL ? " function " : " task " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2013-01-05 04:13:26 -06:00
delete_children ( ) ;
str = std : : string ( ) ;
}
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
2013-07-04 07:12:33 -05:00
if ( type = = AST_WIRE | | type = = AST_PARAMETER | | type = = AST_LOCALPARAM | | type = = AST_DEFPARAM | | type = = AST_PARASET | | type = = AST_RANGE | | type = = AST_PREFIX )
2014-02-14 13:45:30 -06:00
const_fold = true ;
2013-01-05 04:13:26 -06:00
if ( type = = AST_IDENTIFIER & & current_scope . count ( str ) > 0 & & ( current_scope [ str ] - > type = = AST_PARAMETER | | current_scope [ str ] - > type = = AST_LOCALPARAM ) )
const_fold = true ;
2014-02-14 13:45:30 -06:00
// in certain cases a function must be evaluated constant. this is what in_param controls.
if ( type = = AST_PARAMETER | | type = = AST_LOCALPARAM | | type = = AST_DEFPARAM | | type = = AST_PARASET | | type = = AST_PREFIX )
in_param = true ;
2013-01-05 04:13:26 -06:00
std : : map < std : : string , AstNode * > backup_scope ;
// create name resolution entries for all objects with names
// also merge multiple declarations for the same wire (e.g. "output foobar; reg foobar;")
if ( type = = AST_MODULE ) {
current_scope . clear ( ) ;
std : : map < std : : string , AstNode * > this_wire_scope ;
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * node = children [ i ] ;
if ( node - > type = = AST_WIRE ) {
if ( this_wire_scope . count ( node - > str ) > 0 ) {
AstNode * first_node = this_wire_scope [ node - > str ] ;
2013-03-23 12:54:31 -05:00
if ( ! node - > is_input & & ! node - > is_output & & node - > is_reg & & node - > children . size ( ) = = 0 )
goto wires_are_compatible ;
2015-01-15 05:53:12 -06:00
if ( first_node - > children . size ( ) = = 0 & & node - > children . size ( ) = = 1 & & node - > children [ 0 ] - > type = = AST_RANGE ) {
AstNode * r = node - > children [ 0 ] ;
if ( r - > range_valid & & r - > range_left = = 0 & & r - > range_right = = 0 ) {
delete r ;
node - > children . pop_back ( ) ;
}
}
2013-01-05 04:13:26 -06:00
if ( first_node - > children . size ( ) ! = node - > children . size ( ) )
goto wires_are_incompatible ;
for ( size_t j = 0 ; j < node - > children . size ( ) ; j + + ) {
AstNode * n1 = first_node - > children [ j ] , * n2 = node - > children [ j ] ;
if ( n1 - > type = = AST_RANGE & & n2 - > type = = AST_RANGE & & n1 - > range_valid & & n2 - > range_valid ) {
if ( n1 - > range_left ! = n2 - > range_left )
goto wires_are_incompatible ;
if ( n1 - > range_right ! = n2 - > range_right )
goto wires_are_incompatible ;
} else if ( * n1 ! = * n2 )
goto wires_are_incompatible ;
}
if ( first_node - > range_left ! = node - > range_left )
goto wires_are_incompatible ;
if ( first_node - > range_right ! = node - > range_right )
goto wires_are_incompatible ;
if ( first_node - > port_id = = 0 & & ( node - > is_input | | node - > is_output ) )
goto wires_are_incompatible ;
2013-03-23 12:54:31 -05:00
wires_are_compatible :
2013-01-05 04:13:26 -06:00
if ( node - > is_input )
first_node - > is_input = true ;
if ( node - > is_output )
first_node - > is_output = true ;
if ( node - > is_reg )
first_node - > is_reg = true ;
if ( node - > is_signed )
first_node - > is_signed = true ;
for ( auto & it : node - > attributes ) {
if ( first_node - > attributes . count ( it . first ) > 0 )
delete first_node - > attributes [ it . first ] ;
first_node - > attributes [ it . first ] = it . second - > clone ( ) ;
}
children . erase ( children . begin ( ) + ( i - - ) ) ;
did_something = true ;
delete node ;
continue ;
2014-03-05 12:55:58 -06:00
wires_are_incompatible :
if ( stage > 1 )
log_error ( " Incompatible re-declaration of wire %s at %s:%d. \n " , node - > str . c_str ( ) , filename . c_str ( ) , linenum ) ;
continue ;
2013-01-05 04:13:26 -06:00
}
this_wire_scope [ node - > str ] = node ;
}
if ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_WIRE | | node - > type = = AST_AUTOWIRE | | node - > type = = AST_GENVAR | |
2014-08-21 05:43:51 -05:00
node - > type = = AST_MEMORY | | node - > type = = AST_FUNCTION | | node - > type = = AST_TASK | | node - > type = = AST_DPI_FUNCTION | | node - > type = = AST_CELL ) {
2013-01-05 04:13:26 -06:00
backup_scope [ node - > str ] = current_scope [ node - > str ] ;
current_scope [ node - > str ] = node ;
}
}
2013-11-24 12:40:23 -06:00
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * node = children [ i ] ;
if ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_WIRE | | node - > type = = AST_AUTOWIRE )
2014-03-05 12:45:33 -06:00
while ( node - > simplify ( true , false , false , 1 , - 1 , false , node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM ) )
did_something = true ;
2013-11-24 12:40:23 -06:00
}
2013-01-05 04:13:26 -06:00
}
auto backup_current_block = current_block ;
auto backup_current_block_child = current_block_child ;
auto backup_current_top_block = current_top_block ;
2013-11-03 23:04:42 -06:00
int backup_width_hint = width_hint ;
bool backup_sign_hint = sign_hint ;
bool detect_width_simple = false ;
bool child_0_is_self_determined = false ;
bool child_1_is_self_determined = false ;
2014-06-25 03:05:36 -05:00
bool child_2_is_self_determined = false ;
2013-11-03 23:04:42 -06:00
bool children_are_self_determined = false ;
bool reset_width_after_children = false ;
switch ( type )
{
case AST_ASSIGN_EQ :
case AST_ASSIGN_LE :
case AST_ASSIGN :
2014-06-06 10:40:45 -05:00
while ( ! children [ 0 ] - > basic_prep & & children [ 0 ] - > simplify ( false , false , true , stage , - 1 , false , in_param ) = = true )
2014-03-05 12:45:33 -06:00
did_something = true ;
2014-06-06 10:40:45 -05:00
while ( ! children [ 1 ] - > basic_prep & & children [ 1 ] - > simplify ( false , false , false , stage , - 1 , false , in_param ) = = true )
2014-03-05 12:45:33 -06:00
did_something = true ;
2013-11-04 14:29:36 -06:00
children [ 0 ] - > detectSignWidth ( backup_width_hint , backup_sign_hint ) ;
children [ 1 ] - > detectSignWidth ( width_hint , sign_hint ) ;
width_hint = std : : max ( width_hint , backup_width_hint ) ;
2013-11-03 23:04:42 -06:00
child_0_is_self_determined = true ;
break ;
2013-11-07 02:58:15 -06:00
case AST_PARAMETER :
case AST_LOCALPARAM :
2014-03-05 12:45:33 -06:00
while ( ! children [ 0 ] - > basic_prep & & children [ 0 ] - > simplify ( false , false , false , stage , - 1 , false , true ) = = true )
did_something = true ;
2013-11-07 02:58:15 -06:00
children [ 0 ] - > detectSignWidth ( width_hint , sign_hint ) ;
2014-06-14 05:00:47 -05:00
if ( children . size ( ) > 1 & & children [ 1 ] - > type = = AST_RANGE ) {
2014-03-05 12:45:33 -06:00
while ( ! children [ 1 ] - > basic_prep & & children [ 1 ] - > simplify ( false , false , false , stage , - 1 , false , true ) = = true )
did_something = true ;
2013-11-07 02:58:15 -06:00
if ( ! children [ 1 ] - > range_valid )
log_error ( " Non-constant width range on parameter decl at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
width_hint = std : : max ( width_hint , children [ 1 ] - > range_left - children [ 1 ] - > range_right + 1 ) ;
}
break ;
2014-02-01 06:50:23 -06:00
case AST_TO_BITS :
2013-11-03 23:04:42 -06:00
case AST_TO_SIGNED :
case AST_TO_UNSIGNED :
case AST_CONCAT :
case AST_REPLICATE :
case AST_REDUCE_AND :
case AST_REDUCE_OR :
case AST_REDUCE_XOR :
case AST_REDUCE_XNOR :
case AST_REDUCE_BOOL :
detect_width_simple = true ;
children_are_self_determined = true ;
break ;
case AST_NEG :
case AST_BIT_NOT :
case AST_POS :
case AST_BIT_AND :
case AST_BIT_OR :
case AST_BIT_XOR :
case AST_BIT_XNOR :
case AST_ADD :
case AST_SUB :
case AST_MUL :
case AST_DIV :
case AST_MOD :
detect_width_simple = true ;
break ;
case AST_SHIFT_LEFT :
case AST_SHIFT_RIGHT :
case AST_SHIFT_SLEFT :
case AST_SHIFT_SRIGHT :
case AST_POW :
detect_width_simple = true ;
child_1_is_self_determined = true ;
break ;
case AST_LT :
case AST_LE :
case AST_EQ :
case AST_NE :
2013-12-27 06:50:08 -06:00
case AST_EQX :
case AST_NEX :
2013-11-03 23:04:42 -06:00
case AST_GE :
case AST_GT :
width_hint = - 1 ;
sign_hint = true ;
for ( auto child : children ) {
2014-03-05 12:45:33 -06:00
while ( ! child - > basic_prep & & child - > simplify ( false , false , in_lvalue , stage , - 1 , false , in_param ) = = true )
did_something = true ;
2013-11-03 23:04:42 -06:00
child - > detectSignWidthWorker ( width_hint , sign_hint ) ;
}
reset_width_after_children = true ;
break ;
case AST_LOGIC_AND :
case AST_LOGIC_OR :
case AST_LOGIC_NOT :
detect_width_simple = true ;
children_are_self_determined = true ;
break ;
case AST_TERNARY :
detect_width_simple = true ;
child_0_is_self_determined = true ;
break ;
case AST_MEMRD :
detect_width_simple = true ;
children_are_self_determined = true ;
break ;
default :
2013-11-02 07:00:17 -05:00
width_hint = - 1 ;
sign_hint = false ;
}
2013-11-03 23:04:42 -06:00
if ( detect_width_simple & & width_hint < 0 ) {
2014-06-06 17:02:05 -05:00
if ( type = = AST_REPLICATE )
while ( children [ 0 ] - > simplify ( true , false , in_lvalue , stage , - 1 , false , true ) = = true )
did_something = true ;
2013-11-03 23:04:42 -06:00
for ( auto child : children )
2014-03-05 12:45:33 -06:00
while ( ! child - > basic_prep & & child - > simplify ( false , false , in_lvalue , stage , - 1 , false , in_param ) = = true )
did_something = true ;
2013-11-03 23:04:42 -06:00
detectSignWidth ( width_hint , sign_hint ) ;
2013-11-02 07:00:17 -05:00
}
2014-06-25 03:05:36 -05:00
if ( type = = AST_TERNARY ) {
int width_hint_left , width_hint_right ;
bool sign_hint_left , sign_hint_right ;
bool found_real_left , found_real_right ;
children [ 1 ] - > detectSignWidth ( width_hint_left , sign_hint_left , & found_real_left ) ;
children [ 2 ] - > detectSignWidth ( width_hint_right , sign_hint_right , & found_real_right ) ;
if ( found_real_left | | found_real_right ) {
child_1_is_self_determined = true ;
child_2_is_self_determined = true ;
}
}
2014-10-29 02:29:51 -05:00
if ( const_fold & & type = = AST_CASE )
{
while ( children [ 0 ] - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ) { }
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 0 ] - > bits_only_01 ( ) ) {
std : : vector < AstNode * > new_children ;
new_children . push_back ( children [ 0 ] ) ;
for ( int i = 1 ; i < GetSize ( children ) ; i + + ) {
AstNode * child = children [ i ] ;
log_assert ( child - > type = = AST_COND ) ;
for ( auto v : child - > children ) {
if ( v - > type = = AST_DEFAULT )
goto keep_const_cond ;
if ( v - > type = = AST_BLOCK )
continue ;
while ( v - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ) { }
if ( v - > type = = AST_CONSTANT & & v - > bits_only_01 ( ) ) {
if ( v - > bits = = children [ 0 ] - > bits ) {
while ( i + 1 < GetSize ( children ) )
delete children [ + + i ] ;
goto keep_const_cond ;
}
continue ;
}
goto keep_const_cond ;
}
if ( 0 )
keep_const_cond :
new_children . push_back ( child ) ;
else
delete child ;
}
new_children . swap ( children ) ;
}
}
2013-01-05 04:13:26 -06:00
// simplify all children first
// (iterate by index as e.g. auto wires can add new children in the process)
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
bool did_something_here = true ;
if ( ( type = = AST_GENFOR | | type = = AST_FOR ) & & i > = 3 )
break ;
2013-12-04 14:06:54 -06:00
if ( ( type = = AST_GENIF | | type = = AST_GENCASE ) & & i > = 1 )
2013-01-05 04:13:26 -06:00
break ;
2013-03-26 03:44:54 -05:00
if ( type = = AST_GENBLOCK )
break ;
2013-12-04 02:10:16 -06:00
if ( type = = AST_BLOCK & & ! str . empty ( ) )
break ;
2013-02-26 06:18:22 -06:00
if ( type = = AST_PREFIX & & i > = 1 )
break ;
2013-01-05 04:13:26 -06:00
while ( did_something_here & & i < children . size ( ) ) {
bool const_fold_here = const_fold , in_lvalue_here = in_lvalue ;
2013-11-02 07:00:17 -05:00
int width_hint_here = width_hint ;
bool sign_hint_here = sign_hint ;
2014-06-06 17:02:05 -05:00
bool in_param_here = in_param ;
if ( i = = 0 & & ( type = = AST_REPLICATE | | type = = AST_WIRE ) )
const_fold_here = true , in_param_here = true ;
2013-11-07 07:08:53 -06:00
if ( type = = AST_PARAMETER | | type = = AST_LOCALPARAM )
const_fold_here = true ;
2013-01-05 04:13:26 -06:00
if ( i = = 0 & & ( type = = AST_ASSIGN | | type = = AST_ASSIGN_EQ | | type = = AST_ASSIGN_LE ) )
in_lvalue_here = true ;
if ( type = = AST_BLOCK ) {
current_block = this ;
current_block_child = children [ i ] ;
}
2013-03-31 04:19:11 -05:00
if ( ( type = = AST_ALWAYS | | type = = AST_INITIAL ) & & children [ i ] - > type = = AST_BLOCK )
2013-01-05 04:13:26 -06:00
current_top_block = children [ i ] ;
2013-11-03 23:04:42 -06:00
if ( i = = 0 & & child_0_is_self_determined )
width_hint_here = - 1 , sign_hint_here = false ;
if ( i = = 1 & & child_1_is_self_determined )
width_hint_here = - 1 , sign_hint_here = false ;
2014-06-25 03:05:36 -05:00
if ( i = = 2 & & child_2_is_self_determined )
width_hint_here = - 1 , sign_hint_here = false ;
2013-11-03 23:04:42 -06:00
if ( children_are_self_determined )
width_hint_here = - 1 , sign_hint_here = false ;
2014-06-06 17:02:05 -05:00
did_something_here = children [ i ] - > simplify ( const_fold_here , at_zero , in_lvalue_here , stage , width_hint_here , sign_hint_here , in_param_here ) ;
2013-01-05 04:13:26 -06:00
if ( did_something_here )
did_something = true ;
2014-07-11 06:05:53 -05:00
}
if ( stage = = 2 & & children [ i ] - > type = = AST_INITIAL & & current_ast_mod ! = this ) {
current_ast_mod - > children . push_back ( children [ i ] ) ;
children . erase ( children . begin ( ) + ( i - - ) ) ;
did_something = true ;
2013-01-05 04:13:26 -06:00
}
}
for ( auto & attr : attributes ) {
2014-03-05 12:45:33 -06:00
while ( attr . second - > simplify ( true , false , false , stage , - 1 , false , true ) )
did_something = true ;
2013-01-05 04:13:26 -06:00
}
2013-11-03 23:04:42 -06:00
if ( reset_width_after_children ) {
width_hint = backup_width_hint ;
sign_hint = backup_sign_hint ;
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
}
2013-01-05 04:13:26 -06:00
current_block = backup_current_block ;
current_block_child = backup_current_block_child ;
current_top_block = backup_current_top_block ;
for ( auto it = backup_scope . begin ( ) ; it ! = backup_scope . end ( ) ; it + + ) {
if ( it - > second = = NULL )
current_scope . erase ( it - > first ) ;
else
current_scope [ it - > first ] = it - > second ;
}
current_filename = filename ;
set_line_num ( linenum ) ;
if ( type = = AST_MODULE )
current_scope . clear ( ) ;
2013-07-04 07:12:33 -05:00
// convert defparam nodes to cell parameters
if ( type = = AST_DEFPARAM & & ! str . empty ( ) ) {
size_t pos = str . rfind ( ' . ' ) ;
if ( pos = = std : : string : : npos )
2014-09-06 01:47:06 -05:00
log_error ( " Defparam `%s' does not contain a dot (module/parameter separator) at %s:%d! \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , filename . c_str ( ) , linenum ) ;
2013-07-04 07:12:33 -05:00
std : : string modname = str . substr ( 0 , pos ) , paraname = " \\ " + str . substr ( pos + 1 ) ;
if ( current_scope . count ( modname ) = = 0 | | current_scope . at ( modname ) - > type ! = AST_CELL )
2014-08-02 09:03:18 -05:00
log_error ( " Can't find cell for defparam `%s . %s` at %s:%d! \n " , RTLIL : : unescape_id ( modname ) . c_str ( ) , RTLIL : : unescape_id ( paraname ) . c_str ( ) , filename . c_str ( ) , linenum ) ;
2013-07-04 07:12:33 -05:00
AstNode * cell = current_scope . at ( modname ) , * paraset = clone ( ) ;
cell - > children . insert ( cell - > children . begin ( ) + 1 , paraset ) ;
paraset - > type = AST_PARASET ;
paraset - > str = paraname ;
str . clear ( ) ;
}
2013-02-26 06:18:22 -06:00
// resolve constant prefixes
if ( type = = AST_PREFIX ) {
if ( children [ 0 ] - > type ! = AST_CONSTANT ) {
2013-11-07 07:08:53 -06:00
// dumpAst(NULL, "> ");
2013-02-26 06:18:22 -06:00
log_error ( " Index in generate block prefix syntax at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
}
2014-07-28 04:08:55 -05:00
log_assert ( children [ 1 ] - > type = = AST_IDENTIFIER ) ;
2013-02-26 06:18:22 -06:00
newNode = children [ 1 ] - > clone ( ) ;
2013-11-20 06:57:40 -06:00
const char * second_part = children [ 1 ] - > str . c_str ( ) ;
if ( second_part [ 0 ] = = ' \\ ' )
second_part + + ;
newNode - > str = stringf ( " %s[%d].%s " , str . c_str ( ) , children [ 0 ] - > integer , second_part ) ;
2013-02-26 06:18:22 -06:00
goto apply_newNode ;
}
2014-02-01 06:50:23 -06:00
// evaluate TO_BITS nodes
if ( type = = AST_TO_BITS ) {
if ( children [ 0 ] - > type ! = AST_CONSTANT )
log_error ( " Left operand of to_bits expression is not constant at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
if ( children [ 1 ] - > type ! = AST_CONSTANT )
log_error ( " Right operand of to_bits expression is not constant at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
RTLIL : : Const new_value = children [ 1 ] - > bitsAsConst ( children [ 0 ] - > bitsAsConst ( ) . as_int ( ) , children [ 1 ] - > is_signed ) ;
newNode = mkconst_bits ( new_value . bits , children [ 1 ] - > is_signed ) ;
goto apply_newNode ;
}
2013-01-05 04:13:26 -06:00
// annotate constant ranges
if ( type = = AST_RANGE ) {
bool old_range_valid = range_valid ;
range_valid = false ;
2014-07-28 07:25:03 -05:00
range_swapped = false ;
2013-01-05 04:13:26 -06:00
range_left = - 1 ;
range_right = 0 ;
2014-07-28 04:08:55 -05:00
log_assert ( children . size ( ) > = 1 ) ;
2013-01-05 04:13:26 -06:00
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
range_valid = true ;
range_left = children [ 0 ] - > integer ;
if ( children . size ( ) = = 1 )
range_right = range_left ;
}
if ( children . size ( ) > = 2 ) {
if ( children [ 1 ] - > type = = AST_CONSTANT )
range_right = children [ 1 ] - > integer ;
else
range_valid = false ;
}
if ( old_range_valid ! = range_valid )
did_something = true ;
if ( range_valid & & range_left > = 0 & & range_right > range_left ) {
int tmp = range_right ;
range_right = range_left ;
range_left = tmp ;
2014-07-28 07:25:03 -05:00
range_swapped = true ;
2013-01-05 04:13:26 -06:00
}
}
// annotate wires with their ranges
if ( type = = AST_WIRE ) {
if ( children . size ( ) > 0 ) {
if ( children [ 0 ] - > range_valid ) {
if ( ! range_valid )
did_something = true ;
range_valid = true ;
2014-07-28 07:25:03 -05:00
range_swapped = children [ 0 ] - > range_swapped ;
2013-01-05 04:13:26 -06:00
range_left = children [ 0 ] - > range_left ;
range_right = children [ 0 ] - > range_right ;
}
} else {
if ( ! range_valid )
did_something = true ;
range_valid = true ;
2014-07-28 07:25:03 -05:00
range_swapped = false ;
2013-01-05 04:13:26 -06:00
range_left = 0 ;
range_right = 0 ;
}
}
2014-08-06 08:43:46 -05:00
// resolve multiranges on memory decl
if ( type = = AST_MEMORY & & children . size ( ) > 1 & & children [ 1 ] - > type = = AST_MULTIRANGE )
{
int total_size = 1 ;
multirange_dimensions . clear ( ) ;
for ( auto range : children [ 1 ] - > children ) {
if ( ! range - > range_valid )
log_error ( " Non-constant range on memory decl at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
multirange_dimensions . push_back ( std : : min ( range - > range_left , range - > range_right ) ) ;
multirange_dimensions . push_back ( std : : max ( range - > range_left , range - > range_right ) - std : : min ( range - > range_left , range - > range_right ) + 1 ) ;
total_size * = multirange_dimensions . back ( ) ;
}
delete children [ 1 ] ;
children [ 1 ] = new AstNode ( AST_RANGE , AstNode : : mkconst_int ( 0 , true ) , AstNode : : mkconst_int ( total_size - 1 , true ) ) ;
did_something = true ;
}
// resolve multiranges on memory access
if ( type = = AST_IDENTIFIER & & id2ast & & id2ast - > type = = AST_MEMORY & & children . size ( ) > 0 & & children [ 0 ] - > type = = AST_MULTIRANGE )
{
AstNode * index_expr = nullptr ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; 2 * i < GetSize ( id2ast - > multirange_dimensions ) ; i + + )
2014-08-06 08:43:46 -05:00
{
2014-10-10 09:59:44 -05:00
if ( GetSize ( children [ 0 ] - > children ) < i )
2014-08-06 08:43:46 -05:00
log_error ( " Insufficient number of array indices for %s at %s:%d. \n " , log_id ( str ) , filename . c_str ( ) , linenum ) ;
AstNode * new_index_expr = children [ 0 ] - > children [ i ] - > children . at ( 0 ) - > clone ( ) ;
if ( id2ast - > multirange_dimensions [ 2 * i ] )
new_index_expr = new AstNode ( AST_SUB , new_index_expr , AstNode : : mkconst_int ( id2ast - > multirange_dimensions [ 2 * i ] , true ) ) ;
if ( i = = 0 )
index_expr = new_index_expr ;
else
index_expr = new AstNode ( AST_ADD , new AstNode ( AST_MUL , index_expr , AstNode : : mkconst_int ( id2ast - > multirange_dimensions [ 2 * i - 1 ] , true ) ) , new_index_expr ) ;
}
2014-10-10 09:59:44 -05:00
for ( int i = GetSize ( id2ast - > multirange_dimensions ) / 1 ; i < GetSize ( children [ 0 ] - > children ) ; i + + )
2014-08-06 08:43:46 -05:00
children . push_back ( children [ 0 ] - > children [ i ] - > clone ( ) ) ;
delete children [ 0 ] ;
if ( index_expr = = nullptr )
children . erase ( children . begin ( ) ) ;
else
children [ 0 ] = new AstNode ( AST_RANGE , index_expr ) ;
did_something = true ;
}
2013-11-07 02:58:15 -06:00
// trim/extend parameters
2014-06-14 05:00:47 -05:00
if ( type = = AST_PARAMETER | | type = = AST_LOCALPARAM ) {
if ( children . size ( ) > 1 & & children [ 1 ] - > type = = AST_RANGE ) {
2014-06-14 13:38:05 -05:00
if ( ! children [ 1 ] - > range_valid )
log_error ( " Non-constant width range on parameter decl at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
int width = children [ 1 ] - > range_left - children [ 1 ] - > range_right + 1 ;
2014-06-14 05:00:47 -05:00
if ( children [ 0 ] - > type = = AST_REALVALUE ) {
2014-06-14 13:38:05 -05:00
RTLIL : : Const constvalue = children [ 0 ] - > realAsConst ( width ) ;
2014-11-09 03:44:23 -06:00
log_warning ( " converting real value %e to binary %s at %s:%d. \n " ,
2014-06-15 01:38:31 -05:00
children [ 0 ] - > realvalue , log_signal ( constvalue ) , filename . c_str ( ) , linenum ) ;
2014-06-14 05:00:47 -05:00
delete children [ 0 ] ;
2014-06-14 13:38:05 -05:00
children [ 0 ] = mkconst_bits ( constvalue . bits , sign_hint ) ;
2014-06-14 05:00:47 -05:00
did_something = true ;
}
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
if ( width ! = int ( children [ 0 ] - > bits . size ( ) ) ) {
RTLIL : : SigSpec sig ( children [ 0 ] - > bits ) ;
sig . extend_u0 ( width , children [ 0 ] - > is_signed ) ;
AstNode * old_child_0 = children [ 0 ] ;
children [ 0 ] = mkconst_bits ( sig . as_const ( ) . bits , children [ 0 ] - > is_signed ) ;
delete old_child_0 ;
}
children [ 0 ] - > is_signed = is_signed ;
}
2014-07-28 09:45:26 -05:00
range_valid = true ;
range_swapped = children [ 1 ] - > range_swapped ;
range_left = children [ 1 ] - > range_left ;
range_right = children [ 1 ] - > range_right ;
2014-06-14 05:00:47 -05:00
} else
if ( children . size ( ) > 1 & & children [ 1 ] - > type = = AST_REALVALUE & & children [ 0 ] - > type = = AST_CONSTANT ) {
double as_realvalue = children [ 0 ] - > asReal ( sign_hint ) ;
delete children [ 0 ] ;
children [ 0 ] = new AstNode ( AST_REALVALUE ) ;
children [ 0 ] - > realvalue = as_realvalue ;
did_something = true ;
2013-11-07 02:58:15 -06:00
}
}
2013-01-05 04:13:26 -06:00
// annotate identifiers using scope resolution and create auto-wires as needed
if ( type = = AST_IDENTIFIER ) {
if ( current_scope . count ( str ) = = 0 ) {
for ( auto node : current_ast_mod - > children ) {
if ( ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_WIRE | | node - > type = = AST_AUTOWIRE | | node - > type = = AST_GENVAR | |
2014-08-21 05:43:51 -05:00
node - > type = = AST_MEMORY | | node - > type = = AST_FUNCTION | | node - > type = = AST_TASK | | node - > type = = AST_DPI_FUNCTION ) & & str = = node - > str ) {
2013-01-05 04:13:26 -06:00
current_scope [ node - > str ] = node ;
break ;
}
}
}
if ( current_scope . count ( str ) = = 0 ) {
2014-11-09 03:44:23 -06:00
// log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
2013-01-05 04:13:26 -06:00
AstNode * auto_wire = new AstNode ( AST_AUTOWIRE ) ;
auto_wire - > str = str ;
current_ast_mod - > children . push_back ( auto_wire ) ;
current_scope [ str ] = auto_wire ;
did_something = true ;
}
2014-03-05 12:45:33 -06:00
if ( id2ast ! = current_scope [ str ] ) {
id2ast = current_scope [ str ] ;
did_something = true ;
}
2013-01-05 04:13:26 -06:00
}
2013-11-20 03:51:32 -06:00
// split memory access with bit select to individual statements
2014-07-17 06:13:21 -05:00
if ( type = = AST_IDENTIFIER & & children . size ( ) = = 2 & & children [ 0 ] - > type = = AST_RANGE & & children [ 1 ] - > type = = AST_RANGE & & ! in_lvalue )
2013-11-20 03:51:32 -06:00
{
2014-07-17 06:13:21 -05:00
if ( id2ast = = NULL | | id2ast - > type ! = AST_MEMORY | | children [ 0 ] - > children . size ( ) ! = 1 )
2013-11-20 03:51:32 -06:00
log_error ( " Invalid bit-select on memory access at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
int mem_width , mem_size , addr_bits ;
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $mem2bits$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2013-11-20 03:51:32 -06:00
std : : string wire_id = sstr . str ( ) ;
AstNode * wire = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire - > str = wire_id ;
if ( current_block )
wire - > attributes [ " \\ nosync " ] = AstNode : : mkconst_int ( 1 , false ) ;
current_ast_mod - > children . push_back ( wire ) ;
2014-02-14 12:56:44 -06:00
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-11-20 03:51:32 -06:00
AstNode * data = clone ( ) ;
delete data - > children [ 1 ] ;
data - > children . pop_back ( ) ;
AstNode * assign = new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER ) , data ) ;
assign - > children [ 0 ] - > str = wire_id ;
if ( current_block )
{
size_t assign_idx = 0 ;
while ( assign_idx < current_block - > children . size ( ) & & current_block - > children [ assign_idx ] ! = current_block_child )
assign_idx + + ;
log_assert ( assign_idx < current_block - > children . size ( ) ) ;
current_block - > children . insert ( current_block - > children . begin ( ) + assign_idx , assign ) ;
wire - > is_reg = true ;
}
else
{
AstNode * proc = new AstNode ( AST_ALWAYS , new AstNode ( AST_BLOCK ) ) ;
proc - > children [ 0 ] - > children . push_back ( assign ) ;
current_ast_mod - > children . push_back ( proc ) ;
}
newNode = new AstNode ( AST_IDENTIFIER , children [ 1 ] - > clone ( ) ) ;
newNode - > str = wire_id ;
newNode - > id2ast = wire ;
goto apply_newNode ;
}
2014-06-06 15:55:02 -05:00
if ( type = = AST_WHILE )
log_error ( " While loops are only allowed in constant functions at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
if ( type = = AST_REPEAT )
log_error ( " Repeat loops are only allowed in constant functions at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
2013-01-05 04:13:26 -06:00
// unroll for loops and generate-for blocks
if ( ( type = = AST_GENFOR | | type = = AST_FOR ) & & children . size ( ) ! = 0 )
{
AstNode * init_ast = children [ 0 ] ;
AstNode * while_ast = children [ 1 ] ;
AstNode * next_ast = children [ 2 ] ;
AstNode * body_ast = children [ 3 ] ;
2013-12-04 14:33:00 -06:00
while ( body_ast - > type = = AST_GENBLOCK & & body_ast - > str . empty ( ) & &
body_ast - > children . size ( ) = = 1 & & body_ast - > children . at ( 0 ) - > type = = AST_GENBLOCK )
body_ast = body_ast - > children . at ( 0 ) ;
2013-01-05 04:13:26 -06:00
if ( init_ast - > type ! = AST_ASSIGN_EQ )
log_error ( " Unsupported 1st expression of generate for-loop at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
if ( next_ast - > type ! = AST_ASSIGN_EQ )
log_error ( " Unsupported 3rd expression of generate for-loop at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
if ( type = = AST_GENFOR ) {
if ( init_ast - > children [ 0 ] - > id2ast = = NULL | | init_ast - > children [ 0 ] - > id2ast - > type ! = AST_GENVAR )
log_error ( " Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var! \n " , filename . c_str ( ) , linenum ) ;
if ( next_ast - > children [ 0 ] - > id2ast = = NULL | | next_ast - > children [ 0 ] - > id2ast - > type ! = AST_GENVAR )
log_error ( " Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var! \n " , filename . c_str ( ) , linenum ) ;
} else {
if ( init_ast - > children [ 0 ] - > id2ast = = NULL | | init_ast - > children [ 0 ] - > id2ast - > type ! = AST_WIRE )
log_error ( " Left hand side of 1st expression of generate for-loop at %s:%d is not a register! \n " , filename . c_str ( ) , linenum ) ;
if ( next_ast - > children [ 0 ] - > id2ast = = NULL | | next_ast - > children [ 0 ] - > id2ast - > type ! = AST_WIRE )
log_error ( " Left hand side of 3rd expression of generate for-loop at %s:%d is not a register! \n " , filename . c_str ( ) , linenum ) ;
}
if ( init_ast - > children [ 0 ] - > id2ast ! = next_ast - > children [ 0 ] - > id2ast )
log_error ( " Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d! \n " , filename . c_str ( ) , linenum ) ;
// eval 1st expression
AstNode * varbuf = init_ast - > children [ 1 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( varbuf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-01-05 04:13:26 -06:00
if ( varbuf - > type ! = AST_CONSTANT )
log_error ( " Right hand side of 1st expression of generate for-loop at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
varbuf = new AstNode ( AST_LOCALPARAM , varbuf ) ;
varbuf - > str = init_ast - > children [ 0 ] - > str ;
AstNode * backup_scope_varbuf = current_scope [ varbuf - > str ] ;
current_scope [ varbuf - > str ] = varbuf ;
size_t current_block_idx = 0 ;
if ( type = = AST_FOR ) {
while ( current_block_idx < current_block - > children . size ( ) & &
current_block - > children [ current_block_idx ] ! = current_block_child )
current_block_idx + + ;
}
while ( 1 )
{
// eval 2nd expression
AstNode * buf = while_ast - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-01-05 04:13:26 -06:00
if ( buf - > type ! = AST_CONSTANT )
log_error ( " 2nd expression of generate for-loop at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
if ( buf - > integer = = 0 ) {
delete buf ;
break ;
}
delete buf ;
// expand body
int index = varbuf - > children [ 0 ] - > integer ;
if ( body_ast - > type = = AST_GENBLOCK )
buf = body_ast - > clone ( ) ;
else
buf = new AstNode ( AST_GENBLOCK , body_ast - > clone ( ) ) ;
if ( buf - > str . empty ( ) ) {
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $genblock$ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
buf - > str = sstr . str ( ) ;
}
std : : map < std : : string , std : : string > name_map ;
std : : stringstream sstr ;
sstr < < buf - > str < < " [ " < < index < < " ]. " ;
buf - > expand_genblock ( varbuf - > str , sstr . str ( ) , name_map ) ;
if ( type = = AST_GENFOR ) {
2013-11-20 06:57:40 -06:00
for ( size_t i = 0 ; i < buf - > children . size ( ) ; i + + ) {
2014-02-14 12:56:44 -06:00
buf - > children [ i ] - > simplify ( false , false , false , stage , - 1 , false , false ) ;
2013-01-05 04:13:26 -06:00
current_ast_mod - > children . push_back ( buf - > children [ i ] ) ;
2013-11-20 06:57:40 -06:00
}
2013-01-05 04:13:26 -06:00
} else {
for ( size_t i = 0 ; i < buf - > children . size ( ) ; i + + )
current_block - > children . insert ( current_block - > children . begin ( ) + current_block_idx + + , buf - > children [ i ] ) ;
}
buf - > children . clear ( ) ;
delete buf ;
// eval 3rd expression
buf = next_ast - > children [ 1 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-01-05 04:13:26 -06:00
if ( buf - > type ! = AST_CONSTANT )
log_error ( " Right hand side of 3rd expression of generate for-loop at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
delete varbuf - > children [ 0 ] ;
varbuf - > children [ 0 ] = buf ;
}
current_scope [ varbuf - > str ] = backup_scope_varbuf ;
delete varbuf ;
delete_children ( ) ;
did_something = true ;
}
2013-12-04 02:10:16 -06:00
// transform block with name
if ( type = = AST_BLOCK & & ! str . empty ( ) )
{
std : : map < std : : string , std : : string > name_map ;
expand_genblock ( std : : string ( ) , str + " . " , name_map ) ;
std : : vector < AstNode * > new_children ;
for ( size_t i = 0 ; i < children . size ( ) ; i + + )
if ( children [ i ] - > type = = AST_WIRE ) {
2014-02-14 12:56:44 -06:00
children [ i ] - > simplify ( false , false , false , stage , - 1 , false , false ) ;
2013-12-04 02:10:16 -06:00
current_ast_mod - > children . push_back ( children [ i ] ) ;
2014-08-05 05:15:53 -05:00
current_scope [ children [ i ] - > str ] = children [ i ] ;
2013-12-04 02:10:16 -06:00
} else
new_children . push_back ( children [ i ] ) ;
children . swap ( new_children ) ;
did_something = true ;
str . clear ( ) ;
}
2013-03-26 03:44:54 -05:00
// simplify unconditional generate block
if ( type = = AST_GENBLOCK & & children . size ( ) ! = 0 )
{
if ( ! str . empty ( ) ) {
std : : map < std : : string , std : : string > name_map ;
expand_genblock ( std : : string ( ) , str + " . " , name_map ) ;
}
2013-11-20 06:57:40 -06:00
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
2014-02-14 12:56:44 -06:00
children [ i ] - > simplify ( false , false , false , stage , - 1 , false , false ) ;
2013-03-26 03:44:54 -05:00
current_ast_mod - > children . push_back ( children [ i ] ) ;
2013-11-20 06:57:40 -06:00
}
2013-03-26 03:44:54 -05:00
children . clear ( ) ;
did_something = true ;
}
2013-01-05 04:13:26 -06:00
// simplify generate-if blocks
if ( type = = AST_GENIF & & children . size ( ) ! = 0 )
{
AstNode * buf = children [ 0 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-01-05 04:13:26 -06:00
if ( buf - > type ! = AST_CONSTANT ) {
2013-11-07 07:08:53 -06:00
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
2013-01-05 04:13:26 -06:00
log_error ( " Condition for generate if at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
}
2013-12-04 14:06:54 -06:00
if ( buf - > asBool ( ) ! = 0 ) {
2013-01-05 04:13:26 -06:00
delete buf ;
buf = children [ 1 ] - > clone ( ) ;
} else {
delete buf ;
buf = children . size ( ) > 2 ? children [ 2 ] - > clone ( ) : NULL ;
}
if ( buf )
{
if ( buf - > type ! = AST_GENBLOCK )
buf = new AstNode ( AST_GENBLOCK , buf ) ;
if ( ! buf - > str . empty ( ) ) {
std : : map < std : : string , std : : string > name_map ;
2013-03-26 03:44:54 -05:00
buf - > expand_genblock ( std : : string ( ) , buf - > str + " . " , name_map ) ;
2013-01-05 04:13:26 -06:00
}
2013-11-20 06:57:40 -06:00
for ( size_t i = 0 ; i < buf - > children . size ( ) ; i + + ) {
2014-02-14 12:56:44 -06:00
buf - > children [ i ] - > simplify ( false , false , false , stage , - 1 , false , false ) ;
2013-01-05 04:13:26 -06:00
current_ast_mod - > children . push_back ( buf - > children [ i ] ) ;
2013-11-20 06:57:40 -06:00
}
2013-01-05 04:13:26 -06:00
buf - > children . clear ( ) ;
delete buf ;
}
delete_children ( ) ;
did_something = true ;
}
2013-12-04 14:06:54 -06:00
// simplify generate-case blocks
if ( type = = AST_GENCASE & & children . size ( ) ! = 0 )
{
AstNode * buf = children [ 0 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-12-04 14:06:54 -06:00
if ( buf - > type ! = AST_CONSTANT ) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
log_error ( " Condition for generate case at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
}
bool ref_signed = buf - > is_signed ;
RTLIL : : Const ref_value = buf - > bitsAsConst ( ) ;
delete buf ;
AstNode * selected_case = NULL ;
for ( size_t i = 1 ; i < children . size ( ) ; i + + )
{
log_assert ( children . at ( i ) - > type = = AST_COND ) ;
AstNode * this_genblock = NULL ;
for ( auto child : children . at ( i ) - > children ) {
log_assert ( this_genblock = = NULL ) ;
if ( child - > type = = AST_GENBLOCK )
this_genblock = child ;
}
for ( auto child : children . at ( i ) - > children )
{
if ( child - > type = = AST_DEFAULT ) {
if ( selected_case = = NULL )
selected_case = this_genblock ;
continue ;
}
if ( child - > type = = AST_GENBLOCK )
continue ;
buf = child - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2013-12-04 14:06:54 -06:00
if ( buf - > type ! = AST_CONSTANT ) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
log_error ( " Expression in generate case at %s:%d is not constant! \n " , filename . c_str ( ) , linenum ) ;
}
2014-07-25 06:07:31 -05:00
bool is_selected = RTLIL : : const_eq ( ref_value , buf - > bitsAsConst ( ) , ref_signed & & buf - > is_signed , ref_signed & & buf - > is_signed , 1 ) . as_bool ( ) ;
delete buf ;
if ( is_selected ) {
2013-12-04 14:06:54 -06:00
selected_case = this_genblock ;
i = children . size ( ) ;
break ;
}
}
}
if ( selected_case ! = NULL )
{
log_assert ( selected_case - > type = = AST_GENBLOCK ) ;
buf = selected_case - > clone ( ) ;
if ( ! buf - > str . empty ( ) ) {
std : : map < std : : string , std : : string > name_map ;
buf - > expand_genblock ( std : : string ( ) , buf - > str + " . " , name_map ) ;
}
for ( size_t i = 0 ; i < buf - > children . size ( ) ; i + + ) {
2014-02-14 12:56:44 -06:00
buf - > children [ i ] - > simplify ( false , false , false , stage , - 1 , false , false ) ;
2013-12-04 14:06:54 -06:00
current_ast_mod - > children . push_back ( buf - > children [ i ] ) ;
}
buf - > children . clear ( ) ;
delete buf ;
}
delete_children ( ) ;
did_something = true ;
}
2014-06-07 04:48:50 -05:00
// unroll cell arrays
if ( type = = AST_CELLARRAY )
{
if ( ! children . at ( 0 ) - > range_valid )
log_error ( " Non-constant array range on cell array at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
newNode = new AstNode ( AST_GENBLOCK ) ;
int num = std : : max ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) - std : : min ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) + 1 ;
for ( int i = 0 ; i < num ; i + + ) {
int idx = children . at ( 0 ) - > range_left > children . at ( 0 ) - > range_right ? children . at ( 0 ) - > range_right + i : children . at ( 0 ) - > range_right - i ;
AstNode * new_cell = children . at ( 1 ) - > clone ( ) ;
newNode - > children . push_back ( new_cell ) ;
new_cell - > str + = stringf ( " [%d] " , idx ) ;
if ( new_cell - > type = = AST_PRIMITIVE ) {
log_error ( " Cell arrays of primitives are currently not supported at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
} else {
log_assert ( new_cell - > children . at ( 0 ) - > type = = AST_CELLTYPE ) ;
new_cell - > children . at ( 0 ) - > str = stringf ( " $array:%d:%d:%s " , i , num , new_cell - > children . at ( 0 ) - > str . c_str ( ) ) ;
}
}
goto apply_newNode ;
}
2013-01-05 04:13:26 -06:00
// replace primitives with assignmens
if ( type = = AST_PRIMITIVE )
{
if ( children . size ( ) < 2 )
log_error ( " Insufficient number of arguments for primitive `%s' at %s:%d! \n " ,
str . c_str ( ) , filename . c_str ( ) , linenum ) ;
std : : vector < AstNode * > children_list ;
for ( auto child : children ) {
2014-07-28 04:08:55 -05:00
log_assert ( child - > type = = AST_ARGUMENT ) ;
log_assert ( child - > children . size ( ) = = 1 ) ;
2013-01-05 04:13:26 -06:00
children_list . push_back ( child - > children [ 0 ] ) ;
child - > children . clear ( ) ;
delete child ;
}
children . clear ( ) ;
2013-08-20 04:23:59 -05:00
if ( str = = " bufif0 " | | str = = " bufif1 " | | str = = " notif0 " | | str = = " notif1 " )
2013-08-19 12:50:04 -05:00
{
if ( children_list . size ( ) ! = 3 )
log_error ( " Invalid number of arguments for primitive `%s' at %s:%d! \n " ,
str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2013-01-05 04:13:26 -06:00
2013-08-19 12:50:04 -05:00
std : : vector < RTLIL : : State > z_const ( 1 , RTLIL : : State : : Sz ) ;
2013-08-20 04:23:59 -05:00
AstNode * mux_input = children_list . at ( 1 ) ;
if ( str = = " notif0 " | | str = = " notif1 " ) {
mux_input = new AstNode ( AST_BIT_NOT , mux_input ) ;
}
2013-08-19 12:50:04 -05:00
AstNode * node = new AstNode ( AST_TERNARY , children_list . at ( 2 ) ) ;
if ( str = = " bufif0 " ) {
node - > children . push_back ( AstNode : : mkconst_bits ( z_const , false ) ) ;
2013-08-20 04:23:59 -05:00
node - > children . push_back ( mux_input ) ;
2013-08-19 12:50:04 -05:00
} else {
2013-08-20 04:23:59 -05:00
node - > children . push_back ( mux_input ) ;
2013-08-19 12:50:04 -05:00
node - > children . push_back ( AstNode : : mkconst_bits ( z_const , false ) ) ;
}
str . clear ( ) ;
type = AST_ASSIGN ;
children . push_back ( children_list . at ( 0 ) ) ;
children . push_back ( node ) ;
did_something = true ;
}
else
{
AstNodeType op_type = AST_NONE ;
bool invert_results = false ;
if ( str = = " and " )
op_type = AST_BIT_AND ;
if ( str = = " nand " )
op_type = AST_BIT_AND , invert_results = true ;
if ( str = = " or " )
op_type = AST_BIT_OR ;
if ( str = = " nor " )
op_type = AST_BIT_OR , invert_results = true ;
if ( str = = " xor " )
op_type = AST_BIT_XOR ;
if ( str = = " xnor " )
op_type = AST_BIT_XOR , invert_results = true ;
if ( str = = " buf " )
op_type = AST_POS ;
if ( str = = " not " )
op_type = AST_POS , invert_results = true ;
2014-07-28 04:08:55 -05:00
log_assert ( op_type ! = AST_NONE ) ;
2013-08-19 12:50:04 -05:00
AstNode * node = children_list [ 1 ] ;
if ( op_type ! = AST_POS )
for ( size_t i = 2 ; i < children_list . size ( ) ; i + + )
node = new AstNode ( op_type , node , children_list [ i ] ) ;
if ( invert_results )
node = new AstNode ( AST_BIT_NOT , node ) ;
str . clear ( ) ;
type = AST_ASSIGN ;
children . push_back ( children_list [ 0 ] ) ;
children . push_back ( node ) ;
did_something = true ;
}
2013-01-05 04:13:26 -06:00
}
// replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with
// a big case block that selects the correct single-bit assignment.
if ( type = = AST_ASSIGN_EQ | | type = = AST_ASSIGN_LE ) {
if ( children [ 0 ] - > type ! = AST_IDENTIFIER | | children [ 0 ] - > children . size ( ) = = 0 )
goto skip_dynamic_range_lvalue_expansion ;
if ( children [ 0 ] - > children [ 0 ] - > range_valid | | did_something )
goto skip_dynamic_range_lvalue_expansion ;
if ( children [ 0 ] - > id2ast = = NULL | | children [ 0 ] - > id2ast - > type ! = AST_WIRE )
goto skip_dynamic_range_lvalue_expansion ;
if ( ! children [ 0 ] - > id2ast - > range_valid )
goto skip_dynamic_range_lvalue_expansion ;
int source_width = children [ 0 ] - > id2ast - > range_left - children [ 0 ] - > id2ast - > range_right + 1 ;
int result_width = 1 ;
AstNode * shift_expr = NULL ;
AstNode * range = children [ 0 ] - > children [ 0 ] ;
if ( range - > children . size ( ) = = 1 ) {
shift_expr = range - > children [ 0 ] - > clone ( ) ;
} else {
shift_expr = range - > children [ 1 ] - > clone ( ) ;
AstNode * left_at_zero_ast = range - > children [ 0 ] - > clone ( ) ;
AstNode * right_at_zero_ast = range - > children [ 1 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( left_at_zero_ast - > simplify ( true , true , false , stage , - 1 , false , false ) ) { }
while ( right_at_zero_ast - > simplify ( true , true , false , stage , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
if ( left_at_zero_ast - > type ! = AST_CONSTANT | | right_at_zero_ast - > type ! = AST_CONSTANT )
log_error ( " Unsupported expression on dynamic range select on signal `%s' at %s:%d! \n " ,
str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2014-10-14 16:16:50 -05:00
result_width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2013-01-05 04:13:26 -06:00
}
did_something = true ;
newNode = new AstNode ( AST_CASE , shift_expr ) ;
for ( int i = 0 ; i < = source_width - result_width ; i + + ) {
int start_bit = children [ 0 ] - > id2ast - > range_right + i ;
AstNode * cond = new AstNode ( AST_COND , mkconst_int ( start_bit , true ) ) ;
AstNode * lvalue = children [ 0 ] - > clone ( ) ;
lvalue - > delete_children ( ) ;
lvalue - > children . push_back ( new AstNode ( AST_RANGE ,
mkconst_int ( start_bit + result_width - 1 , true ) , mkconst_int ( start_bit , true ) ) ) ;
cond - > children . push_back ( new AstNode ( AST_BLOCK , new AstNode ( type , lvalue , children [ 1 ] - > clone ( ) ) ) ) ;
newNode - > children . push_back ( cond ) ;
}
goto apply_newNode ;
}
skip_dynamic_range_lvalue_expansion : ;
2014-01-19 07:03:40 -06:00
if ( stage > 1 & & type = = AST_ASSERT & & current_block ! = NULL )
{
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $assert$ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2014-01-19 07:03:40 -06:00
std : : string id_check = sstr . str ( ) + " _CHECK " , id_en = sstr . str ( ) + " _EN " ;
AstNode * wire_check = new AstNode ( AST_WIRE ) ;
wire_check - > str = id_check ;
current_ast_mod - > children . push_back ( wire_check ) ;
current_scope [ wire_check - > str ] = wire_check ;
2014-02-14 12:56:44 -06:00
while ( wire_check - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2014-01-19 07:03:40 -06:00
AstNode * wire_en = new AstNode ( AST_WIRE ) ;
wire_en - > str = id_en ;
current_ast_mod - > children . push_back ( wire_en ) ;
2014-02-04 05:46:16 -06:00
current_ast_mod - > children . push_back ( new AstNode ( AST_INITIAL , new AstNode ( AST_BLOCK , new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , AstNode : : mkconst_int ( 0 , false , 1 ) ) ) ) ) ;
current_ast_mod - > children . back ( ) - > children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > str = id_en ;
2014-01-19 07:03:40 -06:00
current_scope [ wire_en - > str ] = wire_en ;
2014-02-14 12:56:44 -06:00
while ( wire_en - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2014-01-19 07:03:40 -06:00
std : : vector < RTLIL : : State > x_bit ;
x_bit . push_back ( RTLIL : : State : : Sx ) ;
AstNode * assign_check = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( x_bit , false ) ) ;
assign_check - > children [ 0 ] - > str = id_check ;
AstNode * assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 0 , false , 1 ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
AstNode * default_signals = new AstNode ( AST_BLOCK ) ;
default_signals - > children . push_back ( assign_check ) ;
default_signals - > children . push_back ( assign_en ) ;
current_top_block - > children . insert ( current_top_block - > children . begin ( ) , default_signals ) ;
assign_check = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , new AstNode ( AST_REDUCE_BOOL , children [ 0 ] - > clone ( ) ) ) ;
assign_check - > children [ 0 ] - > str = id_check ;
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 1 , false , 1 ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
newNode = new AstNode ( AST_BLOCK ) ;
newNode - > children . push_back ( assign_check ) ;
newNode - > children . push_back ( assign_en ) ;
AstNode * assertnode = new AstNode ( AST_ASSERT ) ;
assertnode - > children . push_back ( new AstNode ( AST_IDENTIFIER ) ) ;
assertnode - > children . push_back ( new AstNode ( AST_IDENTIFIER ) ) ;
assertnode - > children [ 0 ] - > str = id_check ;
assertnode - > children [ 1 ] - > str = id_en ;
assertnode - > attributes . swap ( attributes ) ;
current_ast_mod - > children . push_back ( assertnode ) ;
goto apply_newNode ;
}
if ( stage > 1 & & type = = AST_ASSERT & & children . size ( ) = = 1 )
{
children [ 0 ] = new AstNode ( AST_REDUCE_BOOL , children [ 0 ] - > clone ( ) ) ;
children . push_back ( mkconst_int ( 1 , false , 1 ) ) ;
did_something = true ;
}
2013-01-05 04:13:26 -06:00
// found right-hand side identifier for memory -> replace with memory read port
if ( stage > 1 & & type = = AST_IDENTIFIER & & id2ast ! = NULL & & id2ast - > type = = AST_MEMORY & & ! in_lvalue & &
children [ 0 ] - > type = = AST_RANGE & & children [ 0 ] - > children . size ( ) = = 1 ) {
newNode = new AstNode ( AST_MEMRD , children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
newNode - > str = str ;
2013-11-03 23:04:42 -06:00
newNode - > id2ast = id2ast ;
2013-01-05 04:13:26 -06:00
goto apply_newNode ;
}
// assignment with memory in left-hand side expression -> replace with memory write port
if ( stage > 1 & & ( type = = AST_ASSIGN_EQ | | type = = AST_ASSIGN_LE ) & & children [ 0 ] - > type = = AST_IDENTIFIER & &
2014-07-17 06:13:21 -05:00
children [ 0 ] - > id2ast & & children [ 0 ] - > id2ast - > type = = AST_MEMORY & & children [ 0 ] - > id2ast - > children . size ( ) > = 2 & &
children [ 0 ] - > id2ast - > children [ 0 ] - > range_valid & & children [ 0 ] - > id2ast - > children [ 1 ] - > range_valid & &
2014-08-06 08:43:46 -05:00
( children [ 0 ] - > children . size ( ) = = 1 | | children [ 0 ] - > children . size ( ) = = 2 ) & & children [ 0 ] - > children [ 0 ] - > type = = AST_RANGE )
2013-01-05 04:13:26 -06:00
{
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $memwr$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
std : : string id_addr = sstr . str ( ) + " _ADDR " , id_data = sstr . str ( ) + " _DATA " , id_en = sstr . str ( ) + " _EN " ;
2015-01-15 05:41:52 -06:00
if ( type = = AST_ASSIGN_EQ ) {
pair < string , int > this_blocking_assignment_warn ( filename , linenum ) ;
if ( this_blocking_assignment_warn ! = last_blocking_assignment_warn )
log_warning ( " Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment. \n " ,
filename . c_str ( ) , linenum ) ;
last_blocking_assignment_warn = this_blocking_assignment_warn ;
}
2013-01-05 04:13:26 -06:00
int mem_width , mem_size , addr_bits ;
children [ 0 ] - > id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
AstNode * wire_addr = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( addr_bits - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_addr - > str = id_addr ;
current_ast_mod - > children . push_back ( wire_addr ) ;
current_scope [ wire_addr - > str ] = wire_addr ;
2014-02-14 12:56:44 -06:00
while ( wire_addr - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
AstNode * wire_data = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_data - > str = id_data ;
current_ast_mod - > children . push_back ( wire_data ) ;
current_scope [ wire_data - > str ] = wire_data ;
2014-02-14 12:56:44 -06:00
while ( wire_data - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
2014-07-16 05:23:47 -05:00
AstNode * wire_en = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
2013-01-05 04:13:26 -06:00
wire_en - > str = id_en ;
current_ast_mod - > children . push_back ( wire_en ) ;
current_scope [ wire_en - > str ] = wire_en ;
2014-02-14 12:56:44 -06:00
while ( wire_en - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
2014-07-16 05:23:47 -05:00
std : : vector < RTLIL : : State > x_bits_addr , x_bits_data , set_bits_en ;
2014-02-22 10:08:00 -06:00
for ( int i = 0 ; i < addr_bits ; i + + )
x_bits_addr . push_back ( RTLIL : : State : : Sx ) ;
2013-11-18 12:55:12 -06:00
for ( int i = 0 ; i < mem_width ; i + + )
2014-02-22 10:08:00 -06:00
x_bits_data . push_back ( RTLIL : : State : : Sx ) ;
2014-07-16 05:23:47 -05:00
for ( int i = 0 ; i < mem_width ; i + + )
set_bits_en . push_back ( RTLIL : : State : : S1 ) ;
2013-01-05 04:13:26 -06:00
2014-02-22 10:08:00 -06:00
AstNode * assign_addr = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( x_bits_addr , false ) ) ;
2013-01-05 04:13:26 -06:00
assign_addr - > children [ 0 ] - > str = id_addr ;
2014-02-22 10:08:00 -06:00
AstNode * assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( x_bits_data , false ) ) ;
2013-01-05 04:13:26 -06:00
assign_data - > children [ 0 ] - > str = id_data ;
2014-07-16 05:23:47 -05:00
AstNode * assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 0 , false , mem_width ) ) ;
2013-01-05 04:13:26 -06:00
assign_en - > children [ 0 ] - > str = id_en ;
AstNode * default_signals = new AstNode ( AST_BLOCK ) ;
default_signals - > children . push_back ( assign_addr ) ;
default_signals - > children . push_back ( assign_data ) ;
default_signals - > children . push_back ( assign_en ) ;
current_top_block - > children . insert ( current_top_block - > children . begin ( ) , default_signals ) ;
assign_addr = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
assign_addr - > children [ 0 ] - > str = id_addr ;
2014-07-17 06:13:21 -05:00
if ( children [ 0 ] - > children . size ( ) = = 2 )
{
if ( children [ 0 ] - > children [ 1 ] - > range_valid )
{
int offset = children [ 0 ] - > children [ 1 ] - > range_right ;
int width = children [ 0 ] - > children [ 1 ] - > range_left - offset + 1 ;
2013-01-05 04:13:26 -06:00
2014-07-17 06:13:21 -05:00
std : : vector < RTLIL : : State > padding_x ( offset , RTLIL : : State : : Sx ) ;
for ( int i = 0 ; i < mem_width ; i + + )
set_bits_en [ i ] = offset < = i & & i < offset + width ? RTLIL : : State : : S1 : RTLIL : : State : : S0 ;
assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) ,
new AstNode ( AST_CONCAT , mkconst_bits ( padding_x , false ) , children [ 1 ] - > clone ( ) ) ) ;
assign_data - > children [ 0 ] - > str = id_data ;
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( set_bits_en , false ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
}
else
{
2014-07-17 09:49:23 -05:00
AstNode * the_range = children [ 0 ] - > children [ 1 ] ;
AstNode * left_at_zero_ast = the_range - > children [ 0 ] - > clone ( ) ;
AstNode * right_at_zero_ast = the_range - > children . size ( ) > = 2 ? the_range - > children [ 1 ] - > clone ( ) : left_at_zero_ast - > clone ( ) ;
AstNode * offset_ast = right_at_zero_ast - > clone ( ) ;
while ( left_at_zero_ast - > simplify ( true , true , false , 1 , - 1 , false , false ) ) { }
while ( right_at_zero_ast - > simplify ( true , true , false , 1 , - 1 , false , false ) ) { }
if ( left_at_zero_ast - > type ! = AST_CONSTANT | | right_at_zero_ast - > type ! = AST_CONSTANT )
log_error ( " Unsupported expression on dynamic range select on signal `%s' at %s:%d! \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
int width = left_at_zero_ast - > integer - right_at_zero_ast - > integer + 1 ;
for ( int i = 0 ; i < mem_width ; i + + )
set_bits_en [ i ] = i < width ? RTLIL : : State : : S1 : RTLIL : : State : : S0 ;
assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) ,
new AstNode ( AST_SHIFT_LEFT , children [ 1 ] - > clone ( ) , offset_ast - > clone ( ) ) ) ;
assign_data - > children [ 0 ] - > str = id_data ;
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) ,
new AstNode ( AST_SHIFT_LEFT , mkconst_bits ( set_bits_en , false ) , offset_ast - > clone ( ) ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
delete left_at_zero_ast ;
delete right_at_zero_ast ;
delete offset_ast ;
2014-07-17 06:13:21 -05:00
}
}
else
{
assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , children [ 1 ] - > clone ( ) ) ;
assign_data - > children [ 0 ] - > str = id_data ;
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( set_bits_en , false ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
}
2013-01-05 04:13:26 -06:00
newNode = new AstNode ( AST_BLOCK ) ;
newNode - > children . push_back ( assign_addr ) ;
newNode - > children . push_back ( assign_data ) ;
newNode - > children . push_back ( assign_en ) ;
AstNode * wrnode = new AstNode ( AST_MEMWR ) ;
wrnode - > children . push_back ( new AstNode ( AST_IDENTIFIER ) ) ;
wrnode - > children . push_back ( new AstNode ( AST_IDENTIFIER ) ) ;
wrnode - > children . push_back ( new AstNode ( AST_IDENTIFIER ) ) ;
wrnode - > str = children [ 0 ] - > str ;
wrnode - > children [ 0 ] - > str = id_addr ;
wrnode - > children [ 1 ] - > str = id_data ;
wrnode - > children [ 2 ] - > str = id_en ;
current_ast_mod - > children . push_back ( wrnode ) ;
goto apply_newNode ;
}
// replace function and task calls with the code from the function or task
if ( ( type = = AST_FCALL | | type = = AST_TCALL ) & & ! str . empty ( ) )
{
2013-12-04 14:19:54 -06:00
if ( type = = AST_FCALL )
{
if ( str = = " \\ $clog2 " )
{
2014-06-14 06:36:23 -05:00
if ( children . size ( ) ! = 1 )
log_error ( " System function %s got %d arguments, expected 1 at %s:%d. \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) , filename . c_str ( ) , linenum ) ;
2014-06-14 06:36:23 -05:00
2013-12-04 14:19:54 -06:00
AstNode * buf = children [ 0 ] - > clone ( ) ;
2014-02-14 12:56:44 -06:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2014-01-12 14:04:42 -06:00
if ( buf - > type ! = AST_CONSTANT )
2013-12-04 14:19:54 -06:00
log_error ( " Failed to evaluate system function `%s' with non-constant value at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
RTLIL : : Const arg_value = buf - > bitsAsConst ( ) ;
2014-09-08 05:25:23 -05:00
if ( arg_value . as_bool ( ) )
2014-10-10 09:59:44 -05:00
arg_value = const_sub ( arg_value , 1 , false , false , GetSize ( arg_value ) ) ;
2014-07-25 06:07:31 -05:00
delete buf ;
2013-12-04 14:19:54 -06:00
uint32_t result = 0 ;
for ( size_t i = 0 ; i < arg_value . bits . size ( ) ; i + + )
if ( arg_value . bits . at ( i ) = = RTLIL : : State : : S1 )
2014-09-06 12:31:04 -05:00
result = i + 1 ;
2013-12-04 14:19:54 -06:00
newNode = mkconst_int ( result , false ) ;
goto apply_newNode ;
2013-11-20 04:05:58 -06:00
}
2013-12-04 14:19:54 -06:00
2014-06-14 06:36:23 -05:00
if ( str = = " \\ $ln " | | str = = " \\ $log10 " | | str = = " \\ $exp " | | str = = " \\ $sqrt " | | str = = " \\ $pow " | |
str = = " \\ $floor " | | str = = " \\ $ceil " | | str = = " \\ $sin " | | str = = " \\ $cos " | | str = = " \\ $tan " | |
str = = " \\ $asin " | | str = = " \\ $acos " | | str = = " \\ $atan " | | str = = " \\ $atan2 " | | str = = " \\ $hypot " | |
str = = " \\ $sinh " | | str = = " \\ $cosh " | | str = = " \\ $tanh " | | str = = " \\ $asinh " | | str = = " \\ $acosh " | | str = = " \\ $atanh " )
{
bool func_with_two_arguments = str = = " \\ $pow " | | str = = " \\ $atan2 " | | str = = " \\ $hypot " ;
double x = 0 , y = 0 ;
if ( func_with_two_arguments ) {
if ( children . size ( ) ! = 2 )
log_error ( " System function %s got %d arguments, expected 2 at %s:%d. \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) , filename . c_str ( ) , linenum ) ;
2014-06-14 06:36:23 -05:00
} else {
if ( children . size ( ) ! = 1 )
log_error ( " System function %s got %d arguments, expected 1 at %s:%d. \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) , filename . c_str ( ) , linenum ) ;
2014-06-14 06:36:23 -05:00
}
if ( children . size ( ) > = 1 ) {
while ( children [ 0 ] - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( ! children [ 0 ] - > isConst ( ) )
log_error ( " Failed to evaluate system function `%s' with non-constant argument at %s:%d. \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , filename . c_str ( ) , linenum ) ;
2014-06-14 06:36:23 -05:00
int child_width_hint = width_hint ;
bool child_sign_hint = sign_hint ;
children [ 0 ] - > detectSignWidth ( child_width_hint , child_sign_hint ) ;
x = children [ 0 ] - > asReal ( child_sign_hint ) ;
}
if ( children . size ( ) > = 2 ) {
while ( children [ 1 ] - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( ! children [ 1 ] - > isConst ( ) )
log_error ( " Failed to evaluate system function `%s' with non-constant argument at %s:%d. \n " ,
2014-08-02 09:03:18 -05:00
RTLIL : : unescape_id ( str ) . c_str ( ) , filename . c_str ( ) , linenum ) ;
2014-06-14 06:36:23 -05:00
int child_width_hint = width_hint ;
bool child_sign_hint = sign_hint ;
children [ 1 ] - > detectSignWidth ( child_width_hint , child_sign_hint ) ;
y = children [ 1 ] - > asReal ( child_sign_hint ) ;
}
newNode = new AstNode ( AST_REALVALUE ) ;
2014-07-31 06:19:47 -05:00
if ( str = = " \\ $ln " ) newNode - > realvalue = : : log ( x ) ;
else if ( str = = " \\ $log10 " ) newNode - > realvalue = : : log10 ( x ) ;
else if ( str = = " \\ $exp " ) newNode - > realvalue = : : exp ( x ) ;
else if ( str = = " \\ $sqrt " ) newNode - > realvalue = : : sqrt ( x ) ;
else if ( str = = " \\ $pow " ) newNode - > realvalue = : : pow ( x , y ) ;
else if ( str = = " \\ $floor " ) newNode - > realvalue = : : floor ( x ) ;
else if ( str = = " \\ $ceil " ) newNode - > realvalue = : : ceil ( x ) ;
else if ( str = = " \\ $sin " ) newNode - > realvalue = : : sin ( x ) ;
else if ( str = = " \\ $cos " ) newNode - > realvalue = : : cos ( x ) ;
else if ( str = = " \\ $tan " ) newNode - > realvalue = : : tan ( x ) ;
else if ( str = = " \\ $asin " ) newNode - > realvalue = : : asin ( x ) ;
else if ( str = = " \\ $acos " ) newNode - > realvalue = : : acos ( x ) ;
else if ( str = = " \\ $atan " ) newNode - > realvalue = : : atan ( x ) ;
else if ( str = = " \\ $atan2 " ) newNode - > realvalue = : : atan2 ( x , y ) ;
else if ( str = = " \\ $hypot " ) newNode - > realvalue = : : hypot ( x , y ) ;
else if ( str = = " \\ $sinh " ) newNode - > realvalue = : : sinh ( x ) ;
else if ( str = = " \\ $cosh " ) newNode - > realvalue = : : cosh ( x ) ;
else if ( str = = " \\ $tanh " ) newNode - > realvalue = : : tanh ( x ) ;
else if ( str = = " \\ $asinh " ) newNode - > realvalue = : : asinh ( x ) ;
else if ( str = = " \\ $acosh " ) newNode - > realvalue = : : acosh ( x ) ;
else if ( str = = " \\ $atanh " ) newNode - > realvalue = : : atanh ( x ) ;
2014-06-14 06:36:23 -05:00
else log_abort ( ) ;
goto apply_newNode ;
}
2014-08-21 05:43:51 -05:00
if ( current_scope . count ( str ) ! = 0 & & current_scope [ str ] - > type = = AST_DPI_FUNCTION )
{
AstNode * dpi_decl = current_scope [ str ] ;
std : : string rtype , fname ;
std : : vector < std : : string > argtypes ;
std : : vector < AstNode * > args ;
rtype = RTLIL : : unescape_id ( dpi_decl - > children . at ( 0 ) - > str ) ;
2014-08-21 10:22:04 -05:00
fname = RTLIL : : unescape_id ( dpi_decl - > children . at ( 1 ) - > str ) ;
2014-08-21 05:43:51 -05:00
2014-10-10 09:59:44 -05:00
for ( int i = 2 ; i < GetSize ( dpi_decl - > children ) ; i + + )
2014-08-21 05:43:51 -05:00
{
2014-10-10 09:59:44 -05:00
if ( i - 2 > = GetSize ( children ) )
2014-08-21 05:43:51 -05:00
log_error ( " Insufficient number of arguments in DPI function call at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
argtypes . push_back ( RTLIL : : unescape_id ( dpi_decl - > children . at ( i ) - > str ) ) ;
2014-08-21 10:22:04 -05:00
args . push_back ( children . at ( i - 2 ) - > clone ( ) ) ;
2014-08-21 05:43:51 -05:00
while ( args . back ( ) - > simplify ( true , false , false , stage , - 1 , false , true ) ) { }
if ( args . back ( ) - > type ! = AST_CONSTANT & & args . back ( ) - > type ! = AST_REALVALUE )
log_error ( " Failed to evaluate DPI function with non-constant argument at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
}
newNode = dpi_call ( rtype , fname , argtypes , args ) ;
2014-08-21 06:09:47 -05:00
for ( auto arg : args )
delete arg ;
2014-08-21 05:43:51 -05:00
goto apply_newNode ;
}
2013-12-04 14:19:54 -06:00
if ( current_scope . count ( str ) = = 0 | | current_scope [ str ] - > type ! = AST_FUNCTION )
log_error ( " Can't resolve function name `%s' at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2013-01-05 04:13:26 -06:00
}
if ( type = = AST_TCALL ) {
2014-10-26 14:33:10 -05:00
if ( str = = " \\ $readmemh " | | str = = " \\ $readmemb " )
{
if ( GetSize ( children ) < 2 | | GetSize ( children ) > 4 )
log_error ( " System function %s got %d arguments, expected 2-4 at %s:%d. \n " ,
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) , filename . c_str ( ) , linenum ) ;
AstNode * node_filename = children [ 0 ] - > clone ( ) ;
while ( node_filename - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_filename - > type ! = AST_CONSTANT )
log_error ( " Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
AstNode * node_memory = children [ 1 ] - > clone ( ) ;
while ( node_memory - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_memory - > type ! = AST_IDENTIFIER | | node_memory - > id2ast = = nullptr | | node_memory - > id2ast - > type ! = AST_MEMORY )
log_error ( " Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
int start_addr = - 1 , finish_addr = - 1 ;
if ( GetSize ( children ) > 2 ) {
AstNode * node_addr = children [ 2 ] - > clone ( ) ;
while ( node_addr - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_addr - > type ! = AST_CONSTANT )
log_error ( " Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
start_addr = node_addr - > asInt ( false ) ;
}
if ( GetSize ( children ) > 3 ) {
AstNode * node_addr = children [ 3 ] - > clone ( ) ;
while ( node_addr - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_addr - > type ! = AST_CONSTANT )
log_error ( " Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
finish_addr = node_addr - > asInt ( false ) ;
}
newNode = readmem ( str = = " \\ $readmemh " , node_filename - > bitsAsConst ( ) . decode_string ( ) , node_memory - > id2ast , start_addr , finish_addr ) ;
goto apply_newNode ;
}
2013-01-05 04:13:26 -06:00
if ( current_scope . count ( str ) = = 0 | | current_scope [ str ] - > type ! = AST_TASK )
log_error ( " Can't resolve task name `%s' at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
}
2014-08-18 07:29:30 -05:00
AstNode * decl = current_scope [ str ] ;
std : : stringstream sstr ;
sstr < < " $func$ " < < str < < " $ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) < < " $ " ;
std : : string prefix = sstr . str ( ) ;
2014-06-06 17:02:05 -05:00
bool recommend_const_eval = false ;
bool require_const_eval = in_param ? false : has_const_only_constructs ( recommend_const_eval ) ;
2014-08-18 07:29:30 -05:00
if ( ( in_param | | recommend_const_eval | | require_const_eval ) & & ! decl - > attributes . count ( " \\ via_celltype " ) )
2014-02-14 12:56:44 -06:00
{
bool all_args_const = true ;
2014-02-16 06:16:38 -06:00
for ( auto child : children ) {
while ( child - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
2014-02-14 12:56:44 -06:00
if ( child - > type ! = AST_CONSTANT )
all_args_const = false ;
2014-02-16 06:16:38 -06:00
}
2014-02-14 12:56:44 -06:00
if ( all_args_const ) {
AstNode * func_workspace = current_scope [ str ] - > clone ( ) ;
newNode = func_workspace - > eval_const_function ( this ) ;
delete func_workspace ;
goto apply_newNode ;
}
2014-06-06 15:55:02 -05:00
if ( in_param )
log_error ( " Non-constant function call in constant expression at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
2014-06-06 17:02:05 -05:00
if ( require_const_eval )
2014-06-06 15:55:02 -05:00
log_error ( " Function %s can only be called with constant arguments at %s:%d. \n " , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2014-02-14 12:56:44 -06:00
}
2013-01-05 04:13:26 -06:00
size_t arg_count = 0 ;
std : : map < std : : string , std : : string > replace_rules ;
if ( current_block = = NULL )
{
2014-07-28 04:08:55 -05:00
log_assert ( type = = AST_FCALL ) ;
2013-01-05 04:13:26 -06:00
AstNode * wire = NULL ;
for ( auto child : decl - > children )
if ( child - > type = = AST_WIRE & & child - > str = = str )
wire = child - > clone ( ) ;
2014-07-28 04:08:55 -05:00
log_assert ( wire ! = NULL ) ;
2013-01-05 04:13:26 -06:00
wire - > str = prefix + str ;
wire - > port_id = 0 ;
wire - > is_input = false ;
wire - > is_output = false ;
current_ast_mod - > children . push_back ( wire ) ;
2014-02-14 12:56:44 -06:00
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
AstNode * lvalue = new AstNode ( AST_IDENTIFIER ) ;
lvalue - > str = wire - > str ;
AstNode * always = new AstNode ( AST_ALWAYS , new AstNode ( AST_BLOCK ,
new AstNode ( AST_ASSIGN_EQ , lvalue , clone ( ) ) ) ) ;
current_ast_mod - > children . push_back ( always ) ;
goto replace_fcall_with_id ;
}
2014-08-18 07:29:30 -05:00
if ( decl - > attributes . count ( " \\ via_celltype " ) )
{
std : : string celltype = decl - > attributes . at ( " \\ via_celltype " ) - > asAttrConst ( ) . decode_string ( ) ;
std : : string outport = str ;
if ( celltype . find ( ' ' ) ! = std : : string : : npos ) {
int pos = celltype . find ( ' ' ) ;
outport = RTLIL : : escape_id ( celltype . substr ( pos + 1 ) ) ;
celltype = RTLIL : : escape_id ( celltype . substr ( 0 , pos ) ) ;
} else
celltype = RTLIL : : escape_id ( celltype ) ;
AstNode * cell = new AstNode ( AST_CELL , new AstNode ( AST_CELLTYPE ) ) ;
2014-10-10 09:59:44 -05:00
cell - > str = prefix . substr ( 0 , GetSize ( prefix ) - 1 ) ;
2014-08-18 07:29:30 -05:00
cell - > children [ 0 ] - > str = celltype ;
for ( auto attr : decl - > attributes )
if ( attr . first . str ( ) . rfind ( " \\ via_celltype_defparam_ " , 0 ) = = 0 )
{
AstNode * cell_arg = new AstNode ( AST_PARASET , attr . second - > clone ( ) ) ;
cell_arg - > str = RTLIL : : escape_id ( attr . first . str ( ) . substr ( strlen ( " \\ via_celltype_defparam_ " ) ) ) ;
cell - > children . push_back ( cell_arg ) ;
}
for ( auto child : decl - > children )
if ( child - > type = = AST_WIRE & & ( child - > is_input | | child - > is_output | | ( type = = AST_FCALL & & child - > str = = str ) ) )
{
AstNode * wire = child - > clone ( ) ;
wire - > str = prefix + wire - > str ;
wire - > port_id = 0 ;
wire - > is_input = false ;
wire - > is_output = false ;
current_ast_mod - > children . push_back ( wire ) ;
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * wire_id = new AstNode ( AST_IDENTIFIER ) ;
wire_id - > str = wire - > str ;
if ( ( child - > is_input | | child - > is_output ) & & arg_count < children . size ( ) )
{
AstNode * arg = children [ arg_count + + ] - > clone ( ) ;
AstNode * assign = child - > is_input ?
2014-08-21 10:33:40 -05:00
new AstNode ( AST_ASSIGN_EQ , wire_id - > clone ( ) , arg ) :
new AstNode ( AST_ASSIGN_EQ , arg , wire_id - > clone ( ) ) ;
2014-08-18 07:29:30 -05:00
for ( auto it = current_block - > children . begin ( ) ; it ! = current_block - > children . end ( ) ; it + + ) {
if ( * it ! = current_block_child )
continue ;
current_block - > children . insert ( it , assign ) ;
break ;
}
}
2014-08-21 10:33:40 -05:00
AstNode * cell_arg = new AstNode ( AST_ARGUMENT , wire_id ) ;
2014-08-18 07:29:30 -05:00
cell_arg - > str = child - > str = = str ? outport : child - > str ;
cell - > children . push_back ( cell_arg ) ;
}
current_ast_mod - > children . push_back ( cell ) ;
goto replace_fcall_with_id ;
}
2013-01-05 04:13:26 -06:00
for ( auto child : decl - > children )
if ( child - > type = = AST_WIRE )
{
AstNode * wire = child - > clone ( ) ;
wire - > str = prefix + wire - > str ;
wire - > port_id = 0 ;
wire - > is_input = false ;
wire - > is_output = false ;
current_ast_mod - > children . push_back ( wire ) ;
2014-02-14 12:56:44 -06:00
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
replace_rules [ child - > str ] = wire - > str ;
2014-08-14 15:26:10 -05:00
if ( ( child - > is_input | | child - > is_output ) & & arg_count < children . size ( ) )
2013-01-05 04:13:26 -06:00
{
AstNode * arg = children [ arg_count + + ] - > clone ( ) ;
AstNode * wire_id = new AstNode ( AST_IDENTIFIER ) ;
wire_id - > str = wire - > str ;
2014-08-14 15:26:10 -05:00
AstNode * assign = child - > is_input ?
new AstNode ( AST_ASSIGN_EQ , wire_id , arg ) :
new AstNode ( AST_ASSIGN_EQ , arg , wire_id ) ;
2013-01-05 04:13:26 -06:00
for ( auto it = current_block - > children . begin ( ) ; it ! = current_block - > children . end ( ) ; it + + ) {
if ( * it ! = current_block_child )
continue ;
current_block - > children . insert ( it , assign ) ;
break ;
}
}
}
2014-08-05 01:35:51 -05:00
for ( auto child : decl - > children )
if ( child - > type ! = AST_WIRE )
2013-01-05 04:13:26 -06:00
{
AstNode * stmt = child - > clone ( ) ;
2014-08-05 05:15:53 -05:00
stmt - > replace_ids ( prefix , replace_rules ) ;
2013-01-05 04:13:26 -06:00
for ( auto it = current_block - > children . begin ( ) ; it ! = current_block - > children . end ( ) ; it + + ) {
if ( * it ! = current_block_child )
continue ;
current_block - > children . insert ( it , stmt ) ;
break ;
}
}
replace_fcall_with_id :
if ( type = = AST_FCALL ) {
delete_children ( ) ;
type = AST_IDENTIFIER ;
str = prefix + str ;
}
if ( type = = AST_TCALL )
str = " " ;
did_something = true ;
}
// perform const folding when activated
2014-08-17 17:02:30 -05:00
if ( const_fold )
2013-01-05 04:13:26 -06:00
{
2013-12-05 06:26:17 -06:00
bool string_op ;
2013-06-10 06:56:03 -05:00
std : : vector < RTLIL : : State > tmp_bits ;
2013-01-05 04:13:26 -06:00
RTLIL : : Const ( * const_func ) ( const RTLIL : : Const & , const RTLIL : : Const & , bool , bool , int ) ;
RTLIL : : Const dummy_arg ;
switch ( type )
{
case AST_IDENTIFIER :
if ( current_scope . count ( str ) > 0 & & ( current_scope [ str ] - > type = = AST_PARAMETER | | current_scope [ str ] - > type = = AST_LOCALPARAM ) ) {
2013-11-07 07:08:53 -06:00
if ( current_scope [ str ] - > children [ 0 ] - > type = = AST_CONSTANT ) {
if ( children . size ( ) ! = 0 & & children [ 0 ] - > type = = AST_RANGE & & children [ 0 ] - > range_valid ) {
2013-01-05 04:13:26 -06:00
std : : vector < RTLIL : : State > data ;
2014-07-28 09:45:26 -05:00
bool param_upto = current_scope [ str ] - > range_valid & & current_scope [ str ] - > range_swapped ;
int param_offset = current_scope [ str ] - > range_valid ? current_scope [ str ] - > range_right : 0 ;
int param_width = current_scope [ str ] - > range_valid ? current_scope [ str ] - > range_left - current_scope [ str ] - > range_right + 1 :
2014-10-10 09:59:44 -05:00
GetSize ( current_scope [ str ] - > children [ 0 ] - > bits ) ;
2014-07-28 09:45:26 -05:00
int tmp_range_left = children [ 0 ] - > range_left , tmp_range_right = children [ 0 ] - > range_right ;
if ( param_upto ) {
tmp_range_left = ( param_width + 2 * param_offset ) - children [ 0 ] - > range_right - 1 ;
tmp_range_right = ( param_width + 2 * param_offset ) - children [ 0 ] - > range_left - 1 ;
}
for ( int i = tmp_range_right ; i < = tmp_range_left ; i + + ) {
int index = i - param_offset ;
if ( 0 < = index & & index < param_width )
data . push_back ( current_scope [ str ] - > children [ 0 ] - > bits [ index ] ) ;
else
data . push_back ( RTLIL : : State : : Sx ) ;
}
2013-01-05 04:13:26 -06:00
newNode = mkconst_bits ( data , false ) ;
2013-11-07 07:08:53 -06:00
} else
if ( children . size ( ) = = 0 )
newNode = current_scope [ str ] - > children [ 0 ] - > clone ( ) ;
2014-06-14 04:27:05 -05:00
} else
if ( current_scope [ str ] - > children [ 0 ] - > isConst ( ) )
newNode = current_scope [ str ] - > children [ 0 ] - > clone ( ) ;
2013-01-05 04:13:26 -06:00
}
2013-11-07 04:25:19 -06:00
else if ( at_zero & & current_scope . count ( str ) > 0 & & ( current_scope [ str ] - > type = = AST_WIRE | | current_scope [ str ] - > type = = AST_AUTOWIRE ) ) {
newNode = mkconst_int ( 0 , sign_hint , width_hint ) ;
2013-01-05 04:13:26 -06:00
}
break ;
case AST_BIT_NOT :
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
RTLIL : : Const y = RTLIL : : const_not ( children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) , dummy_arg , sign_hint , false , width_hint ) ;
newNode = mkconst_bits ( y . bits , sign_hint ) ;
2013-01-05 04:13:26 -06:00
}
break ;
2013-12-05 06:09:41 -06:00
case AST_TO_SIGNED :
case AST_TO_UNSIGNED :
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
RTLIL : : Const y = children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) ;
newNode = mkconst_bits ( y . bits , type = = AST_TO_SIGNED ) ;
}
break ;
2013-01-05 04:13:26 -06:00
if ( 0 ) { case AST_BIT_AND : const_func = RTLIL : : const_and ; }
if ( 0 ) { case AST_BIT_OR : const_func = RTLIL : : const_or ; }
if ( 0 ) { case AST_BIT_XOR : const_func = RTLIL : : const_xor ; }
if ( 0 ) { case AST_BIT_XNOR : const_func = RTLIL : : const_xnor ; }
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 1 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
RTLIL : : Const y = const_func ( children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) ,
children [ 1 ] - > bitsAsConst ( width_hint , sign_hint ) , sign_hint , sign_hint , width_hint ) ;
newNode = mkconst_bits ( y . bits , sign_hint ) ;
2013-01-05 04:13:26 -06:00
}
break ;
if ( 0 ) { case AST_REDUCE_AND : const_func = RTLIL : : const_reduce_and ; }
if ( 0 ) { case AST_REDUCE_OR : const_func = RTLIL : : const_reduce_or ; }
if ( 0 ) { case AST_REDUCE_XOR : const_func = RTLIL : : const_reduce_xor ; }
if ( 0 ) { case AST_REDUCE_XNOR : const_func = RTLIL : : const_reduce_xnor ; }
if ( 0 ) { case AST_REDUCE_BOOL : const_func = RTLIL : : const_reduce_bool ; }
2013-06-10 06:19:04 -05:00
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
RTLIL : : Const y = const_func ( RTLIL : : Const ( children [ 0 ] - > bits ) , dummy_arg , false , false , - 1 ) ;
2013-01-05 04:13:26 -06:00
newNode = mkconst_bits ( y . bits , false ) ;
}
break ;
case AST_LOGIC_NOT :
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
RTLIL : : Const y = RTLIL : : const_logic_not ( RTLIL : : Const ( children [ 0 ] - > bits ) , dummy_arg , children [ 0 ] - > is_signed , false , - 1 ) ;
newNode = mkconst_bits ( y . bits , false ) ;
2014-06-14 04:27:05 -05:00
} else
if ( children [ 0 ] - > isConst ( ) ) {
newNode = mkconst_int ( children [ 0 ] - > asReal ( sign_hint ) = = 0 , false , 1 ) ;
2013-01-05 04:13:26 -06:00
}
break ;
if ( 0 ) { case AST_LOGIC_AND : const_func = RTLIL : : const_logic_and ; }
if ( 0 ) { case AST_LOGIC_OR : const_func = RTLIL : : const_logic_or ; }
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 1 ] - > type = = AST_CONSTANT ) {
RTLIL : : Const y = const_func ( RTLIL : : Const ( children [ 0 ] - > bits ) , RTLIL : : Const ( children [ 1 ] - > bits ) ,
children [ 0 ] - > is_signed , children [ 1 ] - > is_signed , - 1 ) ;
newNode = mkconst_bits ( y . bits , false ) ;
2014-06-14 04:27:05 -05:00
} else
if ( children [ 0 ] - > isConst ( ) & & children [ 1 ] - > isConst ( ) ) {
if ( type = = AST_LOGIC_AND )
newNode = mkconst_int ( ( children [ 0 ] - > asReal ( sign_hint ) ! = 0 ) & & ( children [ 1 ] - > asReal ( sign_hint ) ! = 0 ) , false , 1 ) ;
else
newNode = mkconst_int ( ( children [ 0 ] - > asReal ( sign_hint ) ! = 0 ) | | ( children [ 1 ] - > asReal ( sign_hint ) ! = 0 ) , false , 1 ) ;
2013-01-05 04:13:26 -06:00
}
break ;
if ( 0 ) { case AST_SHIFT_LEFT : const_func = RTLIL : : const_shl ; }
if ( 0 ) { case AST_SHIFT_RIGHT : const_func = RTLIL : : const_shr ; }
if ( 0 ) { case AST_SHIFT_SLEFT : const_func = RTLIL : : const_sshl ; }
if ( 0 ) { case AST_SHIFT_SRIGHT : const_func = RTLIL : : const_sshr ; }
2013-11-07 15:20:00 -06:00
if ( 0 ) { case AST_POW : const_func = RTLIL : : const_pow ; }
2013-01-05 04:13:26 -06:00
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 1 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
RTLIL : : Const y = const_func ( children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) ,
2013-11-08 04:06:11 -06:00
RTLIL : : Const ( children [ 1 ] - > bits ) , sign_hint , type = = AST_POW ? children [ 1 ] - > is_signed : false , width_hint ) ;
2013-11-04 08:37:09 -06:00
newNode = mkconst_bits ( y . bits , sign_hint ) ;
2014-06-14 04:27:05 -05:00
} else
if ( type = = AST_POW & & children [ 0 ] - > isConst ( ) & & children [ 1 ] - > isConst ( ) ) {
newNode = new AstNode ( AST_REALVALUE ) ;
newNode - > realvalue = pow ( children [ 0 ] - > asReal ( sign_hint ) , children [ 1 ] - > asReal ( sign_hint ) ) ;
2013-01-05 04:13:26 -06:00
}
break ;
2013-12-27 06:50:08 -06:00
if ( 0 ) { case AST_LT : const_func = RTLIL : : const_lt ; }
if ( 0 ) { case AST_LE : const_func = RTLIL : : const_le ; }
if ( 0 ) { case AST_EQ : const_func = RTLIL : : const_eq ; }
if ( 0 ) { case AST_NE : const_func = RTLIL : : const_ne ; }
if ( 0 ) { case AST_EQX : const_func = RTLIL : : const_eqx ; }
if ( 0 ) { case AST_NEX : const_func = RTLIL : : const_nex ; }
if ( 0 ) { case AST_GE : const_func = RTLIL : : const_ge ; }
if ( 0 ) { case AST_GT : const_func = RTLIL : : const_gt ; }
2013-01-05 04:13:26 -06:00
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 1 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
int cmp_width = std : : max ( children [ 0 ] - > bits . size ( ) , children [ 1 ] - > bits . size ( ) ) ;
bool cmp_signed = children [ 0 ] - > is_signed & & children [ 1 ] - > is_signed ;
RTLIL : : Const y = const_func ( children [ 0 ] - > bitsAsConst ( cmp_width , cmp_signed ) ,
children [ 1 ] - > bitsAsConst ( cmp_width , cmp_signed ) , cmp_signed , cmp_signed , 1 ) ;
2013-01-05 04:13:26 -06:00
newNode = mkconst_bits ( y . bits , false ) ;
2014-06-14 04:27:05 -05:00
} else
if ( children [ 0 ] - > isConst ( ) & & children [ 1 ] - > isConst ( ) ) {
2014-06-17 05:47:51 -05:00
bool cmp_signed = ( children [ 0 ] - > type = = AST_REALVALUE | | children [ 0 ] - > is_signed ) & & ( children [ 1 ] - > type = = AST_REALVALUE | | children [ 1 ] - > is_signed ) ;
2014-06-14 04:27:05 -05:00
switch ( type ) {
2014-06-17 05:47:51 -05:00
case AST_LT : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) < children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_LE : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) < = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_EQ : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) = = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_NE : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) ! = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_EQX : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) = = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_NEX : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) ! = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_GE : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) > = children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
case AST_GT : newNode = mkconst_int ( children [ 0 ] - > asReal ( cmp_signed ) > children [ 1 ] - > asReal ( cmp_signed ) , false , 1 ) ; break ;
2014-06-14 04:27:05 -05:00
default : log_abort ( ) ;
}
2013-01-05 04:13:26 -06:00
}
break ;
if ( 0 ) { case AST_ADD : const_func = RTLIL : : const_add ; }
if ( 0 ) { case AST_SUB : const_func = RTLIL : : const_sub ; }
if ( 0 ) { case AST_MUL : const_func = RTLIL : : const_mul ; }
if ( 0 ) { case AST_DIV : const_func = RTLIL : : const_div ; }
if ( 0 ) { case AST_MOD : const_func = RTLIL : : const_mod ; }
2014-06-14 04:27:05 -05:00
if ( children [ 0 ] - > type = = AST_CONSTANT & & children [ 1 ] - > type = = AST_CONSTANT ) {
RTLIL : : Const y = const_func ( children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) ,
children [ 1 ] - > bitsAsConst ( width_hint , sign_hint ) , sign_hint , sign_hint , width_hint ) ;
newNode = mkconst_bits ( y . bits , sign_hint ) ;
} else
2014-06-14 01:51:22 -05:00
if ( children [ 0 ] - > isConst ( ) & & children [ 1 ] - > isConst ( ) ) {
2014-06-14 04:27:05 -05:00
newNode = new AstNode ( AST_REALVALUE ) ;
switch ( type ) {
case AST_ADD : newNode - > realvalue = children [ 0 ] - > asReal ( sign_hint ) + children [ 1 ] - > asReal ( sign_hint ) ; break ;
case AST_SUB : newNode - > realvalue = children [ 0 ] - > asReal ( sign_hint ) - children [ 1 ] - > asReal ( sign_hint ) ; break ;
case AST_MUL : newNode - > realvalue = children [ 0 ] - > asReal ( sign_hint ) * children [ 1 ] - > asReal ( sign_hint ) ; break ;
case AST_DIV : newNode - > realvalue = children [ 0 ] - > asReal ( sign_hint ) / children [ 1 ] - > asReal ( sign_hint ) ; break ;
case AST_MOD : newNode - > realvalue = fmod ( children [ 0 ] - > asReal ( sign_hint ) , children [ 1 ] - > asReal ( sign_hint ) ) ; break ;
default : log_abort ( ) ;
2014-06-14 01:51:22 -05:00
}
2013-01-05 04:13:26 -06:00
}
break ;
if ( 0 ) { case AST_POS : const_func = RTLIL : : const_pos ; }
if ( 0 ) { case AST_NEG : const_func = RTLIL : : const_neg ; }
if ( children [ 0 ] - > type = = AST_CONSTANT ) {
2013-11-04 08:37:09 -06:00
RTLIL : : Const y = const_func ( children [ 0 ] - > bitsAsConst ( width_hint , sign_hint ) , dummy_arg , sign_hint , false , width_hint ) ;
newNode = mkconst_bits ( y . bits , sign_hint ) ;
2014-06-14 04:27:05 -05:00
} else
if ( children [ 0 ] - > isConst ( ) ) {
newNode = new AstNode ( AST_REALVALUE ) ;
if ( type = = AST_POS )
newNode - > realvalue = + children [ 0 ] - > asReal ( sign_hint ) ;
else
newNode - > realvalue = - children [ 0 ] - > asReal ( sign_hint ) ;
2013-01-05 04:13:26 -06:00
}
break ;
case AST_TERNARY :
2014-06-16 08:12:24 -05:00
if ( children [ 0 ] - > isConst ( ) )
{
2013-11-07 11:18:16 -06:00
bool found_sure_true = false ;
bool found_maybe_true = false ;
2014-06-16 08:12:24 -05:00
if ( children [ 0 ] - > type = = AST_CONSTANT )
2014-06-14 04:27:05 -05:00
for ( auto & bit : children [ 0 ] - > bits ) {
if ( bit = = RTLIL : : State : : S1 )
found_sure_true = true ;
if ( bit > RTLIL : : State : : S1 )
found_maybe_true = true ;
}
2014-06-16 08:12:24 -05:00
else
found_sure_true = children [ 0 ] - > asReal ( sign_hint ) ! = 0 ;
AstNode * choice = NULL , * not_choice = NULL ;
2013-11-07 11:18:16 -06:00
if ( found_sure_true )
2014-06-16 08:12:24 -05:00
choice = children [ 1 ] , not_choice = children [ 2 ] ;
2013-11-07 11:18:16 -06:00
else if ( ! found_maybe_true )
2014-06-16 08:12:24 -05:00
choice = children [ 2 ] , not_choice = children [ 1 ] ;
2014-06-14 04:27:05 -05:00
if ( choice ! = NULL ) {
if ( choice - > type = = AST_CONSTANT ) {
2014-06-16 08:12:24 -05:00
int other_width_hint = width_hint ;
bool other_sign_hint = sign_hint , other_real = false ;
not_choice - > detectSignWidth ( other_width_hint , other_sign_hint , & other_real ) ;
if ( other_real ) {
newNode = new AstNode ( AST_REALVALUE ) ;
2014-06-25 03:05:36 -05:00
choice - > detectSignWidth ( width_hint , sign_hint ) ;
2014-06-16 08:12:24 -05:00
newNode - > realvalue = choice - > asReal ( sign_hint ) ;
} else {
RTLIL : : Const y = choice - > bitsAsConst ( width_hint , sign_hint ) ;
if ( choice - > is_string & & y . bits . size ( ) % 8 = = 0 & & sign_hint = = false )
newNode = mkconst_str ( y . bits ) ;
else
newNode = mkconst_bits ( y . bits , sign_hint ) ;
}
2014-06-14 04:27:05 -05:00
} else
if ( choice - > isConst ( ) ) {
newNode = choice - > clone ( ) ;
}
2013-11-07 21:44:09 -06:00
} else if ( children [ 1 ] - > type = = AST_CONSTANT & & children [ 2 ] - > type = = AST_CONSTANT ) {
RTLIL : : Const a = children [ 1 ] - > bitsAsConst ( width_hint , sign_hint ) ;
RTLIL : : Const b = children [ 2 ] - > bitsAsConst ( width_hint , sign_hint ) ;
2014-07-28 04:08:55 -05:00
log_assert ( a . bits . size ( ) = = b . bits . size ( ) ) ;
2013-11-07 21:44:09 -06:00
for ( size_t i = 0 ; i < a . bits . size ( ) ; i + + )
if ( a . bits [ i ] ! = b . bits [ i ] )
a . bits [ i ] = RTLIL : : State : : Sx ;
newNode = mkconst_bits ( a . bits , sign_hint ) ;
2014-06-16 08:05:37 -05:00
} else if ( children [ 1 ] - > isConst ( ) & & children [ 2 ] - > isConst ( ) ) {
newNode = new AstNode ( AST_REALVALUE ) ;
if ( children [ 1 ] - > asReal ( sign_hint ) = = children [ 2 ] - > asReal ( sign_hint ) )
newNode - > realvalue = children [ 1 ] - > asReal ( sign_hint ) ;
else
// IEEE Std 1800-2012 Sec. 11.4.11 states that the entry in Table 7-1 for
// the data type in question should be returned if the ?: is ambiguous. The
// value in Table 7-1 for the 'real' type is 0.0.
newNode - > realvalue = 0.0 ;
2013-11-04 09:46:14 -06:00
}
2013-01-05 04:13:26 -06:00
}
break ;
2013-06-10 06:56:03 -05:00
case AST_CONCAT :
2013-12-05 06:26:17 -06:00
string_op = ! children . empty ( ) ;
2013-06-10 06:56:03 -05:00
for ( auto it = children . begin ( ) ; it ! = children . end ( ) ; it + + ) {
if ( ( * it ) - > type ! = AST_CONSTANT )
goto not_const ;
2013-12-05 06:26:17 -06:00
if ( ! ( * it ) - > is_string )
string_op = false ;
2013-06-10 06:56:03 -05:00
tmp_bits . insert ( tmp_bits . end ( ) , ( * it ) - > bits . begin ( ) , ( * it ) - > bits . end ( ) ) ;
}
2013-12-05 06:26:17 -06:00
newNode = string_op ? mkconst_str ( tmp_bits ) : mkconst_bits ( tmp_bits , false ) ;
2013-11-07 07:08:53 -06:00
break ;
case AST_REPLICATE :
if ( children . at ( 0 ) - > type ! = AST_CONSTANT | | children . at ( 1 ) - > type ! = AST_CONSTANT )
goto not_const ;
for ( int i = 0 ; i < children [ 0 ] - > bitsAsConst ( ) . as_int ( ) ; i + + )
tmp_bits . insert ( tmp_bits . end ( ) , children . at ( 1 ) - > bits . begin ( ) , children . at ( 1 ) - > bits . end ( ) ) ;
2013-12-05 06:26:17 -06:00
newNode = children . at ( 1 ) - > is_string ? mkconst_str ( tmp_bits ) : mkconst_bits ( tmp_bits , false ) ;
2013-06-10 06:56:03 -05:00
break ;
2013-01-05 04:13:26 -06:00
default :
2013-06-10 06:56:03 -05:00
not_const :
2013-01-05 04:13:26 -06:00
break ;
}
}
// if any of the above set 'newNode' -> use 'newNode' as template to update 'this'
if ( newNode ) {
apply_newNode :
// fprintf(stderr, "----\n");
// dumpAst(stderr, "- ");
// newNode->dumpAst(stderr, "+ ");
2014-07-28 04:08:55 -05:00
log_assert ( newNode ! = NULL ) ;
2013-01-05 04:13:26 -06:00
newNode - > filename = filename ;
newNode - > linenum = linenum ;
newNode - > cloneInto ( this ) ;
delete newNode ;
did_something = true ;
}
2014-01-20 13:25:20 -06:00
if ( ! did_something )
basic_prep = true ;
2013-01-05 04:13:26 -06:00
return did_something ;
}
2013-11-20 04:05:58 -06:00
static void replace_result_wire_name_in_function ( AstNode * node , std : : string & from , std : : string & to )
{
for ( auto & it : node - > children )
replace_result_wire_name_in_function ( it , from , to ) ;
if ( node - > str = = from )
node - > str = to ;
}
2014-10-26 14:33:10 -05:00
// replace a readmem[bh] TCALL ast node with a block of memory assignments
AstNode * AstNode : : readmem ( bool is_readmemh , std : : string mem_filename , AstNode * memory , int start_addr , int finish_addr )
{
AstNode * block = new AstNode ( AST_BLOCK ) ;
std : : ifstream f ;
f . open ( mem_filename . c_str ( ) ) ;
if ( f . fail ( ) )
log_error ( " Can not open file `%s` for %s at %s:%d. \n " , mem_filename . c_str ( ) , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
2014-10-26 17:29:36 -05:00
log_assert ( GetSize ( memory - > children ) = = 2 & & memory - > children [ 1 ] - > type = = AST_RANGE & & memory - > children [ 1 ] - > range_valid ) ;
int range_left = memory - > children [ 1 ] - > range_left , range_right = memory - > children [ 1 ] - > range_right ;
int range_min = std : : min ( range_left , range_right ) , range_max = std : : max ( range_left , range_right ) ;
if ( start_addr < 0 )
start_addr = range_min ;
if ( finish_addr < 0 )
finish_addr = range_max ;
2014-10-26 14:33:10 -05:00
bool in_comment = false ;
2014-10-26 17:29:36 -05:00
int increment = start_addr < = finish_addr ? + 1 : - 1 ;
int cursor = start_addr ;
2014-10-26 14:33:10 -05:00
while ( ! f . eof ( ) )
{
std : : string line , token ;
std : : getline ( f , line ) ;
for ( int i = 0 ; i < GetSize ( line ) ; i + + ) {
if ( in_comment & & line . substr ( i , 2 ) = = " */ " ) {
line [ i ] = ' ' ;
line [ i + 1 ] = ' ' ;
in_comment = false ;
continue ;
}
if ( ! in_comment & & line . substr ( i , 2 ) = = " /* " )
in_comment = true ;
if ( in_comment )
line [ i ] = ' ' ;
}
while ( 1 )
{
token = next_token ( line , " \t \r \n " ) ;
if ( token . empty ( ) | | token . substr ( 0 , 2 ) = = " // " )
break ;
if ( token [ 0 ] = = ' @ ' ) {
token = token . substr ( 1 ) ;
const char * nptr = token . c_str ( ) ;
char * endptr ;
cursor = strtol ( nptr , & endptr , 16 ) ;
if ( ! * nptr | | * endptr )
log_error ( " Can not parse address `%s` for %s at %s:%d. \n " , nptr , str . c_str ( ) , filename . c_str ( ) , linenum ) ;
continue ;
}
AstNode * value = VERILOG_FRONTEND : : const2ast ( ( is_readmemh ? " 'h " : " 'b " ) + token ) ;
block - > children . push_back ( new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER , new AstNode ( AST_RANGE , AstNode : : mkconst_int ( cursor , false ) ) ) , value ) ) ;
block - > children . back ( ) - > children [ 0 ] - > str = memory - > str ;
block - > children . back ( ) - > children [ 0 ] - > id2ast = memory ;
2014-10-26 17:29:36 -05:00
if ( ( cursor = = finish_addr ) | | ( increment > 0 & & cursor > = range_max ) | | ( increment < 0 & & cursor < = range_min ) )
2014-10-26 14:33:10 -05:00
break ;
cursor + = increment ;
}
2014-10-26 17:29:36 -05:00
if ( ( cursor = = finish_addr ) | | ( increment > 0 & & cursor > = range_max ) | | ( increment < 0 & & cursor < = range_min ) )
2014-10-26 14:33:10 -05:00
break ;
}
return block ;
}
2013-01-05 04:13:26 -06:00
// annotate the names of all wires and other named objects in a generate block
void AstNode : : expand_genblock ( std : : string index_var , std : : string prefix , std : : map < std : : string , std : : string > & name_map )
{
if ( ! index_var . empty ( ) & & type = = AST_IDENTIFIER & & str = = index_var ) {
current_scope [ index_var ] - > children [ 0 ] - > cloneInto ( this ) ;
return ;
}
2013-03-26 05:13:58 -05:00
if ( ( type = = AST_IDENTIFIER | | type = = AST_FCALL | | type = = AST_TCALL ) & & name_map . count ( str ) > 0 )
2013-01-05 04:13:26 -06:00
str = name_map [ str ] ;
std : : map < std : : string , std : : string > backup_name_map ;
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * child = children [ i ] ;
if ( child - > type = = AST_WIRE | | child - > type = = AST_MEMORY | | child - > type = = AST_PARAMETER | | child - > type = = AST_LOCALPARAM | |
child - > type = = AST_FUNCTION | | child - > type = = AST_TASK | | child - > type = = AST_CELL ) {
if ( backup_name_map . size ( ) = = 0 )
backup_name_map = name_map ;
std : : string new_name = prefix [ 0 ] = = ' \\ ' ? prefix . substr ( 1 ) : prefix ;
size_t pos = child - > str . rfind ( ' . ' ) ;
if ( pos = = std : : string : : npos )
pos = child - > str [ 0 ] = = ' \\ ' ? 1 : 0 ;
else
pos = pos + 1 ;
new_name = child - > str . substr ( 0 , pos ) + new_name + child - > str . substr ( pos ) ;
if ( new_name [ 0 ] ! = ' $ ' & & new_name [ 0 ] ! = ' \\ ' )
new_name = prefix [ 0 ] + new_name ;
name_map [ child - > str ] = new_name ;
2013-11-20 04:05:58 -06:00
if ( child - > type = = AST_FUNCTION )
replace_result_wire_name_in_function ( child , child - > str , new_name ) ;
else
child - > str = new_name ;
current_scope [ new_name ] = child ;
2013-01-05 04:13:26 -06:00
}
}
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * child = children [ i ] ;
2014-01-30 07:52:46 -06:00
if ( child - > type ! = AST_FUNCTION & & child - > type ! = AST_TASK & & child - > type ! = AST_PREFIX )
2013-01-05 04:13:26 -06:00
child - > expand_genblock ( index_var , prefix , name_map ) ;
}
if ( backup_name_map . size ( ) > 0 )
name_map . swap ( backup_name_map ) ;
}
// rename stuff (used when tasks of functions are instanciated)
2014-08-05 05:15:53 -05:00
void AstNode : : replace_ids ( const std : : string & prefix , const std : : map < std : : string , std : : string > & rules )
2013-01-05 04:13:26 -06:00
{
2014-08-05 05:15:53 -05:00
if ( type = = AST_BLOCK )
{
std : : map < std : : string , std : : string > new_rules = rules ;
std : : string new_prefix = prefix + str ;
for ( auto child : children )
if ( child - > type = = AST_WIRE ) {
new_rules [ child - > str ] = new_prefix + child - > str ;
child - > str = new_prefix + child - > str ;
}
for ( auto child : children )
if ( child - > type ! = AST_WIRE )
child - > replace_ids ( new_prefix , new_rules ) ;
}
else
{
if ( type = = AST_IDENTIFIER & & rules . count ( str ) > 0 )
str = rules . at ( str ) ;
for ( auto child : children )
child - > replace_ids ( prefix , rules ) ;
}
2013-01-05 04:13:26 -06:00
}
2014-06-17 14:39:25 -05:00
// helper function for mem2reg_as_needed_pass1
2014-12-28 20:11:50 -06:00
static void mark_memories_assign_lhs_complex ( dict < AstNode * , pool < std : : string > > & mem2reg_places ,
dict < AstNode * , uint32_t > & mem2reg_candidates , AstNode * that )
2014-06-17 14:39:25 -05:00
{
for ( auto & child : that - > children )
mark_memories_assign_lhs_complex ( mem2reg_places , mem2reg_candidates , child ) ;
if ( that - > type = = AST_IDENTIFIER & & that - > id2ast & & that - > id2ast - > type = = AST_MEMORY ) {
AstNode * mem = that - > id2ast ;
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_CMPLX_LHS ) )
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , that - > filename . c_str ( ) , that - > linenum ) ) ;
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_CMPLX_LHS ;
}
}
2013-01-05 04:13:26 -06:00
// find memories that should be replaced by registers
2014-12-28 20:11:50 -06:00
void AstNode : : mem2reg_as_needed_pass1 ( dict < AstNode * , pool < std : : string > > & mem2reg_places ,
dict < AstNode * , uint32_t > & mem2reg_candidates , dict < AstNode * , uint32_t > & proc_flags , uint32_t & flags )
2013-01-05 04:13:26 -06:00
{
2013-11-21 06:49:00 -06:00
uint32_t children_flags = 0 ;
int ignore_children_counter = 0 ;
if ( type = = AST_ASSIGN | | type = = AST_ASSIGN_LE | | type = = AST_ASSIGN_EQ )
{
2014-06-17 14:39:25 -05:00
// mark all memories that are used in a complex expression on the left side of an assignment
for ( auto & lhs_child : children [ 0 ] - > children )
mark_memories_assign_lhs_complex ( mem2reg_places , mem2reg_candidates , lhs_child ) ;
2013-11-21 06:49:00 -06:00
if ( children [ 0 ] - > type = = AST_IDENTIFIER & & children [ 0 ] - > id2ast & & children [ 0 ] - > id2ast - > type = = AST_MEMORY )
{
AstNode * mem = children [ 0 ] - > id2ast ;
// activate mem2reg if this is assigned in an async proc
if ( flags & AstNode : : MEM2REG_FL_ASYNC ) {
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_SET_ASYNC ) )
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , linenum ) ) ;
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_SET_ASYNC ;
}
// remember if this is assigned blocking (=)
if ( type = = AST_ASSIGN_EQ ) {
if ( ! ( proc_flags [ mem ] & AstNode : : MEM2REG_FL_EQ1 ) )
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , linenum ) ) ;
proc_flags [ mem ] | = AstNode : : MEM2REG_FL_EQ1 ;
}
// remember where this is
if ( flags & MEM2REG_FL_INIT ) {
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_SET_INIT ) )
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , linenum ) ) ;
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_SET_INIT ;
} else {
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_SET_ELSE ) )
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , linenum ) ) ;
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_SET_ELSE ;
2013-01-05 04:13:26 -06:00
}
}
2013-11-21 06:49:00 -06:00
ignore_children_counter = 1 ;
}
if ( type = = AST_IDENTIFIER & & id2ast & & id2ast - > type = = AST_MEMORY )
{
AstNode * mem = id2ast ;
// flag if used after blocking assignment (in same proc)
if ( ( proc_flags [ mem ] & AstNode : : MEM2REG_FL_EQ1 ) & & ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_EQ2 ) ) {
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , linenum ) ) ;
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_EQ2 ;
}
}
// also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg'
if ( type = = AST_MEMORY & & ( get_bool_attribute ( " \\ mem2reg " ) | | ( flags & AstNode : : MEM2REG_FL_ALL ) | | ! is_reg ) )
mem2reg_candidates [ this ] | = AstNode : : MEM2REG_FL_FORCED ;
2013-01-05 04:13:26 -06:00
2013-10-24 04:20:13 -05:00
if ( type = = AST_MODULE & & get_bool_attribute ( " \\ mem2reg " ) )
2013-11-21 06:49:00 -06:00
children_flags | = AstNode : : MEM2REG_FL_ALL ;
2014-12-28 20:11:50 -06:00
dict < AstNode * , uint32_t > * proc_flags_p = NULL ;
2013-03-24 05:13:32 -05:00
2013-01-05 04:13:26 -06:00
if ( type = = AST_ALWAYS ) {
2013-11-21 14:26:56 -06:00
int count_edge_events = 0 ;
for ( auto child : children )
2013-01-05 04:13:26 -06:00
if ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE )
2013-11-21 14:26:56 -06:00
count_edge_events + + ;
if ( count_edge_events ! = 1 )
2013-11-21 06:49:00 -06:00
children_flags | = AstNode : : MEM2REG_FL_ASYNC ;
2014-12-28 20:11:50 -06:00
proc_flags_p = new dict < AstNode * , uint32_t > ;
2013-11-21 06:49:00 -06:00
}
if ( type = = AST_INITIAL ) {
children_flags | = AstNode : : MEM2REG_FL_INIT ;
2014-12-28 20:11:50 -06:00
proc_flags_p = new dict < AstNode * , uint32_t > ;
2013-01-05 04:13:26 -06:00
}
2013-11-21 06:49:00 -06:00
uint32_t backup_flags = flags ;
flags | = children_flags ;
2014-07-28 04:08:55 -05:00
log_assert ( ( flags & ~ 0x000000ff ) = = 0 ) ;
2013-11-21 06:49:00 -06:00
2013-01-05 04:13:26 -06:00
for ( auto child : children )
2013-11-21 06:49:00 -06:00
if ( ignore_children_counter > 0 )
ignore_children_counter - - ;
else if ( proc_flags_p )
child - > mem2reg_as_needed_pass1 ( mem2reg_places , mem2reg_candidates , * proc_flags_p , flags ) ;
else
child - > mem2reg_as_needed_pass1 ( mem2reg_places , mem2reg_candidates , proc_flags , flags ) ;
flags & = ~ children_flags | backup_flags ;
if ( proc_flags_p ) {
2015-01-24 05:16:46 -06:00
# ifndef NDEBUG
2013-11-21 06:49:00 -06:00
for ( auto it : * proc_flags_p )
2014-02-06 15:49:14 -06:00
log_assert ( ( it . second & ~ 0xff000000 ) = = 0 ) ;
2015-01-24 05:16:46 -06:00
# endif
2013-11-21 06:49:00 -06:00
delete proc_flags_p ;
}
2013-01-05 04:13:26 -06:00
}
2014-12-28 20:11:50 -06:00
bool AstNode : : mem2reg_check ( pool < AstNode * > & mem2reg_set )
2014-10-15 17:44:23 -05:00
{
if ( type ! = AST_IDENTIFIER | | ! id2ast | | ! mem2reg_set . count ( id2ast ) )
return false ;
if ( children . empty ( ) | | children [ 0 ] - > type ! = AST_RANGE | | GetSize ( children [ 0 ] - > children ) ! = 1 )
log_error ( " Invalid array access at %s:%d. \n " , filename . c_str ( ) , linenum ) ;
return true ;
}
2013-01-05 04:13:26 -06:00
// actually replace memories with registers
2014-12-28 20:11:50 -06:00
void AstNode : : mem2reg_as_needed_pass2 ( pool < AstNode * > & mem2reg_set , AstNode * mod , AstNode * block )
2013-01-05 04:13:26 -06:00
{
if ( type = = AST_BLOCK )
block = this ;
2014-10-15 17:44:23 -05:00
if ( ( type = = AST_ASSIGN_LE | | type = = AST_ASSIGN_EQ ) & & block ! = NULL & &
children [ 0 ] - > mem2reg_check ( mem2reg_set ) & & children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > type ! = AST_CONSTANT )
2013-01-05 04:13:26 -06:00
{
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $mem2reg_wr$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
std : : string id_addr = sstr . str ( ) + " _ADDR " , id_data = sstr . str ( ) + " _DATA " ;
int mem_width , mem_size , addr_bits ;
children [ 0 ] - > id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
AstNode * wire_addr = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( addr_bits - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_addr - > str = id_addr ;
wire_addr - > is_reg = true ;
2013-10-24 04:20:13 -05:00
wire_addr - > attributes [ " \\ nosync " ] = AstNode : : mkconst_int ( 1 , false ) ;
2013-01-05 04:13:26 -06:00
mod - > children . push_back ( wire_addr ) ;
2014-02-14 12:56:44 -06:00
while ( wire_addr - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
AstNode * wire_data = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_data - > str = id_data ;
wire_data - > is_reg = true ;
2013-10-24 04:20:13 -05:00
wire_data - > attributes [ " \\ nosync " ] = AstNode : : mkconst_int ( 1 , false ) ;
2013-01-05 04:13:26 -06:00
mod - > children . push_back ( wire_data ) ;
2014-02-14 12:56:44 -06:00
while ( wire_data - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
2014-07-28 04:08:55 -05:00
log_assert ( block ! = NULL ) ;
2013-01-05 04:13:26 -06:00
size_t assign_idx = 0 ;
while ( assign_idx < block - > children . size ( ) & & block - > children [ assign_idx ] ! = this )
assign_idx + + ;
2014-07-28 04:08:55 -05:00
log_assert ( assign_idx < block - > children . size ( ) ) ;
2013-01-05 04:13:26 -06:00
AstNode * assign_addr = new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER ) , children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
assign_addr - > children [ 0 ] - > str = id_addr ;
block - > children . insert ( block - > children . begin ( ) + assign_idx + 1 , assign_addr ) ;
AstNode * case_node = new AstNode ( AST_CASE , new AstNode ( AST_IDENTIFIER ) ) ;
case_node - > children [ 0 ] - > str = id_addr ;
for ( int i = 0 ; i < mem_size ; i + + ) {
if ( children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > type = = AST_CONSTANT & & int ( children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > integer ) ! = i )
continue ;
AstNode * cond_node = new AstNode ( AST_COND , AstNode : : mkconst_int ( i , false , addr_bits ) , new AstNode ( AST_BLOCK ) ) ;
2013-03-24 04:42:08 -05:00
AstNode * assign_reg = new AstNode ( type , new AstNode ( AST_IDENTIFIER ) , new AstNode ( AST_IDENTIFIER ) ) ;
2014-07-17 06:49:32 -05:00
if ( children [ 0 ] - > children . size ( ) = = 2 )
assign_reg - > children [ 0 ] - > children . push_back ( children [ 0 ] - > children [ 1 ] - > clone ( ) ) ;
2013-01-05 04:13:26 -06:00
assign_reg - > children [ 0 ] - > str = stringf ( " %s[%d] " , children [ 0 ] - > str . c_str ( ) , i ) ;
assign_reg - > children [ 1 ] - > str = id_data ;
cond_node - > children [ 1 ] - > children . push_back ( assign_reg ) ;
case_node - > children . push_back ( cond_node ) ;
}
block - > children . insert ( block - > children . begin ( ) + assign_idx + 2 , case_node ) ;
children [ 0 ] - > delete_children ( ) ;
children [ 0 ] - > range_valid = false ;
children [ 0 ] - > id2ast = NULL ;
children [ 0 ] - > str = id_data ;
2013-03-24 04:42:08 -05:00
type = AST_ASSIGN_EQ ;
2013-01-05 04:13:26 -06:00
}
2014-10-15 17:44:23 -05:00
if ( mem2reg_check ( mem2reg_set ) )
2013-01-05 04:13:26 -06:00
{
2014-07-17 06:49:32 -05:00
AstNode * bit_part_sel = NULL ;
if ( children . size ( ) = = 2 )
bit_part_sel = children [ 1 ] - > clone ( ) ;
2013-11-21 06:49:00 -06:00
if ( children [ 0 ] - > children [ 0 ] - > type = = AST_CONSTANT )
{
int id = children [ 0 ] - > children [ 0 ] - > integer ;
str = stringf ( " %s[%d] " , str . c_str ( ) , id ) ;
2013-01-05 04:13:26 -06:00
2013-11-21 06:49:00 -06:00
delete_children ( ) ;
range_valid = false ;
id2ast = NULL ;
}
else
{
std : : stringstream sstr ;
2014-07-31 06:19:47 -05:00
sstr < < " $mem2reg_rd$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < linenum < < " $ " < < ( autoidx + + ) ;
2013-11-21 06:49:00 -06:00
std : : string id_addr = sstr . str ( ) + " _ADDR " , id_data = sstr . str ( ) + " _DATA " ;
int mem_width , mem_size , addr_bits ;
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
AstNode * wire_addr = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( addr_bits - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_addr - > str = id_addr ;
wire_addr - > is_reg = true ;
if ( block )
wire_addr - > attributes [ " \\ nosync " ] = AstNode : : mkconst_int ( 1 , false ) ;
mod - > children . push_back ( wire_addr ) ;
2014-02-14 12:56:44 -06:00
while ( wire_addr - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-11-21 06:49:00 -06:00
AstNode * wire_data = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_data - > str = id_data ;
wire_data - > is_reg = true ;
if ( block )
wire_data - > attributes [ " \\ nosync " ] = AstNode : : mkconst_int ( 1 , false ) ;
mod - > children . push_back ( wire_data ) ;
2014-02-14 12:56:44 -06:00
while ( wire_data - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-11-21 06:49:00 -06:00
AstNode * assign_addr = new AstNode ( block ? AST_ASSIGN_EQ : AST_ASSIGN , new AstNode ( AST_IDENTIFIER ) , children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
assign_addr - > children [ 0 ] - > str = id_addr ;
AstNode * case_node = new AstNode ( AST_CASE , new AstNode ( AST_IDENTIFIER ) ) ;
case_node - > children [ 0 ] - > str = id_addr ;
for ( int i = 0 ; i < mem_size ; i + + ) {
if ( children [ 0 ] - > children [ 0 ] - > type = = AST_CONSTANT & & int ( children [ 0 ] - > children [ 0 ] - > integer ) ! = i )
continue ;
AstNode * cond_node = new AstNode ( AST_COND , AstNode : : mkconst_int ( i , false , addr_bits ) , new AstNode ( AST_BLOCK ) ) ;
AstNode * assign_reg = new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER ) , new AstNode ( AST_IDENTIFIER ) ) ;
assign_reg - > children [ 0 ] - > str = id_data ;
assign_reg - > children [ 1 ] - > str = stringf ( " %s[%d] " , str . c_str ( ) , i ) ;
cond_node - > children [ 1 ] - > children . push_back ( assign_reg ) ;
case_node - > children . push_back ( cond_node ) ;
}
2013-01-05 04:13:26 -06:00
2013-11-21 06:49:00 -06:00
std : : vector < RTLIL : : State > x_bits ;
for ( int i = 0 ; i < mem_width ; i + + )
x_bits . push_back ( RTLIL : : State : : Sx ) ;
2013-01-05 04:13:26 -06:00
2013-11-21 06:49:00 -06:00
AstNode * cond_node = new AstNode ( AST_COND , new AstNode ( AST_DEFAULT ) , new AstNode ( AST_BLOCK ) ) ;
AstNode * assign_reg = new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER ) , AstNode : : mkconst_bits ( x_bits , false ) ) ;
2013-01-05 04:13:26 -06:00
assign_reg - > children [ 0 ] - > str = id_data ;
cond_node - > children [ 1 ] - > children . push_back ( assign_reg ) ;
case_node - > children . push_back ( cond_node ) ;
2013-03-24 04:42:08 -05:00
2013-11-21 06:49:00 -06:00
if ( block )
{
size_t assign_idx = 0 ;
while ( assign_idx < block - > children . size ( ) & & ! block - > children [ assign_idx ] - > contains ( this ) )
assign_idx + + ;
2014-07-28 04:08:55 -05:00
log_assert ( assign_idx < block - > children . size ( ) ) ;
2013-11-21 06:49:00 -06:00
block - > children . insert ( block - > children . begin ( ) + assign_idx , case_node ) ;
block - > children . insert ( block - > children . begin ( ) + assign_idx , assign_addr ) ;
}
else
{
AstNode * proc = new AstNode ( AST_ALWAYS , new AstNode ( AST_BLOCK ) ) ;
proc - > children [ 0 ] - > children . push_back ( case_node ) ;
mod - > children . push_back ( proc ) ;
mod - > children . push_back ( assign_addr ) ;
}
2013-01-05 04:13:26 -06:00
2013-11-21 06:49:00 -06:00
delete_children ( ) ;
range_valid = false ;
id2ast = NULL ;
str = id_data ;
2013-01-05 04:13:26 -06:00
}
2014-07-17 06:49:32 -05:00
if ( bit_part_sel )
children . push_back ( bit_part_sel ) ;
2013-01-05 04:13:26 -06:00
}
2014-07-28 04:08:55 -05:00
log_assert ( id2ast = = NULL | | mem2reg_set . count ( id2ast ) = = 0 ) ;
2013-01-05 04:13:26 -06:00
2013-03-24 03:27:01 -05:00
auto children_list = children ;
2013-03-25 11:13:14 -05:00
for ( size_t i = 0 ; i < children_list . size ( ) ; i + + )
children_list [ i ] - > mem2reg_as_needed_pass2 ( mem2reg_set , mod , block ) ;
2013-01-05 04:13:26 -06:00
}
// calulate memory dimensions
void AstNode : : meminfo ( int & mem_width , int & mem_size , int & addr_bits )
{
2014-07-28 04:08:55 -05:00
log_assert ( type = = AST_MEMORY ) ;
2013-01-05 04:13:26 -06:00
mem_width = children [ 0 ] - > range_left - children [ 0 ] - > range_right + 1 ;
mem_size = children [ 1 ] - > range_left - children [ 1 ] - > range_right ;
if ( mem_size < 0 )
mem_size * = - 1 ;
mem_size + = std : : min ( children [ 1 ] - > range_left , children [ 1 ] - > range_right ) + 1 ;
addr_bits = 1 ;
while ( ( 1 < < addr_bits ) < mem_size )
addr_bits + + ;
}
2014-06-06 17:02:05 -05:00
bool AstNode : : has_const_only_constructs ( bool & recommend_const_eval )
2014-06-06 15:55:02 -05:00
{
2014-06-06 17:02:05 -05:00
if ( type = = AST_FOR )
recommend_const_eval = true ;
2014-06-06 15:55:02 -05:00
if ( type = = AST_WHILE | | type = = AST_REPEAT )
return true ;
if ( type = = AST_FCALL & & current_scope . count ( str ) )
2014-06-06 17:02:05 -05:00
if ( current_scope [ str ] - > has_const_only_constructs ( recommend_const_eval ) )
2014-06-06 15:55:02 -05:00
return true ;
for ( auto child : children )
2014-06-06 17:02:05 -05:00
if ( child - > AstNode : : has_const_only_constructs ( recommend_const_eval ) )
2014-06-06 15:55:02 -05:00
return true ;
return false ;
}
2014-02-14 12:56:44 -06:00
// helper function for AstNode::eval_const_function()
void AstNode : : replace_variables ( std : : map < std : : string , AstNode : : varinfo_t > & variables , AstNode * fcall )
{
if ( type = = AST_IDENTIFIER & & variables . count ( str ) ) {
int offset = variables . at ( str ) . offset , width = variables . at ( str ) . val . bits . size ( ) ;
if ( ! children . empty ( ) ) {
2014-06-06 10:40:45 -05:00
if ( children . size ( ) ! = 1 | | children . at ( 0 ) - > type ! = AST_RANGE )
log_error ( " Memory access in constant function is not supported in %s:%d (called from %s:%d). \n " ,
filename . c_str ( ) , linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
children . at ( 0 ) - > replace_variables ( variables , fcall ) ;
2014-02-14 12:56:44 -06:00
while ( simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
2014-06-06 10:40:45 -05:00
if ( ! children . at ( 0 ) - > range_valid )
2014-02-14 12:56:44 -06:00
log_error ( " Non-constant range in %s:%d (called from %s:%d). \n " ,
filename . c_str ( ) , linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
2014-06-06 10:40:45 -05:00
offset = std : : min ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) ;
width = std : : min ( std : : abs ( children . at ( 0 ) - > range_left - children . at ( 0 ) - > range_right ) + 1 , width ) ;
2014-02-14 12:56:44 -06:00
}
offset - = variables . at ( str ) . offset ;
std : : vector < RTLIL : : State > & var_bits = variables . at ( str ) . val . bits ;
std : : vector < RTLIL : : State > new_bits ( var_bits . begin ( ) + offset , var_bits . begin ( ) + offset + width ) ;
AstNode * newNode = mkconst_bits ( new_bits , variables . at ( str ) . is_signed ) ;
newNode - > cloneInto ( this ) ;
delete newNode ;
return ;
}
for ( auto & child : children )
child - > replace_variables ( variables , fcall ) ;
}
// evaluate functions with all-const arguments
AstNode * AstNode : : eval_const_function ( AstNode * fcall )
{
std : : map < std : : string , AstNode * > backup_scope ;
std : : map < std : : string , AstNode : : varinfo_t > variables ;
2014-06-06 10:40:45 -05:00
bool delete_temp_block = false ;
2014-02-14 12:56:44 -06:00
AstNode * block = NULL ;
size_t argidx = 0 ;
for ( auto child : children )
{
if ( child - > type = = AST_BLOCK )
{
log_assert ( block = = NULL ) ;
block = child ;
continue ;
}
if ( child - > type = = AST_WIRE )
{
while ( child - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( ! child - > range_valid )
log_error ( " Can't determine size of variable %s in %s:%d (called from %s:%d). \n " ,
child - > str . c_str ( ) , child - > filename . c_str ( ) , child - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
variables [ child - > str ] . val = RTLIL : : Const ( RTLIL : : State : : Sx , abs ( child - > range_left - child - > range_right ) + 1 ) ;
variables [ child - > str ] . offset = std : : min ( child - > range_left , child - > range_right ) ;
variables [ child - > str ] . is_signed = child - > is_signed ;
if ( child - > is_input & & argidx < fcall - > children . size ( ) )
variables [ child - > str ] . val = fcall - > children . at ( argidx + + ) - > bitsAsConst ( variables [ child - > str ] . val . bits . size ( ) ) ;
backup_scope [ child - > str ] = current_scope [ child - > str ] ;
current_scope [ child - > str ] = child ;
continue ;
}
2014-06-06 14:29:23 -05:00
log_assert ( block = = NULL ) ;
delete_temp_block = true ;
block = new AstNode ( AST_BLOCK ) ;
block - > children . push_back ( child - > clone ( ) ) ;
2014-02-14 12:56:44 -06:00
}
log_assert ( block ! = NULL ) ;
2014-10-18 08:20:38 -05:00
log_assert ( variables . count ( str ) ! = 0 ) ;
2014-02-14 12:56:44 -06:00
while ( ! block - > children . empty ( ) )
{
AstNode * stmt = block - > children . front ( ) ;
#if 0
log ( " ----------------------------------- \n " ) ;
for ( auto & it : variables )
log ( " %20s %40s \n " , it . first . c_str ( ) , log_signal ( it . second . val ) ) ;
stmt - > dumpAst ( NULL , " stmt> " ) ;
# endif
if ( stmt - > type = = AST_ASSIGN_EQ )
{
stmt - > children . at ( 1 ) - > replace_variables ( variables , fcall ) ;
while ( stmt - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
2014-06-06 10:40:45 -05:00
if ( stmt - > type ! = AST_ASSIGN_EQ )
continue ;
2014-02-14 12:56:44 -06:00
if ( stmt - > children . at ( 1 ) - > type ! = AST_CONSTANT )
2014-06-06 10:40:45 -05:00
log_error ( " Non-constant expression in constant function at %s:%d (called from %s:%d). X \n " ,
2014-02-14 12:56:44 -06:00
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
2014-06-06 15:55:02 -05:00
if ( stmt - > children . at ( 0 ) - > type ! = AST_IDENTIFIER )
2014-02-14 12:56:44 -06:00
log_error ( " Unsupported composite left hand side in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
if ( ! variables . count ( stmt - > children . at ( 0 ) - > str ) )
log_error ( " Assignment to non-local variable in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
2014-06-06 15:55:02 -05:00
if ( stmt - > children . at ( 0 ) - > children . empty ( ) ) {
variables [ stmt - > children . at ( 0 ) - > str ] . val = stmt - > children . at ( 1 ) - > bitsAsConst ( variables [ stmt - > children . at ( 0 ) - > str ] . val . bits . size ( ) ) ;
} else {
AstNode * range = stmt - > children . at ( 0 ) - > children . at ( 0 ) ;
if ( ! range - > range_valid )
log_error ( " Non-constant range in %s:%d (called from %s:%d). \n " ,
range - > filename . c_str ( ) , range - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
int offset = std : : min ( range - > range_left , range - > range_right ) ;
2014-07-23 13:45:27 -05:00
int width = std : : abs ( range - > range_left - range - > range_right ) + 1 ;
2014-06-06 15:55:02 -05:00
varinfo_t & v = variables [ stmt - > children . at ( 0 ) - > str ] ;
RTLIL : : Const r = stmt - > children . at ( 1 ) - > bitsAsConst ( v . val . bits . size ( ) ) ;
for ( int i = 0 ; i < width ; i + + )
v . val . bits . at ( i + offset - v . offset ) = r . bits . at ( i ) ;
}
2014-02-14 12:56:44 -06:00
2014-02-14 13:33:22 -06:00
delete block - > children . front ( ) ;
2014-02-14 12:56:44 -06:00
block - > children . erase ( block - > children . begin ( ) ) ;
continue ;
}
2014-02-14 13:33:22 -06:00
if ( stmt - > type = = AST_FOR )
{
block - > children . insert ( block - > children . begin ( ) , stmt - > children . at ( 0 ) ) ;
stmt - > children . at ( 3 ) - > children . push_back ( stmt - > children . at ( 2 ) ) ;
stmt - > children . erase ( stmt - > children . begin ( ) + 2 ) ;
stmt - > children . erase ( stmt - > children . begin ( ) ) ;
stmt - > type = AST_WHILE ;
continue ;
}
if ( stmt - > type = = AST_WHILE )
{
AstNode * cond = stmt - > children . at ( 0 ) - > clone ( ) ;
cond - > replace_variables ( variables , fcall ) ;
while ( cond - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( cond - > type ! = AST_CONSTANT )
log_error ( " Non-constant expression in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
if ( cond - > asBool ( ) ) {
block - > children . insert ( block - > children . begin ( ) , stmt - > children . at ( 1 ) - > clone ( ) ) ;
} else {
delete block - > children . front ( ) ;
block - > children . erase ( block - > children . begin ( ) ) ;
}
delete cond ;
continue ;
}
2014-06-07 03:47:53 -05:00
if ( stmt - > type = = AST_REPEAT )
{
AstNode * num = stmt - > children . at ( 0 ) - > clone ( ) ;
num - > replace_variables ( variables , fcall ) ;
while ( num - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( num - > type ! = AST_CONSTANT )
log_error ( " Non-constant expression in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
block - > children . erase ( block - > children . begin ( ) ) ;
for ( int i = 0 ; i < num - > bitsAsConst ( ) . as_int ( ) ; i + + )
block - > children . insert ( block - > children . begin ( ) , stmt - > children . at ( 1 ) - > clone ( ) ) ;
delete stmt ;
delete num ;
continue ;
}
2014-02-16 06:16:38 -06:00
if ( stmt - > type = = AST_CASE )
{
AstNode * expr = stmt - > children . at ( 0 ) - > clone ( ) ;
expr - > replace_variables ( variables , fcall ) ;
while ( expr - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
AstNode * sel_case = NULL ;
for ( size_t i = 1 ; i < stmt - > children . size ( ) ; i + + )
{
bool found_match = false ;
log_assert ( stmt - > children . at ( i ) - > type = = AST_COND ) ;
if ( stmt - > children . at ( i ) - > children . front ( ) - > type = = AST_DEFAULT ) {
sel_case = stmt - > children . at ( i ) - > children . back ( ) ;
continue ;
}
for ( size_t j = 0 ; j + 1 < stmt - > children . at ( i ) - > children . size ( ) & & ! found_match ; j + + )
{
AstNode * cond = stmt - > children . at ( i ) - > children . at ( j ) - > clone ( ) ;
cond - > replace_variables ( variables , fcall ) ;
cond = new AstNode ( AST_EQ , expr - > clone ( ) , cond ) ;
while ( cond - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( cond - > type ! = AST_CONSTANT )
log_error ( " Non-constant expression in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
found_match = cond - > asBool ( ) ;
delete cond ;
}
if ( found_match ) {
sel_case = stmt - > children . at ( i ) - > children . back ( ) ;
break ;
}
}
block - > children . erase ( block - > children . begin ( ) ) ;
if ( sel_case )
block - > children . insert ( block - > children . begin ( ) , sel_case - > clone ( ) ) ;
delete stmt ;
delete expr ;
continue ;
}
2014-02-14 13:33:22 -06:00
if ( stmt - > type = = AST_BLOCK )
{
block - > children . erase ( block - > children . begin ( ) ) ;
block - > children . insert ( block - > children . begin ( ) , stmt - > children . begin ( ) , stmt - > children . end ( ) ) ;
stmt - > children . clear ( ) ;
delete stmt ;
continue ;
}
2014-02-14 12:56:44 -06:00
log_error ( " Unsupported language construct in constant function at %s:%d (called from %s:%d). \n " ,
stmt - > filename . c_str ( ) , stmt - > linenum , fcall - > filename . c_str ( ) , fcall - > linenum ) ;
log_abort ( ) ;
}
2014-06-06 10:40:45 -05:00
if ( delete_temp_block )
delete block ;
2014-02-14 12:56:44 -06:00
for ( auto & it : backup_scope )
if ( it . second = = NULL )
current_scope . erase ( it . first ) ;
else
current_scope [ it . first ] = it . second ;
return AstNode : : mkconst_bits ( variables . at ( str ) . val . bits , variables . at ( str ) . is_signed ) ;
}
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_END