2013-01-05 04:13:26 -06:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
* Copyright ( C ) 2012 Clifford Wolf < clifford @ clifford . at >
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* 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 ;
2020-01-19 15:15:51 -06:00
// Process a format string and arguments for $display, $write, $sprintf, etc
std : : string AstNode : : process_format_str ( const std : : string & sformat , int next_arg , int stage , int width_hint , bool sign_hint ) {
// Other arguments are placeholders. Process the string as we go through it
std : : string sout ;
for ( size_t i = 0 ; i < sformat . length ( ) ; i + + )
{
// format specifier
if ( sformat [ i ] = = ' % ' )
{
// If there's no next character, that's a problem
if ( i + 1 > = sformat . length ( ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System task `%s' called with `%%' at end of string. \n " , str . c_str ( ) ) ;
2020-01-19 15:15:51 -06:00
char cformat = sformat [ + + i ] ;
// %% is special, does not need a matching argument
if ( cformat = = ' % ' )
{
sout + = ' % ' ;
continue ;
}
2020-04-18 07:08:51 -05:00
bool got_len = false ;
bool got_zlen = false ;
int len_value = 0 ;
while ( ' 0 ' < = cformat & & cformat < = ' 9 ' )
{
if ( ! got_len & & cformat = = ' 0 ' )
got_zlen = true ;
got_len = true ;
len_value = 10 * len_value + ( cformat - ' 0 ' ) ;
cformat = sformat [ + + i ] ;
}
2020-01-19 15:15:51 -06:00
// Simplify the argument
AstNode * node_arg = nullptr ;
// Everything from here on depends on the format specifier
switch ( cformat )
{
case ' s ' :
case ' S ' :
case ' d ' :
case ' D ' :
2020-04-18 07:08:51 -05:00
if ( got_len )
goto unsupported_format ;
2020-05-04 14:12:30 -05:00
YS_FALLTHROUGH
2020-01-19 15:15:51 -06:00
case ' x ' :
case ' X ' :
if ( next_arg > = GetSize ( children ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Missing argument for %%%c format specifier in system task `%s'. \n " ,
2020-01-19 15:15:51 -06:00
cformat , str . c_str ( ) ) ;
node_arg = children [ next_arg + + ] ;
while ( node_arg - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_arg - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system task `%s' with non-constant argument. \n " , str . c_str ( ) ) ;
2020-01-19 15:15:51 -06:00
break ;
case ' m ' :
case ' M ' :
2020-04-18 07:08:51 -05:00
if ( got_len )
goto unsupported_format ;
2020-01-19 15:15:51 -06:00
break ;
default :
2020-04-18 07:08:51 -05:00
unsupported_format :
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System task `%s' called with invalid/unsupported format specifier. \n " , str . c_str ( ) ) ;
2020-01-19 15:15:51 -06:00
break ;
}
switch ( cformat )
{
case ' s ' :
case ' S ' :
sout + = node_arg - > bitsAsConst ( ) . decode_string ( ) ;
break ;
case ' d ' :
case ' D ' :
2020-04-18 07:08:51 -05:00
sout + = stringf ( " %d " , node_arg - > bitsAsConst ( ) . as_int ( ) ) ;
2020-01-19 15:15:51 -06:00
break ;
case ' x ' :
case ' X ' :
{
2020-04-18 07:08:51 -05:00
Const val = node_arg - > bitsAsConst ( ) ;
while ( GetSize ( val ) % 4 ! = 0 )
val . bits . push_back ( State : : S0 ) ;
int len = GetSize ( val ) / 4 ;
for ( int i = len ; i < len_value ; i + + )
sout + = got_zlen ? ' 0 ' : ' ' ;
for ( int i = len - 1 ; i > = 0 ; i - - ) {
Const digit = val . extract ( 4 * i , 4 ) ;
if ( digit . is_fully_def ( ) )
sout + = stringf ( cformat = = ' x ' ? " %x " : " %X " , digit . as_int ( ) ) ;
else
sout + = cformat = = ' x ' ? " x " : " X " ;
}
2020-01-19 15:15:51 -06:00
}
break ;
case ' m ' :
case ' M ' :
sout + = log_id ( current_module - > name ) ;
break ;
default :
log_abort ( ) ;
}
}
// not a format specifier
else
sout + = sformat [ i ] ;
}
return sout ;
}
2020-05-08 08:40:49 -05:00
void AstNode : : annotateTypedEnums ( AstNode * template_node )
{
//check if enum
if ( template_node - > attributes . count ( ID : : enum_type ) ) {
//get reference to enum node:
std : : string enum_type = template_node - > attributes [ ID : : enum_type ] - > str . c_str ( ) ;
// log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type));
// log("current scope:\n");
// for (auto &it : current_scope)
// log(" %s\n", it.first.c_str());
log_assert ( current_scope . count ( enum_type ) = = 1 ) ;
AstNode * enum_node = current_scope . at ( enum_type ) ;
log_assert ( enum_node - > type = = AST_ENUM ) ;
//get width from 1st enum item:
log_assert ( enum_node - > children . size ( ) > = 1 ) ;
AstNode * enum_item0 = enum_node - > children [ 0 ] ;
log_assert ( enum_item0 - > type = = AST_ENUM_ITEM ) ;
int width ;
if ( ! enum_item0 - > range_valid )
width = 1 ;
else if ( enum_item0 - > range_swapped )
width = enum_item0 - > range_right - enum_item0 - > range_left + 1 ;
else
width = enum_item0 - > range_left - enum_item0 - > range_right + 1 ;
log_assert ( width > 0 ) ;
//add declared enum items:
for ( auto enum_item : enum_node - > children ) {
log_assert ( enum_item - > type = = AST_ENUM_ITEM ) ;
//get is_signed
bool is_signed ;
if ( enum_item - > children . size ( ) = = 1 ) {
is_signed = false ;
} else if ( enum_item - > children . size ( ) = = 2 ) {
log_assert ( enum_item - > children [ 1 ] - > type = = AST_RANGE ) ;
is_signed = enum_item - > children [ 1 ] - > is_signed ;
} else {
log_error ( " enum_item children size==%lu, expected 1 or 2 for %s (%s) \n " ,
enum_item - > children . size ( ) ,
enum_item - > str . c_str ( ) , enum_node - > str . c_str ( )
) ;
}
//start building attribute string
std : : string enum_item_str = " \\ enum_value_ " ;
//get enum item value
if ( enum_item - > children [ 0 ] - > type ! = AST_CONSTANT ) {
log_error ( " expected const, got %s for %s (%s) \n " ,
type2str ( enum_item - > children [ 0 ] - > type ) . c_str ( ) ,
enum_item - > str . c_str ( ) , enum_node - > str . c_str ( )
) ;
}
RTLIL : : Const val = enum_item - > children [ 0 ] - > bitsAsConst ( width , is_signed ) ;
enum_item_str . append ( val . as_string ( ) ) ;
//set attribute for available val to enum item name mappings
attributes [ enum_item_str . c_str ( ) ] = mkconst_str ( enum_item - > str ) ;
}
}
}
static bool name_has_dot ( const std : : string & name , std : : string & struct_name )
{
// check if plausible struct member name \sss.mmm
std : : string : : size_type pos ;
if ( name . substr ( 0 , 1 ) = = " \\ " & & ( pos = name . find ( ' . ' , 0 ) ) ! = std : : string : : npos ) {
struct_name = name . substr ( 0 , pos ) ;
return true ;
}
return false ;
}
static AstNode * make_range ( int left , int right , bool is_signed = false )
{
// generate a pre-validated range node for a fixed signal range.
auto range = new AstNode ( AST_RANGE ) ;
range - > range_left = left ;
range - > range_right = right ;
range - > range_valid = true ;
range - > children . push_back ( AstNode : : mkconst_int ( left , true ) ) ;
range - > children . push_back ( AstNode : : mkconst_int ( right , true ) ) ;
range - > is_signed = is_signed ;
return range ;
}
2020-06-07 12:28:45 -05:00
static int range_width ( AstNode * node , AstNode * rnode )
{
log_assert ( rnode - > type = = AST_RANGE ) ;
if ( ! rnode - > range_valid ) {
log_file_error ( node - > filename , node - > location . first_line , " Size must be constant in packed struct/union member %s \n " , node - > str . c_str ( ) ) ;
}
// note: range swapping has already been checked for
return rnode - > range_left - rnode - > range_right + 1 ;
}
[[noreturn]] static void struct_array_packing_error ( AstNode * node )
{
log_file_error ( node - > filename , node - > location . first_line , " Unpacked array in packed struct/union member %s \n " , node - > str . c_str ( ) ) ;
}
static void save_struct_array_width ( AstNode * node , int width )
{
// stash the stride for the array
node - > multirange_dimensions . push_back ( width ) ;
}
static int get_struct_array_width ( AstNode * node )
{
// the stride for the array, 1 if not an array
return ( node - > multirange_dimensions . empty ( ) ? 1 : node - > multirange_dimensions . back ( ) ) ;
}
static int size_packed_struct ( AstNode * snode , int base_offset )
2020-05-12 08:25:33 -05:00
{
// Struct members will be laid out in the structure contiguously from left to right.
// Union members all have zero offset from the start of the union.
// Determine total packed size and assign offsets. Store these in the member node.
bool is_union = ( snode - > type = = AST_UNION ) ;
int offset = 0 ;
int packed_width = - 1 ;
// examine members from last to first
for ( auto it = snode - > children . rbegin ( ) ; it ! = snode - > children . rend ( ) ; + + it ) {
auto node = * it ;
int width ;
if ( node - > type = = AST_STRUCT | | node - > type = = AST_UNION ) {
// embedded struct or union
width = size_packed_struct ( node , base_offset + offset ) ;
}
else {
log_assert ( node - > type = = AST_STRUCT_ITEM ) ;
2020-06-07 12:28:45 -05:00
if ( node - > children . size ( ) > 0 & & node - > children [ 0 ] - > type = = AST_RANGE ) {
// member width e.g. bit [7:0] a
width = range_width ( node , node - > children [ 0 ] ) ;
if ( node - > children . size ( ) = = 2 ) {
if ( node - > children [ 1 ] - > type = = AST_RANGE ) {
// unpacked array e.g. bit [63:0] a [0:3]
auto rnode = node - > children [ 1 ] ;
int array_count = range_width ( node , rnode ) ;
if ( array_count = = 1 ) {
// C-type array size e.g. bit [63:0] a [4]
array_count = rnode - > range_left ;
}
save_struct_array_width ( node , width ) ;
width * = array_count ;
}
else {
// array element must be single bit for a packed array
struct_array_packing_error ( node ) ;
}
}
// range nodes are now redundant
node - > children . clear ( ) ;
}
else if ( node - > children . size ( ) = = 1 & & node - > children [ 0 ] - > type = = AST_MULTIRANGE ) {
// packed 2D array, e.g. bit [3:0][63:0] a
2020-05-12 08:25:33 -05:00
auto rnode = node - > children [ 0 ] ;
2020-06-07 12:28:45 -05:00
if ( rnode - > children . size ( ) ! = 2 ) {
// packed arrays can only be 2D
struct_array_packing_error ( node ) ;
}
int array_count = range_width ( node , rnode - > children [ 0 ] ) ;
width = range_width ( node , rnode - > children [ 1 ] ) ;
save_struct_array_width ( node , width ) ;
width * = array_count ;
2020-05-12 08:25:33 -05:00
// range nodes are now redundant
node - > children . clear ( ) ;
}
else if ( node - > range_left < 0 ) {
// 1 bit signal: bit, logic or reg
width = 1 ;
}
else {
// already resolved and compacted
width = node - > range_left - node - > range_right + 1 ;
}
if ( is_union ) {
node - > range_right = base_offset ;
node - > range_left = base_offset + width - 1 ;
}
else {
node - > range_right = base_offset + offset ;
node - > range_left = base_offset + offset + width - 1 ;
}
node - > range_valid = true ;
}
if ( is_union ) {
// check that all members have the same size
if ( packed_width = = - 1 ) {
// first member
packed_width = width ;
}
else {
if ( packed_width ! = width ) {
log_file_error ( node - > filename , node - > location . first_line , " member %s of a packed union has %d bits, expecting %d \n " , node - > str . c_str ( ) , width , packed_width ) ;
}
}
}
else {
offset + = width ;
}
}
return ( is_union ? packed_width : offset ) ;
}
2020-06-07 12:28:45 -05:00
[[noreturn]] static void struct_op_error ( AstNode * node )
{
log_file_error ( node - > filename , node - > location . first_line , " Unsupported operation for struct/union member %s \n " , node - > str . c_str ( ) + 1 ) ;
}
static AstNode * node_int ( int ival )
{
// maybe mkconst_int should have default values for the common integer case
return AstNode : : mkconst_int ( ival , true , 32 ) ;
}
static AstNode * offset_indexed_range ( int offset_right , int stride , AstNode * left_expr , AstNode * right_expr )
{
// adjust the range expressions to add an offset into the struct
// and maybe index using an array stride
auto left = left_expr - > clone ( ) ;
auto right = right_expr - > clone ( ) ;
if ( stride = = 1 ) {
// just add the offset
left = new AstNode ( AST_ADD , node_int ( offset_right ) , left ) ;
right = new AstNode ( AST_ADD , node_int ( offset_right ) , right ) ;
}
else {
// newleft = offset_right - 1 + (left + 1) * stride
left = new AstNode ( AST_ADD , new AstNode ( AST_SUB , node_int ( offset_right ) , node_int ( 1 ) ) ,
new AstNode ( AST_MUL , node_int ( stride ) , new AstNode ( AST_ADD , left , node_int ( 1 ) ) ) ) ;
// newright = offset_right + right * stride
right = new AstNode ( AST_ADD , node_int ( offset_right ) , new AstNode ( AST_MUL , right , node_int ( stride ) ) ) ;
}
return new AstNode ( AST_RANGE , left , right ) ;
}
static AstNode * make_struct_member_range ( AstNode * node , AstNode * member_node )
{
// Work out the range in the packed array that corresponds to a struct member
// taking into account any range operations applicable to the current node
// such as array indexing or slicing
int range_left = member_node - > range_left ;
int range_right = member_node - > range_right ;
if ( node - > children . empty ( ) ) {
// no range operations apply, return the whole width
}
else if ( node - > children . size ( ) = = 1 & & node - > children [ 0 ] - > type = = AST_RANGE ) {
auto rnode = node - > children [ 0 ] ;
int stride = get_struct_array_width ( member_node ) ;
if ( rnode - > children . size ( ) = = 1 ) {
// index e.g. s.a[i]
return offset_indexed_range ( range_right , stride , rnode - > children [ 0 ] , rnode - > children [ 0 ] ) ;
}
else if ( rnode - > children . size ( ) = = 2 ) {
// slice e.g. s.a[i:j]
return offset_indexed_range ( range_right , stride , rnode - > children [ 0 ] , rnode - > children [ 1 ] ) ;
}
else {
struct_op_error ( node ) ;
}
}
else {
// TODO multirange, i.e. bit slice after array index s.a[i][p:q]
struct_op_error ( node ) ;
}
return make_range ( range_left , range_right ) ;
}
2020-05-12 08:25:33 -05:00
static void add_members_to_scope ( AstNode * snode , std : : string name )
{
// add all the members in a struct or union to local scope
// in case later referenced in assignments
log_assert ( snode - > type = = AST_STRUCT | | snode - > type = = AST_UNION ) ;
for ( auto * node : snode - > children ) {
if ( node - > type ! = AST_STRUCT_ITEM ) {
// embedded struct or union
add_members_to_scope ( node , name + " . " + node - > str ) ;
}
else {
auto member_name = name + " . " + node - > str ;
current_scope [ member_name ] = node ;
}
}
}
static int get_max_offset ( AstNode * node )
{
// get the width from the MS member in the struct
// as members are laid out from left to right in the packed wire
log_assert ( node - > type = = AST_STRUCT | | node - > type = = AST_UNION ) ;
while ( node - > type ! = AST_STRUCT_ITEM ) {
node = node - > children [ 0 ] ;
}
return node - > range_left ;
}
2020-05-08 08:40:49 -05:00
static AstNode * make_packed_struct ( AstNode * template_node , std : : string & name )
{
// create a wire for the packed struct
auto wnode = new AstNode ( AST_WIRE ) ;
wnode - > str = name ;
wnode - > is_logic = true ;
wnode - > range_valid = true ;
2020-05-12 08:25:33 -05:00
wnode - > is_signed = template_node - > is_signed ;
int offset = get_max_offset ( template_node ) ;
2020-05-08 08:40:49 -05:00
auto range = make_range ( offset , 0 ) ;
wnode - > children . push_back ( range ) ;
// make sure this node is the one in scope for this name
current_scope [ name ] = wnode ;
2020-05-12 08:25:33 -05:00
// add all the struct members to scope under the wire's name
add_members_to_scope ( template_node , name ) ;
2020-05-08 08:40:49 -05:00
return wnode ;
}
2020-07-24 22:18:24 -05:00
// check if a node or its children contains an assignment to the given variable
static bool node_contains_assignment_to ( const AstNode * node , const AstNode * var )
{
if ( node - > type = = AST_ASSIGN_EQ | | node - > type = = AST_ASSIGN_LE ) {
// current node is iteslf an assignment
log_assert ( node - > children . size ( ) > = 2 ) ;
const AstNode * lhs = node - > children [ 0 ] ;
if ( lhs - > type = = AST_IDENTIFIER & & lhs - > str = = var - > str )
return false ;
}
for ( const AstNode * child : node - > children ) {
// if this child shadows the given variable
if ( child ! = var & & child - > str = = var - > str & & child - > type = = AST_WIRE )
break ; // skip the remainder of this block/scope
// depth-first short circuit
if ( ! node_contains_assignment_to ( child , var ) )
return false ;
}
return true ;
}
2015-08-14 03:56:05 -05:00
// convert the AST into a simpler AST that has all parameters substituted by their
2013-01-05 04:13:26 -06:00
// 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
{
2015-02-13 05:33:12 -06:00
static int recursion_counter = 0 ;
2015-02-20 03:33:20 -06:00
static bool deep_recursion_warning = false ;
if ( recursion_counter + + = = 1000 & & deep_recursion_warning ) {
log_warning ( " Deep recursion in AST simplifier. \n Does this design contain insanely long expressions? \n " ) ;
deep_recursion_warning = false ;
}
2015-02-13 05:33:12 -06:00
2013-01-05 04:13:26 -06:00
AstNode * newNode = NULL ;
bool did_something = false ;
2014-06-14 05:00:47 -05:00
#if 0
log ( " ------------- \n " ) ;
2020-02-23 01:19:52 -06:00
log ( " AST simplify[%d] depth %d at %s:%d on %s %p: \n " , stage , recursion_counter , filename . c_str ( ) , location . first_line , type2str ( type ) . c_str ( ) , this ) ;
2014-06-14 05:00:47 -05:00
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 ) ) ;
2015-02-20 03:21:36 -06:00
// dumpAst(NULL, "> ");
2014-06-14 05:00:47 -05:00
# endif
2013-01-05 04:13:26 -06:00
if ( stage = = 0 )
{
2018-10-11 16:33:31 -05:00
log_assert ( type = = AST_MODULE | | type = = AST_INTERFACE ) ;
2013-01-05 04:13:26 -06:00
2015-02-20 03:33:20 -06:00
deep_recursion_warning = true ;
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
2020-04-02 11:51:32 -05:00
if ( ! flag_nomem2reg & & ! get_bool_attribute ( ID : : 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 ;
2015-02-14 04:21:12 -06:00
bool this_nomeminit = flag_nomeminit ;
2014-07-28 04:08:55 -05:00
log_assert ( ( memflags & ~ 0x00ffff00 ) = = 0 ) ;
2013-11-21 06:49:00 -06:00
2020-04-02 11:51:32 -05:00
if ( mem - > get_bool_attribute ( ID : : nomem2reg ) )
2013-11-21 06:49:00 -06:00
continue ;
2020-04-02 11:51:32 -05:00
if ( mem - > get_bool_attribute ( ID : : nomeminit ) | | get_bool_attribute ( ID : : nomeminit ) )
2015-02-14 04:21:12 -06:00
this_nomeminit = true ;
2013-11-21 06:49:00 -06:00
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 ;
2015-02-14 04:21:12 -06:00
if ( ( memflags & AstNode : : MEM2REG_FL_SET_INIT ) & & ( memflags & AstNode : : MEM2REG_FL_SET_ELSE ) & & this_nomeminit )
2013-11-21 06:49:00 -06:00
goto verbose_activate ;
2014-06-17 14:39:25 -05:00
if ( memflags & AstNode : : MEM2REG_FL_CMPLX_LHS )
goto verbose_activate ;
2019-03-01 15:35:09 -06:00
if ( ( memflags & AstNode : : MEM2REG_FL_CONST_LHS ) & & ! ( memflags & AstNode : : MEM2REG_FL_VAR_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 ) ;
2019-03-21 16:19:17 -05:00
int data_range_left = node - > children [ 0 ] - > range_left ;
int data_range_right = node - > children [ 0 ] - > range_right ;
if ( node - > children [ 0 ] - > range_swapped )
std : : swap ( data_range_left , data_range_right ) ;
2013-01-05 04:13:26 -06:00
for ( int i = 0 ; i < mem_size ; i + + ) {
AstNode * reg = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE ,
2019-03-21 16:19:17 -05:00
mkconst_int ( data_range_left , true ) , mkconst_int ( data_range_right , true ) ) ) ;
2013-01-05 04:13:26 -06:00
reg - > str = stringf ( " %s[%d] " , node - > str . c_str ( ) , i ) ;
reg - > is_reg = true ;
reg - > is_signed = node - > is_signed ;
2019-08-21 15:36:01 -05:00
for ( auto & it : node - > attributes )
2020-04-02 11:51:32 -05:00
if ( it . first ! = ID : : mem2reg )
2019-08-22 18:57:59 -05:00
reg - > attributes . emplace ( it . first , it . second - > clone ( ) ) ;
2019-08-21 15:36:01 -05:00
reg - > filename = node - > filename ;
2020-02-23 01:19:52 -06:00
reg - > location = node - > location ;
2013-01-05 04:13:26 -06:00
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
}
}
2016-08-21 06:23:58 -05:00
AstNode * async_block = NULL ;
while ( mem2reg_as_needed_pass2 ( mem2reg_set , this , NULL , async_block ) ) { }
2013-01-05 04:13:26 -06:00
2016-05-27 10:25:33 -05:00
vector < AstNode * > delnodes ;
mem2reg_remove ( mem2reg_set , delnodes ) ;
for ( auto node : delnodes )
delete node ;
2013-01-05 04:13:26 -06:00
}
2014-02-14 12:56:44 -06:00
while ( simplify ( const_fold , at_zero , in_lvalue , 2 , width_hint , sign_hint , in_param ) ) { }
2015-02-13 05:33:12 -06:00
recursion_counter - - ;
2013-01-05 04:13:26 -06:00
return false ;
}
current_filename = filename ;
// we do not look inside a task or function
2015-08-14 03:56:05 -05:00
// (but as soon as a task or function is instantiated we process the generated AST as usual)
2015-02-13 05:33:12 -06:00
if ( type = = AST_FUNCTION | | type = = AST_TASK ) {
recursion_counter - - ;
2013-01-05 04:13:26 -06:00
return false ;
2015-02-13 05:33:12 -06:00
}
2013-01-05 04:13:26 -06:00
2015-08-14 03:56:05 -05:00
// deactivate all calls to non-synthesis system tasks
2016-03-21 10:19:51 -05:00
// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
if ( ( type = = AST_FCALL | | type = = AST_TCALL ) & & ( str = = " $strobe " | | str = = " $monitor " | | str = = " $time " | |
2015-01-15 06:08:19 -06:00
str = = " $dumpfile " | | str = = " $dumpvars " | | str = = " $dumpon " | | str = = " $dumpoff " | | str = = " $dumpall " ) ) {
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Ignoring call to system %s %s. \n " , type = = AST_FCALL ? " function " : " task " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
delete_children ( ) ;
str = std : : string ( ) ;
}
2015-09-23 00:16:03 -05:00
if ( ( type = = AST_TCALL ) & & ( str = = " $display " | | str = = " $write " ) & & ( ! current_always | | current_always - > type ! = AST_INITIAL ) ) {
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " System task `%s' outside initial block is unsupported. \n " , str . c_str ( ) ) ;
2015-09-23 00:16:03 -05:00
delete_children ( ) ;
str = std : : string ( ) ;
}
2015-09-17 22:34:56 -05:00
// print messages if this a call to $display() or $write()
// This code implements only a small subset of Verilog-2005 $display() format specifiers,
// but should be good enough for most uses
if ( ( type = = AST_TCALL ) & & ( ( str = = " $display " ) | | ( str = = " $write " ) ) )
{
2016-03-19 05:51:13 -05:00
int nargs = GetSize ( children ) ;
if ( nargs < 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System task `%s' got %d arguments, expected >= 1. \n " ,
2018-11-04 03:19:32 -06:00
str . c_str ( ) , int ( children . size ( ) ) ) ;
2015-09-17 22:34:56 -05:00
// First argument is the format string
2016-03-19 05:51:13 -05:00
AstNode * node_string = children [ 0 ] ;
2015-09-17 22:34:56 -05:00
while ( node_string - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_string - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system task `%s' with non-constant 1st argument. \n " , str . c_str ( ) ) ;
2015-09-17 22:34:56 -05:00
std : : string sformat = node_string - > bitsAsConst ( ) . decode_string ( ) ;
2020-01-19 15:15:51 -06:00
std : : string sout = process_format_str ( sformat , 1 , stage , width_hint , sign_hint ) ;
2015-09-17 22:34:56 -05:00
// Finally, print the message (only include a \n for $display, not for $write)
log ( " %s " , sout . c_str ( ) ) ;
2016-03-19 05:51:13 -05:00
if ( str = = " $display " )
2015-09-17 22:34:56 -05:00
log ( " \n " ) ;
delete_children ( ) ;
str = std : : string ( ) ;
}
2013-01-05 04:13:26 -06:00
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
2018-03-09 06:47:11 -06:00
if ( type = = AST_WIRE | | type = = AST_PARAMETER | | type = = AST_LOCALPARAM | | type = = AST_ENUM_ITEM | | type = = AST_DEFPARAM | | type = = AST_PARASET | | type = = AST_RANGE | | type = = AST_PREFIX | | type = = AST_TYPEDEF )
2014-02-14 13:45:30 -06:00
const_fold = true ;
2018-03-09 06:47:11 -06:00
if ( type = = AST_IDENTIFIER & & current_scope . count ( str ) > 0 & & ( current_scope [ str ] - > type = = AST_PARAMETER | | current_scope [ str ] - > type = = AST_LOCALPARAM | | current_scope [ str ] - > type = = AST_ENUM_ITEM ) )
2013-01-05 04:13:26 -06:00
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 ] ;
2019-09-19 14:43:13 -05:00
2013-01-05 04:13:26 -06:00
if ( node - > type = = AST_WIRE ) {
2019-03-02 14:36:46 -06:00
if ( node - > children . size ( ) = = 1 & & node - > children [ 0 ] - > type = = AST_RANGE ) {
for ( auto c : node - > children [ 0 ] - > children ) {
if ( ! c - > is_simple_const_expr ( ) ) {
2020-04-02 11:51:32 -05:00
if ( attributes . count ( ID : : dynports ) )
delete attributes . at ( ID : : dynports ) ;
attributes [ ID : : dynports ] = AstNode : : mkconst_int ( 1 , true ) ;
2019-03-02 14:36:46 -06:00
}
}
}
2013-01-05 04:13:26 -06:00
if ( this_wire_scope . count ( node - > str ) > 0 ) {
AstNode * first_node = this_wire_scope [ node - > str ] ;
2018-03-09 02:35:33 -06:00
if ( first_node - > is_input & & node - > is_reg )
goto wires_are_incompatible ;
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 ;
2018-03-09 02:35:33 -06:00
if ( node - > is_logic )
first_node - > is_logic = true ;
2013-01-05 04:13:26 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Incompatible re-declaration of wire %s. \n " , node - > str . c_str ( ) ) ;
2014-03-05 12:55:58 -06:00
continue ;
2013-01-05 04:13:26 -06:00
}
this_wire_scope [ node - > str ] = node ;
}
2018-03-09 06:47:11 -06:00
// these nodes appear at the top level in a module and can define names
2013-01-05 04:13:26 -06:00
if ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_WIRE | | node - > type = = AST_AUTOWIRE | | node - > type = = AST_GENVAR | |
2019-09-19 14:43:13 -05:00
node - > type = = AST_MEMORY | | node - > type = = AST_FUNCTION | | node - > type = = AST_TASK | | node - > type = = AST_DPI_FUNCTION | | node - > type = = AST_CELL | |
node - > type = = AST_TYPEDEF ) {
2013-01-05 04:13:26 -06:00
backup_scope [ node - > str ] = current_scope [ node - > str ] ;
current_scope [ node - > str ] = node ;
}
2018-03-09 06:47:11 -06:00
if ( node - > type = = AST_ENUM ) {
2020-02-03 00:12:24 -06:00
current_scope [ node - > str ] = node ;
2018-03-09 06:47:11 -06:00
for ( auto enode : node - > children ) {
log_assert ( enode - > type = = AST_ENUM_ITEM ) ;
2020-04-07 01:30:11 -05:00
if ( current_scope . count ( enode - > str ) = = 0 )
2018-03-09 06:47:11 -06:00
current_scope [ enode - > str ] = enode ;
2020-04-07 01:30:11 -05:00
else
log_file_error ( filename , location . first_line , " enum item %s already exists \n " , enode - > str . c_str ( ) ) ;
2018-03-09 06:47:11 -06:00
}
}
2013-01-05 04:13:26 -06:00
}
2013-11-24 12:40:23 -06:00
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * node = children [ i ] ;
2019-09-19 14:43:13 -05:00
if ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_WIRE | | node - > type = = AST_AUTOWIRE | | node - > type = = AST_MEMORY | | node - > type = = AST_TYPEDEF )
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 ;
2020-01-16 14:23:03 -06:00
if ( node - > type = = AST_ENUM ) {
2020-06-18 20:32:48 -05:00
for ( auto enode : node - > children ) {
2020-01-16 14:23:03 -06:00
log_assert ( enode - > type = = AST_ENUM_ITEM ) ;
2020-02-03 00:08:16 -06:00
while ( node - > simplify ( true , false , false , 1 , - 1 , false , in_param ) )
2020-01-16 14:23:03 -06:00
did_something = true ;
}
}
2013-11-24 12:40:23 -06:00
}
2013-01-05 04:13:26 -06:00
}
2020-04-06 23:37:44 -05:00
// create name resolution entries for all objects with names
if ( type = = AST_PACKAGE ) {
//add names to package scope
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * node = children [ i ] ;
// these nodes appear at the top level in a package and can define names
if ( node - > type = = AST_PARAMETER | | node - > type = = AST_LOCALPARAM | | node - > type = = AST_TYPEDEF ) {
current_scope [ node - > str ] = node ;
}
if ( node - > type = = AST_ENUM ) {
current_scope [ node - > str ] = node ;
for ( auto enode : node - > children ) {
log_assert ( enode - > type = = AST_ENUM_ITEM ) ;
if ( current_scope . count ( enode - > str ) = = 0 )
current_scope [ enode - > str ] = enode ;
else
log_file_error ( filename , location . first_line , " enum item %s already exists in package \n " , enode - > str . c_str ( ) ) ;
}
}
}
}
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 ;
2015-02-14 03:49:30 -06:00
auto backup_current_always = current_always ;
2016-09-06 10:34:42 -05:00
auto backup_current_always_clocked = current_always_clocked ;
2015-02-14 03:49:30 -06:00
if ( type = = AST_ALWAYS | | type = = AST_INITIAL )
2016-09-06 10:34:42 -05:00
{
2017-12-02 11:52:05 -06:00
if ( current_always ! = nullptr )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Invalid nesting of always blocks and/or initializations. \n " ) ;
2017-12-02 11:52:05 -06:00
2015-02-14 03:49:30 -06:00
current_always = this ;
2016-09-06 10:34:42 -05:00
current_always_clocked = false ;
if ( type = = AST_ALWAYS )
2017-10-10 04:59:32 -05:00
for ( auto child : children ) {
2016-09-06 10:34:42 -05:00
if ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE )
current_always_clocked = true ;
2017-10-10 04:59:32 -05:00
if ( child - > type = = AST_EDGE & & GetSize ( child - > children ) = = 1 & &
child - > children [ 0 ] - > type = = AST_IDENTIFIER & & child - > children [ 0 ] - > str = = " \\ $global_clock " )
current_always_clocked = true ;
}
2016-09-06 10:34:42 -05:00
}
2013-01-05 04:13:26 -06:00
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 ) ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , backup_width_hint ) ;
2013-11-03 23:04:42 -06:00
child_0_is_self_determined = true ;
2018-06-05 09:44:24 -05:00
// test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier
if ( children [ 0 ] - > id2ast & & ! children [ 0 ] - > was_checked ) {
if ( ( type = = AST_ASSIGN_LE | | type = = AST_ASSIGN_EQ ) & & children [ 0 ] - > id2ast - > is_logic )
children [ 0 ] - > id2ast - > is_reg = true ; // if logic type is used in a block asignment
if ( ( type = = AST_ASSIGN_LE | | type = = AST_ASSIGN_EQ ) & & ! children [ 0 ] - > id2ast - > is_reg )
2020-02-23 01:19:52 -06:00
log_warning ( " wire '%s' is assigned in a block at %s:%d.%d-%d.%d. \n " , children [ 0 ] - > str . c_str ( ) , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2018-11-01 09:25:24 -05:00
if ( type = = AST_ASSIGN & & children [ 0 ] - > id2ast - > is_reg ) {
bool is_rand_reg = false ;
if ( children [ 1 ] - > type = = AST_FCALL ) {
if ( children [ 1 ] - > str = = " \\ $anyconst " )
is_rand_reg = true ;
if ( children [ 1 ] - > str = = " \\ $anyseq " )
is_rand_reg = true ;
if ( children [ 1 ] - > str = = " \\ $allconst " )
is_rand_reg = true ;
if ( children [ 1 ] - > str = = " \\ $allseq " )
is_rand_reg = true ;
}
if ( ! is_rand_reg )
2020-02-23 01:19:52 -06:00
log_warning ( " reg '%s' is assigned in a continuous assignment at %s:%d.%d-%d.%d. \n " , children [ 0 ] - > str . c_str ( ) , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2018-11-01 09:25:24 -05:00
}
2018-06-05 09:44:24 -05:00
children [ 0 ] - > was_checked = true ;
}
2013-11-03 23:04:42 -06:00
break ;
2020-05-08 08:40:49 -05:00
case AST_STRUCT :
2020-05-12 08:25:33 -05:00
case AST_UNION :
2020-05-08 08:40:49 -05:00
if ( ! basic_prep ) {
for ( auto * node : children ) {
// resolve any ranges
while ( ! node - > basic_prep & & node - > simplify ( true , false , false , stage , - 1 , false , false ) ) {
did_something = true ;
}
}
2020-05-12 08:25:33 -05:00
// determine member offsets and widths
size_packed_struct ( this , 0 ) ;
// instance rather than just a type in a typedef or outer struct?
if ( ! str . empty ( ) & & str [ 0 ] = = ' \\ ' ) {
// instance so add a wire for the packed structure
2020-05-08 08:40:49 -05:00
auto wnode = make_packed_struct ( this , str ) ;
2020-05-12 08:25:33 -05:00
log_assert ( current_ast_mod ) ;
2020-05-08 08:40:49 -05:00
current_ast_mod - > children . push_back ( wnode ) ;
}
2020-05-12 08:25:33 -05:00
basic_prep = true ;
2020-05-08 08:40:49 -05:00
}
break ;
case AST_STRUCT_ITEM :
break ;
2018-03-09 06:47:11 -06:00
case AST_ENUM :
2020-02-03 00:08:16 -06:00
//log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep);
2018-03-09 06:47:11 -06:00
if ( ! basic_prep ) {
for ( auto item_node : children ) {
2020-02-03 00:08:16 -06:00
while ( ! item_node - > basic_prep & & item_node - > simplify ( false , false , false , stage , - 1 , false , in_param ) )
2018-03-09 06:47:11 -06:00
did_something = true ;
}
// allocate values (called more than once)
allocateDefaultEnumValues ( ) ;
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant width range on parameter decl. \n " ) ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , children [ 1 ] - > range_left - children [ 1 ] - > range_right + 1 ) ;
2013-11-07 02:58:15 -06:00
}
break ;
2020-02-03 00:08:16 -06:00
case AST_ENUM_ITEM :
while ( ! children [ 0 ] - > basic_prep & & children [ 0 ] - > simplify ( false , false , false , stage , - 1 , false , in_param ) )
did_something = true ;
children [ 0 ] - > detectSignWidth ( width_hint , sign_hint ) ;
if ( children . size ( ) > 1 & & children [ 1 ] - > type = = AST_RANGE ) {
while ( ! children [ 1 ] - > basic_prep & & children [ 1 ] - > simplify ( false , false , false , stage , - 1 , false , in_param ) )
did_something = true ;
if ( ! children [ 1 ] - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant width range on enum item decl. \n " ) ;
2020-02-03 00:08:16 -06:00
width_hint = max ( width_hint , children [ 1 ] - > range_left - children [ 1 ] - > range_right + 1 ) ;
}
break ;
2013-11-07 02:58:15 -06:00
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 :
2020-04-29 07:28:04 -05:00
case AST_SELFSZ :
2020-06-14 17:15:59 -05:00
case AST_CAST_SIZE :
2013-11-03 23:04:42 -06:00
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 ;
2015-07-02 04:14:30 -05:00
2013-11-03 23:04:42 -06:00
case AST_MEMRD :
detect_width_simple = true ;
children_are_self_determined = true ;
break ;
2016-09-18 18:30:07 -05:00
case AST_FCALL :
case AST_TCALL :
children_are_self_determined = true ;
break ;
2013-11-03 23:04:42 -06:00
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
}
2016-09-18 18:30:07 -05:00
if ( type = = AST_FCALL & & str = = " \\ $past " )
detectSignWidth ( width_hint , sign_hint ) ;
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 ;
}
}
2016-04-21 08:31:54 -05:00
if ( type = = AST_CONDX & & children . size ( ) > 0 & & children . at ( 0 ) - > type = = AST_CONSTANT ) {
for ( auto & bit : children . at ( 0 ) - > bits )
if ( bit = = State : : Sz | | bit = = State : : Sx )
bit = State : : Sa ;
}
if ( type = = AST_CONDZ & & children . size ( ) > 0 & & children . at ( 0 ) - > type = = AST_CONSTANT ) {
for ( auto & bit : children . at ( 0 ) - > bits )
if ( bit = = State : : Sz )
bit = State : : Sa ;
}
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 ] ;
2016-04-21 08:31:54 -05:00
log_assert ( child - > type = = AST_COND | | child - > type = = AST_CONDX | | child - > type = = AST_CONDZ ) ;
2014-10-29 02:29:51 -05:00
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 ;
2019-02-24 13:09:41 -06:00
bool backup_flag_autowire = flag_autowire ;
2013-01-05 04:13:26 -06:00
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 ;
2019-02-24 13:09:41 -06:00
if ( type = = AST_DEFPARAM & & i = = 0 )
flag_autowire = true ;
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 ;
2020-06-26 21:52:36 -05:00
if ( i = = 0 & & ( type = = AST_GENIF | | type = = AST_GENCASE ) )
in_param_here = true ;
if ( i = = 1 & & ( type = = AST_FOR | | type = = AST_GENFOR ) )
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
}
2019-02-24 13:09:41 -06:00
flag_autowire = backup_flag_autowire ;
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 ;
2015-02-14 03:49:30 -06:00
current_always = backup_current_always ;
2016-09-06 10:34:42 -05:00
current_always_clocked = backup_current_always_clocked ;
2013-01-05 04:13:26 -06:00
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 ;
if ( type = = AST_MODULE )
current_scope . clear ( ) ;
2013-07-04 07:12:33 -05:00
// convert defparam nodes to cell parameters
2016-11-15 06:35:19 -06:00
if ( type = = AST_DEFPARAM & & ! children . empty ( ) )
{
if ( children [ 0 ] - > type ! = AST_IDENTIFIER )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Module name in defparam contains non-constant expressions! \n " ) ;
2016-11-15 06:35:19 -06:00
string modname , paramname = children [ 0 ] - > str ;
size_t pos = paramname . rfind ( ' . ' ) ;
while ( pos ! = 0 & & pos ! = std : : string : : npos )
{
modname = paramname . substr ( 0 , pos ) ;
if ( current_scope . count ( modname ) )
break ;
pos = paramname . rfind ( ' . ' , pos - 1 ) ;
}
2013-07-04 07:12:33 -05:00
if ( pos = = std : : string : : npos )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Can't find object for defparam `%s`! \n " , RTLIL : : unescape_id ( paramname ) . c_str ( ) ) ;
2016-11-15 06:35:19 -06:00
paramname = " \\ " + paramname . substr ( pos + 1 ) ;
if ( current_scope . at ( modname ) - > type ! = AST_CELL )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Defparam argument `%s . %s` does not match a cell! \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( modname ) . c_str ( ) , RTLIL : : unescape_id ( paramname ) . c_str ( ) ) ;
2016-11-15 06:35:19 -06:00
AstNode * paraset = new AstNode ( AST_PARASET , children [ 1 ] - > clone ( ) , GetSize ( children ) > 2 ? children [ 2 ] - > clone ( ) : NULL ) ;
paraset - > str = paramname ;
AstNode * cell = current_scope . at ( modname ) ;
2013-07-04 07:12:33 -05:00
cell - > children . insert ( cell - > children . begin ( ) + 1 , paraset ) ;
2016-11-15 06:35:19 -06:00
delete_children ( ) ;
2013-07-04 07:12:33 -05:00
}
2019-09-19 14:43:13 -05:00
// resolve typedefs
if ( type = = AST_TYPEDEF ) {
log_assert ( children . size ( ) = = 1 ) ;
2020-05-08 08:40:49 -05:00
auto type_node = children [ 0 ] ;
2020-05-12 08:25:33 -05:00
log_assert ( type_node - > type = = AST_WIRE | | type_node - > type = = AST_MEMORY | | type_node - > type = = AST_STRUCT | | type_node - > type = = AST_UNION ) ;
2020-05-08 08:40:49 -05:00
while ( type_node - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ) {
2019-09-20 05:39:15 -05:00
did_something = true ;
2020-05-08 08:40:49 -05:00
}
log_assert ( ! type_node - > is_custom_type ) ;
2019-09-19 14:43:13 -05:00
}
2019-09-19 15:07:20 -05:00
// resolve types of wires
2019-09-20 05:46:37 -05:00
if ( type = = AST_WIRE | | type = = AST_MEMORY ) {
2019-09-19 14:43:13 -05:00
if ( is_custom_type ) {
2019-09-20 05:46:37 -05:00
log_assert ( children . size ( ) > = 1 ) ;
2019-09-19 14:43:13 -05:00
log_assert ( children [ 0 ] - > type = = AST_WIRETYPE ) ;
2020-05-08 08:40:49 -05:00
auto type_name = children [ 0 ] - > str ;
if ( ! current_scope . count ( type_name ) ) {
log_file_error ( filename , location . first_line , " Unknown identifier `%s' used as type name \n " , type_name . c_str ( ) ) ;
}
AstNode * resolved_type_node = current_scope . at ( type_name ) ;
if ( resolved_type_node - > type ! = AST_TYPEDEF )
log_file_error ( filename , location . first_line , " `%s' does not name a type \n " , type_name . c_str ( ) ) ;
log_assert ( resolved_type_node - > children . size ( ) = = 1 ) ;
AstNode * template_node = resolved_type_node - > children [ 0 ] ;
// Ensure typedef itself is fully simplified
while ( template_node - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ) { } ;
2020-05-12 08:25:33 -05:00
if ( template_node - > type = = AST_STRUCT | | template_node - > type = = AST_UNION ) {
2020-05-08 08:40:49 -05:00
// replace with wire representing the packed structure
newNode = make_packed_struct ( template_node , str ) ;
current_scope [ str ] = this ;
goto apply_newNode ;
}
2019-09-20 05:46:37 -05:00
// Remove type reference
delete children [ 0 ] ;
children . erase ( children . begin ( ) ) ;
2019-09-19 14:43:13 -05:00
2019-09-20 05:46:37 -05:00
if ( type = = AST_WIRE )
2020-05-08 08:40:49 -05:00
type = template_node - > type ;
is_reg = template_node - > is_reg ;
is_logic = template_node - > is_logic ;
is_signed = template_node - > is_signed ;
is_string = template_node - > is_string ;
is_custom_type = template_node - > is_custom_type ;
range_valid = template_node - > range_valid ;
range_swapped = template_node - > range_swapped ;
range_left = template_node - > range_left ;
range_right = template_node - > range_right ;
attributes [ ID : : wiretype ] = mkconst_str ( resolved_type_node - > str ) ;
// if an enum then add attributes to support simulator tracing
annotateTypedEnums ( template_node ) ;
2019-09-20 05:46:37 -05:00
// Insert clones children from template at beginning
2020-05-08 08:40:49 -05:00
for ( int i = 0 ; i < GetSize ( template_node - > children ) ; i + + )
children . insert ( children . begin ( ) + i , template_node - > children [ i ] - > clone ( ) ) ;
2018-03-09 06:47:11 -06:00
2019-09-20 05:46:37 -05:00
if ( type = = AST_MEMORY & & GetSize ( children ) = = 1 ) {
// Single-bit memories must have [0:0] range
2020-05-08 08:40:49 -05:00
AstNode * rng = make_range ( 0 , 0 ) ;
2019-09-20 05:46:37 -05:00
children . insert ( children . begin ( ) , rng ) ;
}
2019-09-20 05:39:15 -05:00
did_something = true ;
2019-09-19 14:43:13 -05:00
}
log_assert ( ! is_custom_type ) ;
}
2019-09-19 15:07:20 -05:00
// resolve types of parameters
if ( type = = AST_LOCALPARAM | | type = = AST_PARAMETER ) {
if ( is_custom_type ) {
log_assert ( children . size ( ) = = 2 ) ;
log_assert ( children [ 1 ] - > type = = AST_WIRETYPE ) ;
if ( ! current_scope . count ( children [ 1 ] - > str ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unknown identifier `%s' used as type name \n " , children [ 1 ] - > str . c_str ( ) ) ;
2020-05-08 08:40:49 -05:00
AstNode * resolved_type_node = current_scope . at ( children [ 1 ] - > str ) ;
if ( resolved_type_node - > type ! = AST_TYPEDEF )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " `%s' does not name a type \n " , children [ 1 ] - > str . c_str ( ) ) ;
2020-05-08 08:40:49 -05:00
log_assert ( resolved_type_node - > children . size ( ) = = 1 ) ;
AstNode * template_node = resolved_type_node - > children [ 0 ] ;
2019-09-19 15:07:20 -05:00
delete children [ 1 ] ;
children . pop_back ( ) ;
2019-09-19 15:21:21 -05:00
// Ensure typedef itself is fully simplified
2020-05-08 08:40:49 -05:00
while ( template_node - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ) { } ;
2019-09-19 15:21:21 -05:00
2020-05-08 08:40:49 -05:00
if ( template_node - > type = = AST_MEMORY )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " unpacked array type `%s' cannot be used for a parameter \n " , children [ 1 ] - > str . c_str ( ) ) ;
2020-05-08 08:40:49 -05:00
is_signed = template_node - > is_signed ;
is_string = template_node - > is_string ;
is_custom_type = template_node - > is_custom_type ;
range_valid = template_node - > range_valid ;
range_swapped = template_node - > range_swapped ;
range_left = template_node - > range_left ;
range_right = template_node - > range_right ;
attributes [ ID : : wiretype ] = mkconst_str ( resolved_type_node - > str ) ;
for ( auto template_child : template_node - > children )
2019-09-19 15:07:20 -05:00
children . push_back ( template_child - > clone ( ) ) ;
2019-09-20 05:39:15 -05:00
did_something = true ;
2019-09-19 15:07:20 -05:00
}
log_assert ( ! is_custom_type ) ;
2018-03-09 06:47:11 -06:00
}
2019-09-19 15:07:20 -05:00
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, "> ");
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Index in generate block prefix syntax is not constant! \n " ) ;
2013-02-26 06:18:22 -06:00
}
2015-09-22 13:52:02 -05:00
if ( children [ 1 ] - > type = = AST_PREFIX )
children [ 1 ] - > simplify ( const_fold , at_zero , in_lvalue , stage , width_hint , sign_hint , in_param ) ;
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Left operand of to_bits expression is not constant! \n " ) ;
2014-02-01 06:50:23 -06:00
if ( children [ 1 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Right operand of to_bits expression is not constant! \n " ) ;
2014-02-01 06:50:23 -06:00
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 ;
2020-05-04 14:18:20 -05:00
if ( range_valid & & range_right > range_left ) {
2013-01-05 04:13:26 -06:00
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 ;
2020-05-18 11:15:03 -05:00
bool force_upto = false , force_downto = false ;
if ( attributes . count ( ID : : force_upto ) ) {
AstNode * val = attributes [ ID : : force_upto ] ;
if ( val - > type ! = AST_CONSTANT )
log_file_error ( filename , location . first_line , " Attribute `force_upto' with non-constant value! \n " ) ;
force_upto = val - > asAttrConst ( ) . as_bool ( ) ;
}
if ( attributes . count ( ID : : force_downto ) ) {
AstNode * val = attributes [ ID : : force_downto ] ;
if ( val - > type ! = AST_CONSTANT )
log_file_error ( filename , location . first_line , " Attribute `force_downto' with non-constant value! \n " ) ;
force_downto = val - > asAttrConst ( ) . as_bool ( ) ;
}
if ( force_upto & & force_downto )
log_file_error ( filename , location . first_line , " Attributes `force_downto' and `force_upto' cannot be both set! \n " ) ;
if ( ( force_upto & & ! range_swapped ) | | ( force_downto & & range_swapped ) ) {
std : : swap ( range_left , range_right ) ;
range_swapped = force_upto ;
}
2013-01-05 04:13:26 -06:00
}
} 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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant range on memory decl. \n " ) ;
2015-10-25 13:30:49 -05:00
multirange_dimensions . push_back ( min ( range - > range_left , range - > range_right ) ) ;
multirange_dimensions . push_back ( max ( range - > range_left , range - > range_right ) - min ( range - > range_left , range - > range_right ) + 1 ) ;
2014-08-06 08:43:46 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Insufficient number of array indices for %s. \n " , log_id ( str ) ) ;
2014-08-06 08:43:46 -05:00
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
2015-09-23 00:56:17 -05:00
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-08-06 08:43:46 -05:00
}
2015-09-23 00:56:17 -05:00
for ( int i = GetSize ( id2ast - > multirange_dimensions ) / 2 ; 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
2018-03-09 06:47:11 -06:00
if ( type = = AST_PARAMETER | | type = = AST_LOCALPARAM | | type = = AST_ENUM_ITEM ) {
2014-06-14 05:00:47 -05:00
if ( children . size ( ) > 1 & & children [ 1 ] - > type = = AST_RANGE ) {
2014-06-14 13:38:05 -05:00
if ( ! children [ 1 ] - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant width range on parameter decl. \n " ) ;
2015-06-08 07:03:06 -05:00
int width = std : : abs ( 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 ) ;
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " converting real value %e to binary %s. \n " ,
2018-11-04 03:19:32 -06:00
children [ 0 ] - > realvalue , log_signal ( constvalue ) ) ;
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 ] ;
2016-03-18 06:15:00 -05:00
children [ 0 ] = mkconst_bits ( sig . as_const ( ) . bits , is_signed ) ;
2014-06-14 05:00:47 -05:00
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
}
}
2020-05-08 08:40:49 -05:00
if ( type = = AST_IDENTIFIER & & ! basic_prep ) {
// check if a plausible struct member sss.mmmm
std : : string sname ;
2020-06-07 12:28:45 -05:00
if ( name_has_dot ( str , sname ) ) {
2020-05-08 08:40:49 -05:00
if ( current_scope . count ( str ) > 0 ) {
auto item_node = current_scope [ str ] ;
if ( item_node - > type = = AST_STRUCT_ITEM ) {
// structure member, rewrite this node to reference the packed struct wire
2020-06-07 12:28:45 -05:00
auto range = make_struct_member_range ( this , item_node ) ;
2020-05-08 08:40:49 -05:00
newNode = new AstNode ( AST_IDENTIFIER , range ) ;
newNode - > str = sname ;
newNode - > basic_prep = true ;
goto apply_newNode ;
}
}
}
}
2020-06-07 12:28:45 -05:00
// annotate identifiers using scope resolution and create auto-wires as needed
2013-01-05 04:13:26 -06:00
if ( type = = AST_IDENTIFIER ) {
if ( current_scope . count ( str ) = = 0 ) {
2020-04-16 04:27:59 -05:00
AstNode * current_scope_ast = ( current_ast_mod = = nullptr ) ? current_ast : current_ast_mod ;
for ( auto node : current_scope_ast - > children ) {
2018-03-09 06:47:11 -06:00
//log("looking at mod scope child %s\n", type2str(node->type).c_str());
switch ( node - > type ) {
case AST_PARAMETER :
case AST_LOCALPARAM :
case AST_WIRE :
case AST_AUTOWIRE :
case AST_GENVAR :
case AST_MEMORY :
case AST_FUNCTION :
case AST_TASK :
case AST_DPI_FUNCTION :
//log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str());
2020-01-17 00:21:09 -06:00
if ( str = = node - > str ) {
2020-02-27 18:53:49 -06:00
//log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str());
2020-01-17 00:21:09 -06:00
current_scope [ node - > str ] = node ;
}
2013-01-05 04:13:26 -06:00
break ;
2018-03-09 06:47:11 -06:00
case AST_ENUM :
2013-01-05 04:13:26 -06:00
current_scope [ node - > str ] = node ;
2018-03-09 06:47:11 -06:00
for ( auto enum_node : node - > children ) {
log_assert ( enum_node - > type = = AST_ENUM_ITEM ) ;
if ( str = = enum_node - > str ) {
2020-02-03 00:12:24 -06:00
//log("\nadding enum item %s to scope\n", str.c_str());
2018-03-09 06:47:11 -06:00
current_scope [ str ] = enum_node ;
}
}
break ;
default :
2013-01-05 04:13:26 -06:00
break ;
}
}
}
if ( current_scope . count ( str ) = = 0 ) {
2020-04-16 04:27:59 -05:00
if ( current_ast_mod = = nullptr ) {
log_file_error ( filename , location . first_line , " Identifier `%s' is implicitly declared outside of a module. \n " , str . c_str ( ) ) ;
} else if ( flag_autowire | | str = = " \\ $global_clock " ) {
2019-02-21 11:40:11 -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 ;
} else {
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Identifier `%s' is implicitly declared and `default_nettype is set to none. \n " , str . c_str ( ) ) ;
2019-02-21 11:40:11 -06:00
}
2013-01-05 04:13:26 -06:00
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Invalid bit-select on memory access! \n " ) ;
2013-11-20 03:51:32 -06:00
int mem_width , mem_size , addr_bits ;
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
2016-08-22 07:27:46 -05:00
int data_range_left = id2ast - > children [ 0 ] - > range_left ;
int data_range_right = id2ast - > children [ 0 ] - > range_right ;
2019-03-21 16:19:17 -05:00
if ( id2ast - > children [ 0 ] - > range_swapped )
std : : swap ( data_range_left , data_range_right ) ;
2013-11-20 03:51:32 -06:00
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < " $mem2bits$ " < < str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( autoidx + + ) ;
2013-11-20 03:51:32 -06:00
std : : string wire_id = sstr . str ( ) ;
2016-08-22 07:27:46 -05:00
AstNode * wire = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( data_range_left , true ) , mkconst_int ( data_range_right , true ) ) ) ;
2013-11-20 03:51:32 -06:00
wire - > str = wire_id ;
if ( current_block )
2020-04-02 11:51:32 -05:00
wire - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2013-11-20 03:51:32 -06:00
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 ;
2018-06-05 09:44:24 -05:00
assign - > children [ 0 ] - > was_checked = true ;
2013-11-20 03:51:32 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " While loops are only allowed in constant functions! \n " ) ;
2014-06-06 15:55:02 -05:00
if ( type = = AST_REPEAT )
2019-04-09 11:28:32 -05:00
{
AstNode * count = children [ 0 ] ;
AstNode * body = children [ 1 ] ;
// eval count expression
while ( count - > simplify ( true , false , false , stage , 32 , true , false ) ) { }
if ( count - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Repeat loops outside must have constant repeat counts! \n " ) ;
2019-04-09 11:28:32 -05:00
// convert to a block with the body repeated n times
type = AST_BLOCK ;
children . clear ( ) ;
for ( int i = 0 ; i < count - > bitsAsConst ( ) . as_int ( ) ; i + + )
children . insert ( children . begin ( ) , body - > clone ( ) ) ;
delete count ;
delete body ;
did_something = true ;
}
2014-06-06 15:55:02 -05:00
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 ) ;
2020-07-25 11:35:03 -05:00
const char * loop_type_str = " procedural " ;
const char * var_type_str = " register " ;
AstNodeType var_type = AST_WIRE ;
if ( type = = AST_GENFOR ) {
loop_type_str = " generate " ;
var_type_str = " genvar " ;
var_type = AST_GENVAR ;
}
2013-01-05 04:13:26 -06:00
if ( init_ast - > type ! = AST_ASSIGN_EQ )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " Unsupported 1st expression of %s for-loop! \n " , loop_type_str ) ;
2013-01-05 04:13:26 -06:00
if ( next_ast - > type ! = AST_ASSIGN_EQ )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " Unsupported 3rd expression of %s for-loop! \n " , loop_type_str ) ;
2013-01-05 04:13:26 -06:00
2020-07-25 11:35:03 -05:00
if ( init_ast - > children [ 0 ] - > id2ast = = NULL | | init_ast - > children [ 0 ] - > id2ast - > type ! = var_type )
log_file_error ( filename , location . first_line , " Left hand side of 1st expression of %s for-loop is not a %s! \n " , loop_type_str , var_type_str ) ;
if ( next_ast - > children [ 0 ] - > id2ast = = NULL | | next_ast - > children [ 0 ] - > id2ast - > type ! = var_type )
log_file_error ( filename , location . first_line , " Left hand side of 3rd expression of %s for-loop is not a %s! \n " , loop_type_str , var_type_str ) ;
2013-01-05 04:13:26 -06:00
if ( init_ast - > children [ 0 ] - > id2ast ! = next_ast - > children [ 0 ] - > id2ast )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " Incompatible left-hand sides in 1st and 3rd expression of %s for-loop! \n " , loop_type_str ) ;
2013-01-05 04:13:26 -06:00
// eval 1st expression
AstNode * varbuf = init_ast - > children [ 1 ] - > clone ( ) ;
2019-04-22 11:19:02 -05:00
{
int expr_width_hint = - 1 ;
bool expr_sign_hint = true ;
varbuf - > detectSignWidth ( expr_width_hint , expr_sign_hint ) ;
while ( varbuf - > simplify ( true , false , false , stage , 32 , true , false ) ) { }
}
2013-01-05 04:13:26 -06:00
if ( varbuf - > type ! = AST_CONSTANT )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " Right hand side of 1st expression of %s for-loop is not constant! \n " , loop_type_str ) ;
2013-01-05 04:13:26 -06:00
2019-12-11 18:26:26 -06:00
auto resolved = current_scope . at ( init_ast - > children [ 0 ] - > str ) ;
if ( resolved - > range_valid ) {
2020-02-05 19:19:42 -06:00
int const_size = varbuf - > range_left - varbuf - > range_right ;
int resolved_size = resolved - > range_left - resolved - > range_right ;
if ( const_size < resolved_size ) {
for ( int i = const_size ; i < resolved_size ; i + + )
varbuf - > bits . push_back ( resolved - > is_signed ? varbuf - > bits . back ( ) : State : : S0 ) ;
varbuf - > range_left = resolved - > range_left ;
varbuf - > range_right = resolved - > range_right ;
varbuf - > range_swapped = resolved - > range_swapped ;
varbuf - > range_valid = resolved - > range_valid ;
}
2019-12-11 18:26:26 -06:00
}
2020-02-05 19:19:42 -06:00
varbuf = new AstNode ( AST_LOCALPARAM , varbuf ) ;
varbuf - > str = init_ast - > children [ 0 ] - > str ;
2013-01-05 04:13:26 -06:00
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 ( ) ;
2019-04-22 11:19:02 -05:00
{
int expr_width_hint = - 1 ;
bool expr_sign_hint = true ;
buf - > detectSignWidth ( expr_width_hint , expr_sign_hint ) ;
while ( buf - > simplify ( true , false , false , stage , expr_width_hint , expr_sign_hint , false ) ) { }
}
2013-01-05 04:13:26 -06:00
if ( buf - > type ! = AST_CONSTANT )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " 2nd expression of %s for-loop is not constant! \n " , loop_type_str ) ;
2013-01-05 04:13:26 -06:00
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 ;
2020-02-23 01:19:52 -06:00
sstr < < " $genblock$ " < < filename < < " : " < < location . first_line < < " $ " < < ( 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 ( ) ;
2019-04-22 11:19:02 -05:00
{
int expr_width_hint = - 1 ;
bool expr_sign_hint = true ;
buf - > detectSignWidth ( expr_width_hint , expr_sign_hint ) ;
while ( buf - > simplify ( true , false , false , stage , expr_width_hint , expr_sign_hint , true ) ) { }
}
2013-01-05 04:13:26 -06:00
if ( buf - > type ! = AST_CONSTANT )
2020-07-25 11:35:03 -05:00
log_file_error ( filename , location . first_line , " Right hand side of 3rd expression of %s for-loop is not constant (%s)! \n " , loop_type_str , type2str ( buf - > type ) . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
delete varbuf - > children [ 0 ] ;
varbuf - > children [ 0 ] = buf ;
}
2019-04-30 08:03:32 -05:00
if ( type = = AST_FOR ) {
AstNode * buf = next_ast - > clone ( ) ;
delete buf - > children [ 1 ] ;
buf - > children [ 1 ] = varbuf - > children [ 0 ] - > clone ( ) ;
current_block - > children . insert ( current_block - > children . begin ( ) + current_block_idx + + , buf ) ;
}
2013-01-05 04:13:26 -06:00
current_scope [ varbuf - > str ] = backup_scope_varbuf ;
delete varbuf ;
delete_children ( ) ;
did_something = true ;
}
2017-01-04 09:03:04 -06:00
// check for local objects in unnamed block
if ( type = = AST_BLOCK & & str . empty ( ) )
{
for ( size_t i = 0 ; i < children . size ( ) ; i + + )
2019-09-19 14:43:13 -05:00
if ( children [ i ] - > type = = AST_WIRE | | children [ i ] - > type = = AST_MEMORY | | children [ i ] - > type = = AST_PARAMETER | | children [ i ] - > type = = AST_LOCALPARAM | | children [ i ] - > type = = AST_TYPEDEF )
2020-02-23 01:19:52 -06:00
log_file_error ( children [ i ] - > filename , children [ i ] - > location . first_line , " Local declaration in unnamed block is an unsupported SystemVerilog feature! \n " ) ;
2017-01-04 09:03:04 -06:00
}
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 + + )
2019-09-19 14:43:13 -05:00
if ( children [ i ] - > type = = AST_WIRE | | children [ i ] - > type = = AST_MEMORY | | children [ i ] - > type = = AST_PARAMETER | | children [ i ] - > type = = AST_LOCALPARAM | | children [ i ] - > type = = AST_TYPEDEF ) {
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> ");
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Condition for generate if is not constant! \n " ) ;
2013-01-05 04:13:26 -06:00
}
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> ");
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Condition for generate case is not constant! \n " ) ;
2013-12-04 14:06:54 -06:00
}
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 + + )
{
2016-04-21 08:31:54 -05:00
log_assert ( children . at ( i ) - > type = = AST_COND | | children . at ( i ) - > type = = AST_CONDX | | children . at ( i ) - > type = = AST_CONDZ ) ;
2013-12-04 14:06:54 -06:00
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 ( ) ;
2020-06-26 21:52:36 -05:00
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , true ) ) { }
2013-12-04 14:06:54 -06:00
if ( buf - > type ! = AST_CONSTANT ) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Expression in generate case is not constant! \n " ) ;
2013-12-04 14:06:54 -06:00
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant array range on cell array. \n " ) ;
2014-06-07 04:48:50 -05:00
newNode = new AstNode ( AST_GENBLOCK ) ;
2015-10-25 13:30:49 -05:00
int num = max ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) - min ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) + 1 ;
2014-06-07 04:48:50 -05:00
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 ) {
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Cell arrays of primitives are currently not supported. \n " ) ;
2014-06-07 04:48:50 -05:00
} 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 ;
}
2015-08-14 03:56:05 -05:00
// replace primitives with assignments
2013-01-05 04:13:26 -06:00
if ( type = = AST_PRIMITIVE )
{
if ( children . size ( ) < 2 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Insufficient number of arguments for primitive `%s'! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Invalid number of arguments for primitive `%s'! \n " , str . c_str ( ) ) ;
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 ) ) ;
2018-09-17 17:23:40 -05:00
children . back ( ) - > was_checked = true ;
2013-08-19 12:50:04 -05:00
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 )
2020-05-04 12:22:05 -05:00
for ( size_t i = 2 ; i < children_list . size ( ) ; i + + ) {
2013-08-19 12:50:04 -05:00
node = new AstNode ( op_type , node , children_list [ i ] ) ;
2020-05-04 12:22:05 -05:00
node - > location = location ;
}
2013-08-19 12:50:04 -05:00
if ( invert_results )
node = new AstNode ( AST_BIT_NOT , node ) ;
str . clear ( ) ;
type = AST_ASSIGN ;
children . push_back ( children_list [ 0 ] ) ;
2018-09-17 17:23:40 -05:00
children . back ( ) - > was_checked = true ;
2013-08-19 12:50:04 -05:00
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
2020-04-01 05:43:42 -05:00
// either a big case block that selects the correct single-bit assignment, or mask and
// shift operations.
if ( type = = AST_ASSIGN_EQ | | type = = AST_ASSIGN_LE )
{
2013-01-05 04:13:26 -06:00
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 ;
2020-04-01 05:43:42 -05:00
2013-01-05 04:13:26 -06:00
int source_width = children [ 0 ] - > id2ast - > range_left - children [ 0 ] - > id2ast - > range_right + 1 ;
int result_width = 1 ;
2020-04-01 05:43:42 -05:00
2013-01-05 04:13:26 -06:00
AstNode * shift_expr = NULL ;
AstNode * range = children [ 0 ] - > children [ 0 ] ;
2020-04-01 05:43:42 -05:00
2013-01-05 04:13:26 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unsupported expression on dynamic range select on signal `%s'! \n " , str . c_str ( ) ) ;
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
}
2020-04-01 05:43:42 -05:00
2020-04-27 10:04:47 -05:00
bool use_case_method = false ;
if ( children [ 0 ] - > id2ast - > attributes . count ( ID : : nowrshmsk ) ) {
AstNode * node = children [ 0 ] - > id2ast - > attributes . at ( ID : : nowrshmsk ) ;
while ( node - > simplify ( true , false , false , stage , - 1 , false , false ) ) { }
if ( node - > type ! = AST_CONSTANT )
log_file_error ( filename , location . first_line , " Non-constant value for `nowrshmsk' attribute on `%s'! \n " , children [ 0 ] - > id2ast - > str . c_str ( ) ) ;
if ( node - > asAttrConst ( ) . as_bool ( ) )
use_case_method = true ;
}
2020-06-04 16:10:03 -05:00
if ( ! use_case_method & & current_always - > detect_latch ( children [ 0 ] - > str ) )
use_case_method = true ;
2020-04-27 10:04:47 -05:00
if ( use_case_method )
2020-04-01 05:43:42 -05:00
{
// big case block
did_something = true ;
newNode = new AstNode ( AST_CASE , shift_expr ) ;
for ( int i = 0 ; i < source_width ; i + + ) {
int start_bit = children [ 0 ] - > id2ast - > range_right + i ;
2020-04-27 10:04:47 -05:00
int end_bit = std : : min ( start_bit + result_width , source_width ) - 1 ;
2020-04-01 05:43:42 -05:00
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 ( end_bit , 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 ) ;
}
}
else
{
// mask and shift operations, disabled for now
AstNode * wire_mask = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( source_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_mask - > str = stringf ( " $bitselwrite$mask$%s:%d$%d " , filename . c_str ( ) , location . first_line , autoidx + + ) ;
2020-05-04 12:48:37 -05:00
wire_mask - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2020-04-01 05:43:42 -05:00
wire_mask - > is_logic = true ;
while ( wire_mask - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
current_ast_mod - > children . push_back ( wire_mask ) ;
AstNode * wire_data = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( source_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_data - > str = stringf ( " $bitselwrite$data$%s:%d$%d " , filename . c_str ( ) , location . first_line , autoidx + + ) ;
2020-05-04 12:48:37 -05:00
wire_data - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2020-04-01 05:43:42 -05:00
wire_data - > is_logic = true ;
while ( wire_data - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
current_ast_mod - > children . push_back ( wire_data ) ;
did_something = true ;
newNode = new AstNode ( AST_BLOCK ) ;
2013-01-05 04:13:26 -06:00
AstNode * lvalue = children [ 0 ] - > clone ( ) ;
lvalue - > delete_children ( ) ;
2020-04-01 05:43:42 -05:00
AstNode * ref_mask = new AstNode ( AST_IDENTIFIER ) ;
ref_mask - > str = wire_mask - > str ;
2020-04-15 13:36:40 -05:00
ref_mask - > id2ast = wire_mask ;
2020-04-01 05:43:42 -05:00
ref_mask - > was_checked = true ;
AstNode * ref_data = new AstNode ( AST_IDENTIFIER ) ;
ref_data - > str = wire_data - > str ;
2020-04-15 13:36:40 -05:00
ref_data - > id2ast = wire_data ;
2020-04-01 05:43:42 -05:00
ref_data - > was_checked = true ;
2020-04-15 13:36:40 -05:00
AstNode * old_data = lvalue - > clone ( ) ;
if ( type = = AST_ASSIGN_LE )
old_data - > lookahead = true ;
2020-04-01 05:43:42 -05:00
AstNode * shamt = shift_expr ;
2020-04-29 07:28:04 -05:00
int shamt_width_hint = 0 ;
bool shamt_sign_hint = true ;
shamt - > detectSignWidth ( shamt_width_hint , shamt_sign_hint ) ;
2020-04-27 10:04:47 -05:00
int start_bit = children [ 0 ] - > id2ast - > range_right ;
2020-04-29 07:28:04 -05:00
bool use_shift = shamt_sign_hint ;
2020-04-27 10:04:47 -05:00
if ( start_bit ! = 0 ) {
shamt = new AstNode ( AST_SUB , shamt , mkconst_int ( start_bit , true ) ) ;
use_shift = true ;
}
AstNode * t ;
t = mkconst_bits ( std : : vector < RTLIL : : State > ( result_width , State : : S1 ) , false ) ;
if ( use_shift )
t = new AstNode ( AST_SHIFT , t , new AstNode ( AST_NEG , shamt - > clone ( ) ) ) ;
else
t = new AstNode ( AST_SHIFT_LEFT , t , shamt - > clone ( ) ) ;
t = new AstNode ( AST_ASSIGN_EQ , ref_mask - > clone ( ) , t ) ;
newNode - > children . push_back ( t ) ;
t = new AstNode ( AST_BIT_AND , mkconst_bits ( std : : vector < RTLIL : : State > ( result_width , State : : S1 ) , false ) , children [ 1 ] - > clone ( ) ) ;
if ( use_shift )
t = new AstNode ( AST_SHIFT , t , new AstNode ( AST_NEG , shamt ) ) ;
else
t = new AstNode ( AST_SHIFT_LEFT , t , shamt ) ;
t = new AstNode ( AST_ASSIGN_EQ , ref_data - > clone ( ) , t ) ;
newNode - > children . push_back ( t ) ;
t = new AstNode ( AST_BIT_AND , old_data , new AstNode ( AST_BIT_NOT , ref_mask ) ) ;
t = new AstNode ( AST_BIT_OR , t , ref_data ) ;
t = new AstNode ( type , lvalue , t ) ;
newNode - > children . push_back ( t ) ;
2013-01-05 04:13:26 -06:00
}
2020-04-01 05:43:42 -05:00
2013-01-05 04:13:26 -06:00
goto apply_newNode ;
}
skip_dynamic_range_lvalue_expansion : ;
2017-02-25 03:36:39 -06:00
if ( stage > 1 & & ( type = = AST_ASSERT | | type = = AST_ASSUME | | type = = AST_LIVE | | type = = AST_FAIR | | type = = AST_COVER ) & & current_block ! = NULL )
2014-01-19 07:03:40 -06:00
{
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < " $formal$ " < < filename < < " : " < < location . first_line < < " $ " < < ( 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 ;
2018-06-05 09:44:24 -05:00
wire_check - > was_checked = true ;
2014-01-19 07:03:40 -06:00
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 ;
2018-06-05 09:44:24 -05:00
wire_en - > was_checked = true ;
2014-01-19 07:03:40 -06:00
current_ast_mod - > children . push_back ( wire_en ) ;
2016-09-06 10:34:42 -05:00
if ( current_always_clocked ) {
2016-07-13 09:56:17 -05: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 ;
2018-06-05 09:44:24 -05:00
current_ast_mod - > children . back ( ) - > children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > was_checked = true ;
2016-07-13 09:56:17 -05:00
}
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
2019-09-02 15:56:38 -05:00
AstNode * check_defval ;
if ( type = = AST_LIVE | | type = = AST_FAIR ) {
check_defval = new AstNode ( AST_REDUCE_BOOL , children [ 0 ] - > clone ( ) ) ;
} else {
std : : vector < RTLIL : : State > x_bit ;
x_bit . push_back ( RTLIL : : State : : Sx ) ;
check_defval = mkconst_bits ( x_bit , false ) ;
}
2014-01-19 07:03:40 -06:00
2019-09-02 15:56:38 -05:00
AstNode * assign_check = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , check_defval ) ;
2014-01-19 07:03:40 -06:00
assign_check - > children [ 0 ] - > str = id_check ;
2018-06-05 09:44:24 -05:00
assign_check - > children [ 0 ] - > was_checked = true ;
2014-01-19 07:03:40 -06:00
AstNode * assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 0 , false , 1 ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
2014-01-19 07:03:40 -06:00
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 ) ;
2019-09-02 15:56:38 -05:00
if ( type = = AST_LIVE | | type = = AST_FAIR ) {
assign_check = nullptr ;
} else {
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_check - > children [ 0 ] - > was_checked = true ;
}
2014-01-19 07:03:40 -06:00
2016-07-21 07:37:28 -05:00
if ( current_always = = nullptr | | current_always - > type ! = AST_INITIAL ) {
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 1 , false , 1 ) ) ;
} else {
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , new AstNode ( AST_FCALL ) ) ;
assign_en - > children [ 1 ] - > str = " \\ $initstate " ;
}
2014-01-19 07:03:40 -06:00
assign_en - > children [ 0 ] - > str = id_en ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
2014-01-19 07:03:40 -06:00
newNode = new AstNode ( AST_BLOCK ) ;
2019-09-02 15:56:38 -05:00
if ( assign_check ! = nullptr )
newNode - > children . push_back ( assign_check ) ;
2014-01-19 07:03:40 -06:00
newNode - > children . push_back ( assign_en ) ;
2015-02-26 11:47:39 -06:00
AstNode * assertnode = new AstNode ( type ) ;
2020-03-17 00:00:12 -05:00
assertnode - > location = location ;
2019-03-07 13:17:32 -06:00
assertnode - > str = str ;
2014-01-19 07:03:40 -06:00
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 ;
}
2017-02-25 03:36:39 -06:00
if ( stage > 1 & & ( type = = AST_ASSERT | | type = = AST_ASSUME | | type = = AST_LIVE | | type = = AST_FAIR | | type = = AST_COVER ) & & children . size ( ) = = 1 )
2014-01-19 07:03:40 -06:00
{
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 & &
2015-08-22 07:46:42 -05:00
children . size ( ) = = 1 & & children [ 0 ] - > type = = AST_RANGE & & children [ 0 ] - > children . size ( ) = = 1 ) {
2013-01-05 04:13:26 -06:00
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 ;
}
2016-07-08 07:31:06 -05:00
// assignment with nontrivial member in left-hand concat expression -> split assignment
if ( ( type = = AST_ASSIGN_EQ | | type = = AST_ASSIGN_LE ) & & children [ 0 ] - > type = = AST_CONCAT & & width_hint > 0 )
{
bool found_nontrivial_member = false ;
for ( auto child : children [ 0 ] - > children ) {
if ( child - > type = = AST_IDENTIFIER & & child - > id2ast ! = NULL & & child - > id2ast - > type = = AST_MEMORY )
found_nontrivial_member = true ;
}
if ( found_nontrivial_member )
{
newNode = new AstNode ( AST_BLOCK ) ;
AstNode * wire_tmp = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( width_hint - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
2020-02-23 01:19:52 -06:00
wire_tmp - > str = stringf ( " $splitcmplxassign$%s:%d$%d " , filename . c_str ( ) , location . first_line , autoidx + + ) ;
2016-07-08 07:31:06 -05:00
current_ast_mod - > children . push_back ( wire_tmp ) ;
current_scope [ wire_tmp - > str ] = wire_tmp ;
2020-04-02 11:51:32 -05:00
wire_tmp - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2016-07-08 07:31:06 -05:00
while ( wire_tmp - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2019-05-01 03:01:54 -05:00
wire_tmp - > is_logic = true ;
2016-07-08 07:31:06 -05:00
AstNode * wire_tmp_id = new AstNode ( AST_IDENTIFIER ) ;
wire_tmp_id - > str = wire_tmp - > str ;
newNode - > children . push_back ( new AstNode ( AST_ASSIGN_EQ , wire_tmp_id , children [ 1 ] - > clone ( ) ) ) ;
2018-09-17 17:23:40 -05:00
newNode - > children . back ( ) - > was_checked = true ;
2016-07-08 07:31:06 -05:00
int cursor = 0 ;
for ( auto child : children [ 0 ] - > children )
{
int child_width_hint = - 1 ;
bool child_sign_hint = true ;
child - > detectSignWidth ( child_width_hint , child_sign_hint ) ;
AstNode * rhs = wire_tmp_id - > clone ( ) ;
rhs - > children . push_back ( new AstNode ( AST_RANGE , AstNode : : mkconst_int ( cursor + child_width_hint - 1 , true ) , AstNode : : mkconst_int ( cursor , true ) ) ) ;
newNode - > children . push_back ( new AstNode ( type , child - > clone ( ) , rhs ) ) ;
cursor + = child_width_hint ;
}
goto apply_newNode ;
}
}
2013-01-05 04:13:26 -06:00
// 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 ;
2020-02-23 01:19:52 -06:00
sstr < < " $memwr$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( 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 " ;
int mem_width , mem_size , addr_bits ;
2016-11-01 17:17:43 -05:00
bool mem_signed = children [ 0 ] - > id2ast - > is_signed ;
2013-01-05 04:13:26 -06:00
children [ 0 ] - > id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
newNode = new AstNode ( AST_BLOCK ) ;
AstNode * defNode = new AstNode ( AST_BLOCK ) ;
2016-08-22 07:27:46 -05:00
int data_range_left = children [ 0 ] - > id2ast - > children [ 0 ] - > range_left ;
int data_range_right = children [ 0 ] - > id2ast - > children [ 0 ] - > range_right ;
int mem_data_range_offset = std : : min ( data_range_left , data_range_right ) ;
2016-08-19 11:38:25 -05:00
int addr_width_hint = - 1 ;
bool addr_sign_hint = true ;
children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > detectSignWidthWorker ( addr_width_hint , addr_sign_hint ) ;
addr_bits = std : : max ( addr_bits , addr_width_hint ) ;
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
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
AstNode * node_addr = nullptr ;
if ( children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > isConst ( ) ) {
node_addr = children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > clone ( ) ;
} else {
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 - > was_checked = true ;
current_ast_mod - > children . push_back ( wire_addr ) ;
current_scope [ wire_addr - > str ] = wire_addr ;
while ( wire_addr - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * assign_addr = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( x_bits_addr , false ) ) ;
assign_addr - > children [ 0 ] - > str = id_addr ;
assign_addr - > children [ 0 ] - > was_checked = true ;
defNode - > children . push_back ( assign_addr ) ;
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 ;
assign_addr - > children [ 0 ] - > was_checked = true ;
newNode - > children . push_back ( assign_addr ) ;
node_addr = new AstNode ( AST_IDENTIFIER ) ;
node_addr - > str = id_addr ;
}
AstNode * node_data = nullptr ;
if ( children [ 0 ] - > children . size ( ) = = 1 & & children [ 1 ] - > isConst ( ) ) {
node_data = children [ 1 ] - > clone ( ) ;
} else {
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 - > was_checked = true ;
wire_data - > is_signed = mem_signed ;
current_ast_mod - > children . push_back ( wire_data ) ;
current_scope [ wire_data - > str ] = wire_data ;
while ( wire_data - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( x_bits_data , false ) ) ;
assign_data - > children [ 0 ] - > str = id_data ;
assign_data - > children [ 0 ] - > was_checked = true ;
defNode - > children . push_back ( assign_data ) ;
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
node_data = new AstNode ( AST_IDENTIFIER ) ;
node_data - > str = id_data ;
}
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
AstNode * node_en = nullptr ;
if ( current_always - > type = = AST_INITIAL ) {
node_en = AstNode : : mkconst_int ( 1 , false ) ;
} else {
AstNode * wire_en = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE , mkconst_int ( mem_width - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
wire_en - > str = id_en ;
wire_en - > was_checked = true ;
current_ast_mod - > children . push_back ( wire_en ) ;
current_scope [ wire_en - > str ] = wire_en ;
while ( wire_en - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_int ( 0 , false , mem_width ) ) ;
2015-02-14 03:49:30 -06:00
assign_en - > children [ 0 ] - > str = id_en ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
defNode - > children . push_back ( assign_en ) ;
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
node_en = new AstNode ( AST_IDENTIFIER ) ;
node_en - > str = id_en ;
}
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
if ( ! defNode - > children . empty ( ) )
current_top_block - > children . insert ( current_top_block - > children . begin ( ) , defNode ) ;
else
delete defNode ;
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
AstNode * assign_data = nullptr ;
AstNode * assign_en = nullptr ;
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 ;
2016-08-22 07:27:46 -05:00
offset - = mem_data_range_offset ;
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 ) ;
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 ;
2018-06-05 09:44:24 -05:00
assign_data - > children [ 0 ] - > was_checked = true ;
2014-07-17 06:13:21 -05:00
2015-02-14 03:49:30 -06:00
if ( current_always - > type ! = AST_INITIAL ) {
for ( int i = 0 ; i < mem_width ; i + + )
set_bits_en [ i ] = offset < = i & & i < offset + width ? RTLIL : : State : : S1 : RTLIL : : State : : S0 ;
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( set_bits_en , false ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
2015-02-14 03:49:30 -06:00
}
2014-07-17 06:13:21 -05:00
}
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 ( ) ;
2016-08-22 07:27:46 -05:00
if ( mem_data_range_offset )
offset_ast = new AstNode ( AST_SUB , offset_ast , mkconst_int ( mem_data_range_offset , true ) ) ;
2014-07-17 09:49:23 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unsupported expression on dynamic range select on signal `%s'! \n " , str . c_str ( ) ) ;
2019-02-21 11:40:11 -06:00
int width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2014-07-17 09:49:23 -05:00
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 ;
2018-06-05 09:44:24 -05:00
assign_data - > children [ 0 ] - > was_checked = true ;
2014-07-17 09:49:23 -05:00
2015-02-14 03:49:30 -06:00
if ( current_always - > type ! = AST_INITIAL ) {
for ( int i = 0 ; i < mem_width ; i + + )
set_bits_en [ i ] = i < width ? RTLIL : : State : : S1 : RTLIL : : State : : S0 ;
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 ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
2015-02-14 03:49:30 -06:00
}
2014-07-17 09:49:23 -05:00
delete left_at_zero_ast ;
delete right_at_zero_ast ;
delete offset_ast ;
2014-07-17 06:13:21 -05:00
}
}
else
{
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
if ( ! ( children [ 0 ] - > children . size ( ) = = 1 & & children [ 1 ] - > isConst ( ) ) ) {
assign_data = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , children [ 1 ] - > clone ( ) ) ;
assign_data - > children [ 0 ] - > str = id_data ;
assign_data - > children [ 0 ] - > was_checked = true ;
}
2014-07-17 06:13:21 -05:00
2015-02-14 03:49:30 -06:00
if ( current_always - > type ! = AST_INITIAL ) {
assign_en = new AstNode ( AST_ASSIGN_LE , new AstNode ( AST_IDENTIFIER ) , mkconst_bits ( set_bits_en , false ) ) ;
assign_en - > children [ 0 ] - > str = id_en ;
2018-06-05 09:44:24 -05:00
assign_en - > children [ 0 ] - > was_checked = true ;
2015-02-14 03:49:30 -06:00
}
2014-07-17 06:13:21 -05:00
}
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
if ( assign_data )
newNode - > children . push_back ( assign_data ) ;
if ( assign_en )
2015-02-14 03:49:30 -06:00
newNode - > children . push_back ( assign_en ) ;
2013-01-05 04:13:26 -06:00
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
AstNode * wrnode = new AstNode ( current_always - > type = = AST_INITIAL ? AST_MEMINIT : AST_MEMWR , node_addr , node_data , node_en ) ;
2013-01-05 04:13:26 -06:00
wrnode - > str = children [ 0 ] - > str ;
2015-02-14 07:21:15 -06:00
wrnode - > id2ast = children [ 0 ] - > id2ast ;
2013-01-05 04:13:26 -06:00
current_ast_mod - > children . push_back ( wrnode ) ;
ast: avoid intermediate wires/assigns when lowering to AST_MEMINIT.
Before this commit, every initial assignment to a memory generated
two wires and four assigns in a process. For unknown reasons (I did
not investigate), large amounts of assigns cause quadratic slowdown
later in the AST frontend, in processAst/removeSignalFromCaseTree.
As a consequence, common and reasonable Verilog code, such as:
reg [`WIDTH:0] mem [0:`DEPTH];
integer i; initial for (i = 0; i <= `DEPTH; i++) mem[i] = 0;
took extremely long time to be processed; around 80 s for a 8-wide,
8192-deep memory.
After this commit, initial assignments where address and/or data are
constant (after `generate`) do not incur the cost of intermediate
wires; expressions like `mem[i+1]=i^(i<<1)` are considered constant.
This results in speedups of orders of magnitude for common memory
sizes; it now takes merely 0.4 s to process a 8-wide, 8192-deep
memory, and only 5.8 s to process a 8-wide, 131072-deep one.
As a bonus, this change also results in nontrivial speedups later
in the synthesis pipeline, since pass sequencing issues meant that
all of these intermediate wires were subject to transformations such
as width reduction, even though they existed solely to be constant
folded away in `memory_collect`.
2020-01-01 14:18:28 -06:00
if ( newNode - > children . empty ( ) ) {
delete newNode ;
newNode = new AstNode ( ) ;
}
2013-01-05 04:13:26 -06:00
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 )
{
2016-07-21 07:23:22 -05:00
if ( str = = " \\ $initstate " )
{
int myidx = autoidx + + ;
AstNode * wire = new AstNode ( AST_WIRE ) ;
wire - > str = stringf ( " $initstate$%d_wire " , myidx ) ;
current_ast_mod - > children . push_back ( wire ) ;
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * cell = new AstNode ( AST_CELL , new AstNode ( AST_CELLTYPE ) , new AstNode ( AST_ARGUMENT , new AstNode ( AST_IDENTIFIER ) ) ) ;
cell - > str = stringf ( " $initstate$%d " , myidx ) ;
cell - > children [ 0 ] - > str = " $initstate " ;
cell - > children [ 1 ] - > str = " \\ Y " ;
cell - > children [ 1 ] - > children [ 0 ] - > str = wire - > str ;
cell - > children [ 1 ] - > children [ 0 ] - > id2ast = wire ;
current_ast_mod - > children . push_back ( cell ) ;
while ( cell - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
newNode = new AstNode ( AST_IDENTIFIER ) ;
newNode - > str = wire - > str ;
newNode - > id2ast = wire ;
goto apply_newNode ;
}
2016-09-18 18:30:07 -05:00
if ( str = = " \\ $past " )
{
2019-02-21 10:55:33 -06:00
if ( width_hint < 0 )
2016-09-18 18:30:07 -05:00
goto replace_fcall_later ;
int num_steps = 1 ;
if ( GetSize ( children ) ! = 1 & & GetSize ( children ) ! = 2 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1 or 2. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2016-09-18 18:30:07 -05:00
if ( ! current_always_clocked )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s is only allowed in clocked blocks. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
2016-09-18 18:30:07 -05:00
if ( GetSize ( children ) = = 2 )
{
AstNode * buf = children [ 1 ] - > clone ( ) ;
2018-09-30 11:43:35 -05:00
while ( buf - > simplify ( true , false , false , stage , - 1 , false , false ) ) { }
2016-09-18 18:30:07 -05:00
if ( buf - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant value. \n " , str . c_str ( ) ) ;
2016-09-18 18:30:07 -05:00
num_steps = buf - > asInt ( true ) ;
delete buf ;
}
AstNode * block = nullptr ;
for ( auto child : current_always - > children )
if ( child - > type = = AST_BLOCK )
block = child ;
log_assert ( block ! = nullptr ) ;
2018-12-18 10:49:38 -06:00
if ( num_steps = = 0 ) {
newNode = children [ 0 ] - > clone ( ) ;
goto apply_newNode ;
}
2016-09-18 18:30:07 -05:00
int myidx = autoidx + + ;
AstNode * outreg = nullptr ;
for ( int i = 0 ; i < num_steps ; i + + )
{
AstNode * reg = new AstNode ( AST_WIRE , new AstNode ( AST_RANGE ,
mkconst_int ( width_hint - 1 , true ) , mkconst_int ( 0 , true ) ) ) ;
2020-02-23 01:19:52 -06:00
reg - > str = stringf ( " $past$%s:%d$%d$%d " , filename . c_str ( ) , location . first_line , myidx , i ) ;
2016-09-18 18:30:07 -05:00
reg - > is_reg = true ;
current_ast_mod - > children . push_back ( reg ) ;
while ( reg - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
AstNode * regid = new AstNode ( AST_IDENTIFIER ) ;
regid - > str = reg - > str ;
regid - > id2ast = reg ;
2018-09-17 17:23:40 -05:00
regid - > was_checked = true ;
2016-09-18 18:30:07 -05:00
AstNode * rhs = nullptr ;
if ( outreg = = nullptr ) {
rhs = children . at ( 0 ) - > clone ( ) ;
} else {
rhs = new AstNode ( AST_IDENTIFIER ) ;
rhs - > str = outreg - > str ;
rhs - > id2ast = outreg ;
}
block - > children . push_back ( new AstNode ( AST_ASSIGN_LE , regid , rhs ) ) ;
outreg = reg ;
}
newNode = new AstNode ( AST_IDENTIFIER ) ;
newNode - > str = outreg - > str ;
newNode - > id2ast = outreg ;
goto apply_newNode ;
}
2018-10-01 12:41:35 -05:00
if ( str = = " \\ $stable " | | str = = " \\ $rose " | | str = = " \\ $fell " | | str = = " \\ $changed " )
2016-09-18 18:30:07 -05:00
{
if ( GetSize ( children ) ! = 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2016-09-18 18:30:07 -05:00
if ( ! current_always_clocked )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s is only allowed in clocked blocks. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
2016-09-18 18:30:07 -05:00
AstNode * present = children . at ( 0 ) - > clone ( ) ;
AstNode * past = clone ( ) ;
past - > str = " \\ $past " ;
if ( str = = " \\ $stable " )
newNode = new AstNode ( AST_EQ , past , present ) ;
2018-10-01 12:41:35 -05:00
else if ( str = = " \\ $changed " )
newNode = new AstNode ( AST_NE , past , present ) ;
2016-09-18 18:30:07 -05:00
else if ( str = = " \\ $rose " )
2018-11-03 12:39:32 -05:00
newNode = new AstNode ( AST_LOGIC_AND ,
2018-11-04 03:19:32 -06:00
new AstNode ( AST_LOGIC_NOT , new AstNode ( AST_BIT_AND , past , mkconst_int ( 1 , false ) ) ) ,
2018-11-03 12:39:32 -05:00
new AstNode ( AST_BIT_AND , present , mkconst_int ( 1 , false ) ) ) ;
2016-09-18 18:30:07 -05:00
else if ( str = = " \\ $fell " )
2018-11-03 12:39:32 -05:00
newNode = new AstNode ( AST_LOGIC_AND ,
2018-11-04 03:19:32 -06:00
new AstNode ( AST_BIT_AND , past , mkconst_int ( 1 , false ) ) ,
new AstNode ( AST_LOGIC_NOT , new AstNode ( AST_BIT_AND , present , mkconst_int ( 1 , false ) ) ) ) ;
2016-09-18 18:30:07 -05:00
else
log_abort ( ) ;
goto apply_newNode ;
}
2016-10-14 08:24:03 -05:00
// $anyconst and $anyseq are mapped in AstNode::genRTLIL()
2018-02-23 06:14:47 -06:00
if ( str = = " \\ $anyconst " | | str = = " \\ $anyseq " | | str = = " \\ $allconst " | | str = = " \\ $allseq " ) {
2016-09-18 18:30:07 -05:00
recursion_counter - - ;
2016-07-27 08:41:22 -05:00
return false ;
2016-09-18 18:30:07 -05:00
}
2016-07-27 08:41:22 -05:00
2013-12-04 14:19:54 -06:00
if ( str = = " \\ $clog2 " )
{
2014-06-14 06:36:23 -05:00
if ( children . size ( ) ! = 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant value. \n " , str . c_str ( ) ) ;
2013-12-04 14:19:54 -06:00
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
2018-11-24 11:49:23 -06:00
newNode = mkconst_int ( result , true ) ;
2013-12-04 14:19:54 -06:00
goto apply_newNode ;
2013-11-20 04:05:58 -06:00
}
2017-09-25 22:25:42 -05:00
2017-09-29 04:56:43 -05:00
if ( str = = " \\ $size " | | str = = " \\ $bits " )
2017-09-25 22:25:42 -05:00
{
2017-09-26 11:18:25 -05:00
if ( str = = " \\ $bits " & & children . size ( ) ! = 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2017-09-25 22:25:42 -05:00
2017-09-26 11:18:25 -05:00
if ( str = = " \\ $size " & & children . size ( ) ! = 1 & & children . size ( ) ! = 2 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1 or 2. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2017-09-26 11:18:25 -05:00
int dim = 1 ;
if ( str = = " \\ $size " & & children . size ( ) = = 2 ) {
AstNode * buf = children [ 1 ] - > clone ( ) ;
2017-09-26 12:34:24 -05:00
// Evaluate constant expression
while ( buf - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
2017-09-26 11:18:25 -05:00
dim = buf - > asInt ( false ) ;
delete buf ;
}
2017-09-25 22:25:42 -05:00
AstNode * buf = children [ 0 ] - > clone ( ) ;
2017-09-26 01:11:25 -05:00
int mem_depth = 1 ;
AstNode * id_ast = NULL ;
2017-09-26 11:18:25 -05:00
2017-09-26 00:36:45 -05:00
// Is this needed?
//while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
2017-09-25 22:25:42 -05:00
buf - > detectSignWidth ( width_hint , sign_hint ) ;
2017-09-26 12:34:24 -05:00
2017-09-26 11:18:25 -05:00
if ( buf - > type = = AST_IDENTIFIER ) {
id_ast = buf - > id2ast ;
if ( id_ast = = NULL & & current_scope . count ( buf - > str ) )
id_ast = current_scope . at ( buf - > str ) ;
if ( ! id_ast )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to resolve identifier %s for width detection! \n " , buf - > str . c_str ( ) ) ;
2017-09-26 11:18:25 -05:00
if ( id_ast - > type = = AST_MEMORY ) {
// We got here only if the argument is a memory
// Otherwise $size() and $bits() return the expression width
AstNode * mem_range = id_ast - > children [ 1 ] ;
if ( str = = " \\ $bits " ) {
2017-09-26 01:11:25 -05:00
if ( mem_range - > type = = AST_RANGE ) {
if ( ! mem_range - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width of memory access `%s'! \n " , buf - > str . c_str ( ) ) ;
2017-09-26 01:11:25 -05:00
mem_depth = mem_range - > range_left - mem_range - > range_right + 1 ;
} else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unknown memory depth AST type in `%s'! \n " , buf - > str . c_str ( ) ) ;
2017-09-26 11:18:25 -05:00
} else {
// $size()
if ( mem_range - > type = = AST_RANGE ) {
if ( ! mem_range - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width of memory access `%s'! \n " , buf - > str . c_str ( ) ) ;
2017-09-26 12:34:24 -05:00
int dims ;
if ( id_ast - > multirange_dimensions . empty ( ) )
dims = 1 ;
else
dims = GetSize ( id_ast - > multirange_dimensions ) / 2 ;
2017-09-26 11:18:25 -05:00
if ( dim = = 1 )
2017-09-26 12:34:24 -05:00
width_hint = ( dims > 1 ) ? id_ast - > multirange_dimensions [ 1 ] : ( mem_range - > range_left - mem_range - > range_right + 1 ) ;
else if ( dim < = dims ) {
width_hint = id_ast - > multirange_dimensions [ 2 * dim - 1 ] ;
} else if ( ( dim > dims + 1 ) | | ( dim < 0 ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Dimension %d out of range in `%s', as it only has dimensions 1..%d! \n " , dim , buf - > str . c_str ( ) , dims + 1 ) ;
2017-09-26 11:18:25 -05:00
} else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unknown memory depth AST type in `%s'! \n " , buf - > str . c_str ( ) ) ;
2017-09-26 01:11:25 -05:00
}
}
}
2017-09-25 22:25:42 -05:00
delete buf ;
2017-09-26 01:11:25 -05:00
newNode = mkconst_int ( width_hint * mem_depth , false ) ;
2017-09-25 22:25:42 -05:00
goto apply_newNode ;
}
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 " | |
2017-01-03 10:40:58 -06:00
str = = " \\ $sinh " | | str = = " \\ $cosh " | | str = = " \\ $tanh " | | str = = " \\ $asinh " | | str = = " \\ $acosh " | | str = = " \\ $atanh " | |
str = = " \\ $rtoi " | | str = = " \\ $itor " )
2014-06-14 06:36:23 -05:00
{
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 2. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2014-06-14 06:36:23 -05:00
} else {
if ( children . size ( ) ! = 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 1. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
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 ( ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant argument. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
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 ( ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant argument. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
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 ) ;
}
2017-01-03 10:40:58 -06:00
if ( str = = " \\ $rtoi " ) {
newNode = AstNode : : mkconst_int ( x , true ) ;
} else {
newNode = new AstNode ( AST_REALVALUE ) ;
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 ) ;
else if ( str = = " \\ $itor " ) newNode - > realvalue = x ;
else log_abort ( ) ;
}
2014-06-14 06:36:23 -05:00
goto apply_newNode ;
}
2020-01-19 15:15:51 -06:00
if ( str = = " \\ $sformatf " ) {
AstNode * node_string = children [ 0 ] ;
while ( node_string - > simplify ( true , false , false , stage , width_hint , sign_hint , false ) ) { }
if ( node_string - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant 1st argument. \n " , str . c_str ( ) ) ;
2020-01-19 15:15:51 -06:00
std : : string sformat = node_string - > bitsAsConst ( ) . decode_string ( ) ;
std : : string sout = process_format_str ( sformat , 1 , stage , width_hint , sign_hint ) ;
newNode = AstNode : : mkconst_str ( sout ) ;
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 ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Insufficient number of arguments in DPI function call. \n " ) ;
2014-08-21 05:43:51 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate DPI function with non-constant argument. \n " ) ;
2014-08-21 05:43:51 -05:00
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Can't resolve function name `%s'. \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
}
2015-09-18 02:50:53 -05:00
2015-09-17 22:34:56 -05:00
if ( type = = AST_TCALL )
{
2016-03-21 10:19:51 -05:00
if ( str = = " $finish " | | str = = " $stop " )
2015-09-17 22:34:56 -05:00
{
2015-09-18 02:50:53 -05:00
if ( ! current_always | | current_always - > type ! = AST_INITIAL )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System task `%s' outside initial block is unsupported. \n " , str . c_str ( ) ) ;
2015-09-18 02:50:53 -05:00
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System task `%s' executed. \n " , str . c_str ( ) ) ;
2015-09-17 22:34:56 -05:00
}
2014-10-26 14:33:10 -05:00
if ( str = = " \\ $readmemh " | | str = = " \\ $readmemb " )
{
if ( GetSize ( children ) < 2 | | GetSize ( children ) > 4 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s got %d arguments, expected 2-4. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , int ( children . size ( ) ) ) ;
2014-10-26 14:33:10 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant 1st argument. \n " , str . c_str ( ) ) ;
2014-10-26 14:33:10 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-memory 2nd argument. \n " , str . c_str ( ) ) ;
2014-10-26 14:33:10 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant 3rd argument. \n " , str . c_str ( ) ) ;
2016-02-13 10:31:24 -06:00
start_addr = int ( node_addr - > asInt ( false ) ) ;
2014-10-26 14:33:10 -05:00
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to evaluate system function `%s' with non-constant 4th argument. \n " , str . c_str ( ) ) ;
2016-02-13 10:31:24 -06:00
finish_addr = int ( node_addr - > asInt ( false ) ) ;
2014-10-26 14:33:10 -05:00
}
2015-07-31 03:40:09 -05:00
bool unconditional_init = false ;
if ( current_always - > type = = AST_INITIAL ) {
2015-09-30 08:46:51 -05:00
pool < AstNode * > queue ;
2015-07-31 03:40:09 -05:00
log_assert ( current_always - > children [ 0 ] - > type = = AST_BLOCK ) ;
2015-09-30 08:46:51 -05:00
queue . insert ( current_always - > children [ 0 ] ) ;
while ( ! unconditional_init & & ! queue . empty ( ) ) {
pool < AstNode * > next_queue ;
for ( auto n : queue )
for ( auto c : n - > children ) {
if ( c = = this )
unconditional_init = true ;
next_queue . insert ( c ) ;
2015-07-31 03:40:09 -05:00
}
2015-09-30 08:46:51 -05:00
next_queue . swap ( queue ) ;
}
2015-07-31 03:40:09 -05:00
}
newNode = readmem ( str = = " \\ $readmemh " , node_filename - > bitsAsConst ( ) . decode_string ( ) , node_memory - > id2ast , start_addr , finish_addr , unconditional_init ) ;
2019-03-02 11:58:20 -06:00
delete node_filename ;
delete node_memory ;
2014-10-26 14:33:10 -05:00
goto apply_newNode ;
}
2013-01-05 04:13:26 -06:00
if ( current_scope . count ( str ) = = 0 | | current_scope [ str ] - > type ! = AST_TASK )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Can't resolve task name `%s'. \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
}
2014-08-18 07:29:30 -05:00
AstNode * decl = current_scope [ str ] ;
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < " $func$ " < < str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( autoidx + + ) < < " $ " ;
2014-08-18 07:29:30 -05:00
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 ) ;
2020-05-04 12:48:37 -05:00
if ( ( in_param | | recommend_const_eval | | require_const_eval ) & & ! decl - > attributes . count ( ID : : 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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant function call in constant expression. \n " ) ;
2014-06-06 17:02:05 -05:00
if ( require_const_eval )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Function %s can only be called with constant arguments. \n " , str . c_str ( ) ) ;
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 ;
2015-11-12 06:02:36 -06:00
vector < AstNode * > added_mod_children ;
2015-11-23 10:09:57 -06:00
dict < std : : string , AstNode * > wire_cache ;
2019-03-08 00:44:37 -06:00
vector < AstNode * > new_stmts ;
vector < AstNode * > output_assignments ;
2013-01-05 04:13:26 -06:00
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 ( ) ) ) ) ;
2018-09-17 17:23:40 -05:00
always - > children [ 0 ] - > children [ 0 ] - > was_checked = true ;
2013-01-05 04:13:26 -06:00
current_ast_mod - > children . push_back ( always ) ;
goto replace_fcall_with_id ;
}
2020-05-04 12:48:37 -05:00
if ( decl - > attributes . count ( ID : : via_celltype ) )
2014-08-18 07:29:30 -05:00
{
2020-05-04 12:48:37 -05:00
std : : string celltype = decl - > attributes . at ( ID : : via_celltype ) - > asAttrConst ( ) . decode_string ( ) ;
2014-08-18 07:29:30 -05:00
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 ( ) ) ;
2019-08-06 21:08:33 -05:00
cell_arg - > str = RTLIL : : escape_id ( attr . first . substr ( strlen ( " \\ via_celltype_defparam_ " ) ) ) ;
2014-08-18 07:29:30 -05:00
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 ( ) ) ;
2018-09-17 17:23:40 -05:00
assign - > children [ 0 ] - > was_checked = true ;
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 )
2018-03-09 06:47:11 -06:00
if ( child - > type = = AST_WIRE | | child - > type = = AST_MEMORY | | child - > type = = AST_PARAMETER | | child - > type = = AST_LOCALPARAM | | child - > type = = AST_ENUM_ITEM )
2013-01-05 04:13:26 -06:00
{
2015-11-23 10:09:57 -06:00
AstNode * wire = nullptr ;
if ( wire_cache . count ( child - > str ) )
{
wire = wire_cache . at ( child - > str ) ;
if ( wire - > children . empty ( ) ) {
for ( auto c : child - > children )
wire - > children . push_back ( c - > clone ( ) ) ;
2017-02-14 08:10:59 -06:00
} else if ( ! child - > children . empty ( ) ) {
while ( child - > simplify ( true , false , false , stage , - 1 , false , false ) ) { }
if ( GetSize ( child - > children ) = = GetSize ( wire - > children ) ) {
for ( int i = 0 ; i < GetSize ( child - > children ) ; i + + )
if ( * child - > children . at ( i ) ! = * wire - > children . at ( i ) )
goto tcall_incompatible_wires ;
} else {
tcall_incompatible_wires :
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Incompatible re-declaration of wire %s. \n " , child - > str . c_str ( ) ) ;
2017-02-14 08:10:59 -06:00
}
2015-11-23 10:09:57 -06:00
}
}
else
{
wire = child - > clone ( ) ;
wire - > str = prefix + wire - > str ;
wire - > port_id = 0 ;
wire - > is_input = false ;
wire - > is_output = false ;
2019-03-08 00:44:37 -06:00
wire - > is_reg = true ;
2020-04-02 11:51:32 -05:00
wire - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2020-02-17 03:40:02 -06:00
if ( child - > type = = AST_ENUM_ITEM )
2020-05-04 12:48:37 -05:00
wire - > attributes [ ID : : enum_base_type ] = child - > attributes [ ID : : enum_base_type ] ;
2020-02-03 00:12:24 -06:00
2015-11-23 10:09:57 -06:00
wire_cache [ child - > str ] = wire ;
current_ast_mod - > children . push_back ( wire ) ;
added_mod_children . push_back ( wire ) ;
}
2015-11-12 06:02:36 -06:00
if ( child - > type = = AST_WIRE )
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
2013-01-05 04:13:26 -06:00
replace_rules [ child - > str ] = wire - > str ;
2015-11-12 06:02:36 -06:00
current_scope [ wire - > str ] = wire ;
2013-01-05 04:13:26 -06:00
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 ( ) ;
2020-07-24 22:18:24 -05:00
// convert purely constant arguments into localparams
if ( child - > is_input & & child - > type = = AST_WIRE & & arg - > type = = AST_CONSTANT & & node_contains_assignment_to ( decl , child ) ) {
wire - > type = AST_LOCALPARAM ;
wire - > attributes . erase ( ID : : nosync ) ;
wire - > children . insert ( wire - > children . begin ( ) , arg - > clone ( ) ) ;
continue ;
}
2013-01-05 04:13:26 -06:00
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 ) ;
2018-09-17 17:23:40 -05:00
assign - > children [ 0 ] - > was_checked = true ;
2019-03-08 00:44:37 -06:00
if ( child - > is_input )
new_stmts . push_back ( assign ) ;
else
output_assignments . push_back ( assign ) ;
2013-01-05 04:13:26 -06:00
}
}
2014-08-05 01:35:51 -05:00
2015-11-12 06:02:36 -06:00
for ( auto child : added_mod_children ) {
child - > replace_ids ( prefix , replace_rules ) ;
while ( child - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
}
2014-08-05 01:35:51 -05:00
for ( auto child : decl - > children )
2017-01-05 06:18:58 -06:00
if ( child - > type ! = AST_WIRE & & child - > type ! = AST_MEMORY & & child - > type ! = AST_PARAMETER & & child - > type ! = AST_LOCALPARAM )
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 ) ;
2019-03-08 00:44:37 -06:00
new_stmts . push_back ( stmt ) ;
}
2013-01-05 04:13:26 -06:00
2019-03-08 00:44:37 -06:00
new_stmts . insert ( new_stmts . end ( ) , output_assignments . begin ( ) , output_assignments . end ( ) ) ;
for ( auto it = current_block - > children . begin ( ) ; ; it + + ) {
log_assert ( it ! = current_block - > children . end ( ) ) ;
if ( * it = = current_block_child ) {
current_block - > children . insert ( it , new_stmts . begin ( ) , new_stmts . end ( ) ) ;
break ;
2013-01-05 04:13:26 -06:00
}
2019-03-08 00:44:37 -06:00
}
2013-01-05 04:13:26 -06:00
replace_fcall_with_id :
if ( type = = AST_FCALL ) {
delete_children ( ) ;
type = AST_IDENTIFIER ;
str = prefix + str ;
}
if ( type = = AST_TCALL )
str = " " ;
did_something = true ;
}
2016-09-18 18:30:07 -05:00
replace_fcall_later : ;
2013-01-05 04:13:26 -06:00
// 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 :
2018-03-09 06:47:11 -06:00
if ( current_scope . count ( str ) > 0 & & ( current_scope [ str ] - > type = = AST_PARAMETER | | current_scope [ str ] - > type = = AST_LOCALPARAM | | current_scope [ str ] - > type = = AST_ENUM_ITEM ) ) {
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 ) {
2015-10-25 13:30:49 -05:00
int cmp_width = max ( children [ 0 ] - > bits . size ( ) , children [ 1 ] - > bits . size ( ) ) ;
2013-11-04 08:37:09 -06:00
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 ;
2020-04-29 07:28:04 -05:00
if ( 0 ) { case AST_SELFSZ : const_func = RTLIL : : const_pos ; }
2013-01-05 04:13:26 -06:00
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 ) ;
2020-04-29 07:28:04 -05:00
if ( type = = AST_NEG )
2014-06-14 04:27:05 -05:00
newNode - > realvalue = - children [ 0 ] - > asReal ( sign_hint ) ;
2020-04-29 07:28:04 -05:00
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 ;
2020-06-19 21:09:43 -05:00
case AST_CAST_SIZE :
if ( children . at ( 0 ) - > type = = AST_CONSTANT & & children . at ( 1 ) - > type = = AST_CONSTANT ) {
int width = children [ 0 ] - > bitsAsConst ( ) . as_int ( ) ;
RTLIL : : Const val = children [ 1 ] - > bitsAsConst ( width ) ;
newNode = mkconst_bits ( val . bits , children [ 1 ] - > is_signed ) ;
}
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 ;
2020-02-23 01:19:52 -06:00
newNode - > location = location ;
2013-01-05 04:13:26 -06:00
newNode - > cloneInto ( this ) ;
delete newNode ;
did_something = true ;
}
2014-01-20 13:25:20 -06:00
if ( ! did_something )
basic_prep = true ;
2015-02-13 05:33:12 -06:00
recursion_counter - - ;
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
2015-07-31 03:40:09 -05:00
AstNode * AstNode : : readmem ( bool is_readmemh , std : : string mem_filename , AstNode * memory , int start_addr , int finish_addr , bool unconditional_init )
2014-10-26 14:33:10 -05:00
{
2015-09-25 06:49:48 -05:00
int mem_width , mem_size , addr_bits ;
memory - > meminfo ( mem_width , mem_size , addr_bits ) ;
2014-10-26 14:33:10 -05:00
AstNode * block = new AstNode ( AST_BLOCK ) ;
2015-07-31 03:40:09 -05:00
AstNode * meminit = nullptr ;
2015-08-14 15:22:17 -05:00
int next_meminit_cursor = 0 ;
2015-07-31 03:40:09 -05:00
vector < State > meminit_bits ;
2015-08-14 15:22:17 -05:00
int meminit_size = 0 ;
2015-07-31 03:40:09 -05:00
2014-10-26 14:33:10 -05:00
std : : ifstream f ;
2020-01-31 19:10:51 -06:00
f . open ( mem_filename . c_str ( ) ) ;
if ( f . fail ( ) ) {
2020-02-06 07:10:29 -06:00
# ifdef _WIN32
char slash = ' \\ ' ;
# else
char slash = ' / ' ;
# endif
std : : string path = filename . substr ( 0 , filename . find_last_of ( slash ) + 1 ) ;
2020-01-31 19:10:51 -06:00
f . open ( path + mem_filename . c_str ( ) ) ;
yosys_input_files . insert ( path + mem_filename ) ;
} else {
yosys_input_files . insert ( mem_filename ) ;
}
2020-02-03 07:30:33 -06:00
if ( f . fail ( ) | | GetSize ( mem_filename ) = = 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Can not open file `%s` for %s. \n " , mem_filename . c_str ( ) , str . c_str ( ) ) ;
2014-10-26 14:33:10 -05:00
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 ;
2015-10-25 13:30:49 -05:00
int range_min = min ( range_left , range_right ) , range_max = max ( range_left , range_right ) ;
2014-10-26 17:29:36 -05:00
if ( start_addr < 0 )
start_addr = range_min ;
if ( finish_addr < 0 )
2015-09-25 06:49:48 -05:00
finish_addr = range_max + 1 ;
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 + + ) {
2019-08-07 14:20:08 -05:00
if ( in_comment & & line . compare ( i , 2 , " */ " ) = = 0 ) {
2014-10-26 14:33:10 -05:00
line [ i ] = ' ' ;
line [ i + 1 ] = ' ' ;
in_comment = false ;
continue ;
}
2019-08-07 14:20:08 -05:00
if ( ! in_comment & & line . compare ( i , 2 , " /* " ) = = 0 )
2014-10-26 14:33:10 -05:00
in_comment = true ;
if ( in_comment )
line [ i ] = ' ' ;
}
while ( 1 )
{
token = next_token ( line , " \t \r \n " ) ;
2019-08-07 14:20:08 -05:00
if ( token . empty ( ) | | token . compare ( 0 , 2 , " // " ) = = 0 )
2014-10-26 14:33:10 -05:00
break ;
if ( token [ 0 ] = = ' @ ' ) {
token = token . substr ( 1 ) ;
const char * nptr = token . c_str ( ) ;
char * endptr ;
cursor = strtol ( nptr , & endptr , 16 ) ;
if ( ! * nptr | | * endptr )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Can not parse address `%s` for %s. \n " , nptr , str . c_str ( ) ) ;
2014-10-26 14:33:10 -05:00
continue ;
}
2015-09-25 06:49:48 -05:00
AstNode * value = VERILOG_FRONTEND : : const2ast ( stringf ( " %d'%c " , mem_width , is_readmemh ? ' h ' : ' b ' ) + token ) ;
2014-10-26 14:33:10 -05:00
2015-07-31 03:40:09 -05:00
if ( unconditional_init )
{
if ( meminit = = nullptr | | cursor ! = next_meminit_cursor )
{
if ( meminit ! = nullptr ) {
meminit - > children [ 1 ] = AstNode : : mkconst_bits ( meminit_bits , false ) ;
meminit - > children [ 2 ] = AstNode : : mkconst_int ( meminit_size , false ) ;
}
meminit = new AstNode ( AST_MEMINIT ) ;
meminit - > children . push_back ( AstNode : : mkconst_int ( cursor , false ) ) ;
meminit - > children . push_back ( nullptr ) ;
meminit - > children . push_back ( nullptr ) ;
meminit - > str = memory - > str ;
meminit - > id2ast = memory ;
meminit_bits . clear ( ) ;
meminit_size = 0 ;
current_ast_mod - > children . push_back ( meminit ) ;
next_meminit_cursor = cursor ;
}
meminit_size + + ;
next_meminit_cursor + + ;
meminit_bits . insert ( meminit_bits . end ( ) , value - > bits . begin ( ) , value - > bits . end ( ) ) ;
delete value ;
}
else
{
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 ;
2018-09-17 17:23:40 -05:00
block - > children . back ( ) - > children [ 0 ] - > was_checked = true ;
2015-07-31 03:40:09 -05:00
}
2014-10-26 14:33:10 -05:00
cursor + = increment ;
2016-08-20 06:47:46 -05:00
if ( ( cursor = = finish_addr + increment ) | | ( increment > 0 & & cursor > range_max ) | | ( increment < 0 & & cursor < range_min ) )
break ;
2014-10-26 14:33:10 -05:00
}
2016-08-20 06:47:46 -05:00
if ( ( cursor = = finish_addr + increment ) | | ( increment > 0 & & cursor > range_max ) | | ( increment < 0 & & cursor < range_min ) )
2014-10-26 14:33:10 -05:00
break ;
}
2015-07-31 03:40:09 -05:00
if ( meminit ! = nullptr ) {
meminit - > children [ 1 ] = AstNode : : mkconst_bits ( meminit_bits , false ) ;
meminit - > children [ 2 ] = AstNode : : mkconst_int ( meminit_size , false ) ;
}
2014-10-26 14:33:10 -05:00
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 ) {
2019-09-16 04:25:16 -05:00
if ( children . empty ( ) ) {
current_scope [ index_var ] - > children [ 0 ] - > cloneInto ( this ) ;
} else {
AstNode * p = new AstNode ( AST_LOCALPARAM , current_scope [ index_var ] - > children [ 0 ] - > clone ( ) ) ;
p - > str = stringf ( " $genval$%d " , autoidx + + ) ;
current_ast_mod - > children . push_back ( p ) ;
str = p - > str ;
id2ast = p ;
}
2013-01-05 04:13:26 -06:00
}
2019-09-20 12:40:23 -05:00
if ( ( type = = AST_IDENTIFIER | | type = = AST_FCALL | | type = = AST_TCALL | | type = = AST_WIRETYPE ) & & 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 | |
2018-03-09 06:47:11 -06:00
child - > type = = AST_FUNCTION | | child - > type = = AST_TASK | | child - > type = = AST_CELL | | child - > type = = AST_TYPEDEF | | child - > type = = AST_ENUM_ITEM ) {
2013-01-05 04:13:26 -06:00
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 )
2016-11-04 01:46:30 -05:00
pos = child - > str [ 0 ] = = ' \\ ' & & prefix [ 0 ] = = ' \\ ' ? 1 : 0 ;
2013-01-05 04:13:26 -06:00
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
}
2020-01-16 16:05:45 -06:00
if ( child - > type = = AST_ENUM ) {
2020-02-03 00:12:24 -06:00
current_scope [ child - > str ] = child ;
2020-01-16 16:05:45 -06:00
for ( auto enode : child - > children ) {
log_assert ( enode - > type = = AST_ENUM_ITEM ) ;
if ( backup_name_map . size ( ) = = 0 )
backup_name_map = name_map ;
std : : string new_name = prefix [ 0 ] = = ' \\ ' ? prefix . substr ( 1 ) : prefix ;
size_t pos = enode - > str . rfind ( ' . ' ) ;
if ( pos = = std : : string : : npos )
pos = enode - > str [ 0 ] = = ' \\ ' & & prefix [ 0 ] = = ' \\ ' ? 1 : 0 ;
else
pos = pos + 1 ;
new_name = enode - > str . substr ( 0 , pos ) + new_name + enode - > str . substr ( pos ) ;
if ( new_name [ 0 ] ! = ' $ ' & & new_name [ 0 ] ! = ' \\ ' )
new_name = prefix [ 0 ] + new_name ;
name_map [ enode - > str ] = new_name ;
enode - > str = new_name ;
current_scope [ new_name ] = enode ;
}
}
2013-01-05 04:13:26 -06:00
}
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
AstNode * child = children [ i ] ;
2019-03-18 19:34:21 -05:00
// AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
// still needs to recursed-into
if ( type = = AST_PREFIX & & i = = 1 & & child - > type = = AST_IDENTIFIER )
continue ;
if ( child - > type ! = AST_FUNCTION & & child - > type ! = AST_TASK )
2013-01-05 04:13:26 -06:00
child - > expand_genblock ( index_var , prefix , name_map ) ;
}
2019-09-19 14:43:13 -05:00
2013-01-05 04:13:26 -06:00
if ( backup_name_map . size ( ) > 0 )
name_map . swap ( backup_name_map ) ;
}
2015-08-14 03:56:05 -05:00
// rename stuff (used when tasks of functions are instantiated)
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 ) )
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , that - > filename . c_str ( ) , that - > location . first_line ) ) ;
2014-06-17 14:39:25 -05:00
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 ;
2019-03-12 14:12:02 -05:00
int lhs_children_counter = 0 ;
2013-11-21 06:49:00 -06:00
2019-09-20 05:39:15 -05:00
if ( type = = AST_TYPEDEF )
return ; // don't touch content of typedefs
2013-11-21 06:49:00 -06:00
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 ) )
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , location . first_line ) ) ;
2013-11-21 06:49:00 -06:00
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 ) )
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , location . first_line ) ) ;
2013-11-21 06:49:00 -06:00
proc_flags [ mem ] | = AstNode : : MEM2REG_FL_EQ1 ;
}
2019-03-12 14:09:47 -05:00
// for proper (non-init) writes: remember if this is a constant index or not
if ( ( flags & MEM2REG_FL_INIT ) = = 0 ) {
if ( children [ 0 ] - > children . size ( ) & & children [ 0 ] - > children [ 0 ] - > type = = AST_RANGE & & children [ 0 ] - > children [ 0 ] - > children . size ( ) ) {
if ( children [ 0 ] - > children [ 0 ] - > children [ 0 ] - > type = = AST_CONSTANT )
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_CONST_LHS ;
else
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_VAR_LHS ;
}
2019-03-01 15:35:09 -06:00
}
2013-11-21 06:49:00 -06:00
// remember where this is
if ( flags & MEM2REG_FL_INIT ) {
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_SET_INIT ) )
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , location . first_line ) ) ;
2013-11-21 06:49:00 -06:00
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_SET_INIT ;
} else {
if ( ! ( mem2reg_candidates [ mem ] & AstNode : : MEM2REG_FL_SET_ELSE ) )
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , location . first_line ) ) ;
2013-11-21 06:49:00 -06:00
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_SET_ELSE ;
2013-01-05 04:13:26 -06:00
}
}
2013-11-21 06:49:00 -06:00
2019-03-12 14:12:02 -05:00
lhs_children_counter = 1 ;
2013-11-21 06:49:00 -06:00
}
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 ) ) {
2020-02-23 01:19:52 -06:00
mem2reg_places [ mem ] . insert ( stringf ( " %s:%d " , filename . c_str ( ) , location . first_line ) ) ;
2013-11-21 06:49:00 -06:00
mem2reg_candidates [ mem ] | = AstNode : : MEM2REG_FL_EQ2 ;
}
}
2020-05-04 23:11:16 -05:00
// also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' or 'logic'
if ( type = = AST_MEMORY & & ( get_bool_attribute ( ID : : mem2reg ) | | ( flags & AstNode : : MEM2REG_FL_ALL ) | | ! ( is_reg | | is_logic ) ) )
2013-11-21 06:49:00 -06:00
mem2reg_candidates [ this ] | = AstNode : : MEM2REG_FL_FORCED ;
2013-01-05 04:13:26 -06:00
2020-03-12 14:57:01 -05:00
if ( type = = AST_MODULE & & get_bool_attribute ( ID : : 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 )
2019-03-12 14:12:02 -05:00
{
if ( lhs_children_counter > 0 ) {
lhs_children_counter - - ;
if ( child - > children . size ( ) & & child - > children [ 0 ] - > type = = AST_RANGE & & child - > children [ 0 ] - > children . size ( ) ) {
for ( auto c : child - > children [ 0 ] - > children ) {
if ( proc_flags_p )
c - > mem2reg_as_needed_pass1 ( mem2reg_places , mem2reg_candidates , * proc_flags_p , flags ) ;
else
c - > mem2reg_as_needed_pass1 ( mem2reg_places , mem2reg_candidates , proc_flags , flags ) ;
}
}
} else
if ( proc_flags_p )
2013-11-21 06:49:00 -06:00
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 ) ;
2019-03-12 14:12:02 -05:00
}
2013-11-21 06:49:00 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Invalid array access. \n " ) ;
2014-10-15 17:44:23 -05:00
return true ;
}
2016-05-27 10:25:33 -05:00
void AstNode : : mem2reg_remove ( pool < AstNode * > & mem2reg_set , vector < AstNode * > & delnodes )
{
log_assert ( mem2reg_set . count ( this ) = = 0 ) ;
if ( mem2reg_set . count ( id2ast ) )
id2ast = nullptr ;
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
if ( mem2reg_set . count ( children [ i ] ) > 0 ) {
delnodes . push_back ( children [ i ] ) ;
children . erase ( children . begin ( ) + ( i - - ) ) ;
} else {
children [ i ] - > mem2reg_remove ( mem2reg_set , delnodes ) ;
}
}
}
2013-01-05 04:13:26 -06:00
// actually replace memories with registers
2016-08-21 06:23:58 -05:00
bool AstNode : : mem2reg_as_needed_pass2 ( pool < AstNode * > & mem2reg_set , AstNode * mod , AstNode * block , AstNode * & async_block )
2013-01-05 04:13:26 -06:00
{
2015-07-29 09:37:08 -05:00
bool did_something = false ;
2013-01-05 04:13:26 -06:00
if ( type = = AST_BLOCK )
block = this ;
2016-08-21 06:23:58 -05:00
if ( type = = AST_FUNCTION | | type = = AST_TASK )
return false ;
2019-09-20 05:39:15 -05:00
if ( type = = AST_TYPEDEF )
return false ;
2019-03-02 11:58:20 -06:00
if ( type = = AST_MEMINIT & & id2ast & & mem2reg_set . count ( id2ast ) )
{
log_assert ( children [ 0 ] - > type = = AST_CONSTANT ) ;
log_assert ( children [ 1 ] - > type = = AST_CONSTANT ) ;
log_assert ( children [ 2 ] - > type = = AST_CONSTANT ) ;
int cursor = children [ 0 ] - > asInt ( false ) ;
Const data = children [ 1 ] - > bitsAsConst ( ) ;
int length = children [ 2 ] - > asInt ( false ) ;
if ( length ! = 0 )
{
AstNode * block = new AstNode ( AST_INITIAL , new AstNode ( AST_BLOCK ) ) ;
mod - > children . push_back ( block ) ;
block = block - > children [ 0 ] ;
int wordsz = GetSize ( data ) / length ;
for ( int i = 0 ; i < length ; i + + ) {
block - > children . push_back ( new AstNode ( AST_ASSIGN_EQ , new AstNode ( AST_IDENTIFIER , new AstNode ( AST_RANGE , AstNode : : mkconst_int ( cursor + i , false ) ) ) , mkconst_bits ( data . extract ( i * wordsz , wordsz ) . bits , false ) ) ) ;
block - > children . back ( ) - > children [ 0 ] - > str = str ;
block - > children . back ( ) - > children [ 0 ] - > id2ast = id2ast ;
block - > children . back ( ) - > children [ 0 ] - > was_checked = true ;
}
}
AstNode * newNode = new AstNode ( AST_NONE ) ;
newNode - > cloneInto ( this ) ;
delete newNode ;
did_something = true ;
}
2016-08-21 06:23:58 -05:00
if ( type = = AST_ASSIGN & & block = = NULL & & children [ 0 ] - > mem2reg_check ( mem2reg_set ) )
{
if ( async_block = = NULL ) {
async_block = new AstNode ( AST_ALWAYS , new AstNode ( AST_BLOCK ) ) ;
mod - > children . push_back ( async_block ) ;
}
AstNode * newNode = clone ( ) ;
newNode - > type = AST_ASSIGN_EQ ;
2018-09-24 16:32:57 -05:00
newNode - > children [ 0 ] - > was_checked = true ;
2016-08-21 06:23:58 -05:00
async_block - > children [ 0 ] - > children . push_back ( newNode ) ;
newNode = new AstNode ( AST_NONE ) ;
newNode - > cloneInto ( this ) ;
delete newNode ;
did_something = true ;
}
if ( ( type = = AST_ASSIGN_LE | | type = = AST_ASSIGN_EQ ) & & 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 ;
2020-02-23 01:19:52 -06:00
sstr < < " $mem2reg_wr$ " < < children [ 0 ] - > str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( 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 ;
2016-11-01 17:17:43 -05:00
bool mem_signed = children [ 0 ] - > id2ast - > is_signed ;
2013-01-05 04:13:26 -06:00
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 ;
2018-06-05 09:44:24 -05:00
wire_addr - > was_checked = true ;
2020-04-02 11:51:32 -05:00
wire_addr - > attributes [ ID : : 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 ;
2018-06-05 09:44:24 -05:00
wire_data - > was_checked = true ;
2016-11-01 17:17:43 -05:00
wire_data - > is_signed = mem_signed ;
2020-04-02 11:51:32 -05:00
wire_data - > attributes [ ID : : 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 ;
2018-09-24 16:32:57 -05:00
assign_addr - > children [ 0 ] - > was_checked = true ;
2013-01-05 04:13:26 -06:00
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 ;
2018-09-17 17:23:40 -05:00
children [ 0 ] - > was_checked = true ;
2015-07-29 09:37:08 -05:00
did_something = true ;
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 ;
2020-02-23 01:19:52 -06:00
sstr < < " $mem2reg_rd$ " < < str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( 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 ;
2016-11-01 17:17:43 -05:00
bool mem_signed = id2ast - > is_signed ;
2013-11-21 06:49:00 -06:00
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 ;
2018-06-05 09:44:24 -05:00
wire_addr - > was_checked = true ;
2013-11-21 06:49:00 -06:00
if ( block )
2020-04-02 11:51:32 -05:00
wire_addr - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2013-11-21 06:49:00 -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-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 ;
2018-06-05 09:44:24 -05:00
wire_data - > was_checked = true ;
2016-11-01 17:17:43 -05:00
wire_data - > is_signed = mem_signed ;
2013-11-21 06:49:00 -06:00
if ( block )
2020-04-02 11:51:32 -05:00
wire_data - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2013-11-21 06:49:00 -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-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 ;
2018-06-05 09:44:24 -05:00
assign_addr - > children [ 0 ] - > was_checked = true ;
2013-11-21 06:49:00 -06:00
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 ;
2018-06-05 09:44:24 -05:00
assign_reg - > children [ 0 ] - > was_checked = true ;
2013-11-21 06:49:00 -06:00
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 ;
2018-06-05 09:44:24 -05:00
assign_reg - > children [ 0 ] - > was_checked = true ;
2013-01-05 04:13:26 -06:00
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 ) ;
2017-01-15 06:52:50 -06:00
did_something = true ;
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 + + )
2016-08-21 06:23:58 -05:00
if ( children_list [ i ] - > mem2reg_as_needed_pass2 ( mem2reg_set , mod , block , async_block ) )
2015-07-29 09:37:08 -05:00
did_something = true ;
return did_something ;
2013-01-05 04:13:26 -06:00
}
2015-08-14 03:56:05 -05:00
// calculate memory dimensions
2013-01-05 04:13:26 -06:00
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 ;
2015-10-25 13:30:49 -05:00
mem_size + = min ( children [ 1 ] - > range_left , children [ 1 ] - > range_right ) + 1 ;
2013-01-05 04:13:26 -06:00
addr_bits = 1 ;
while ( ( 1 < < addr_bits ) < mem_size )
addr_bits + + ;
}
2020-06-04 16:10:03 -05:00
bool AstNode : : detect_latch ( const std : : string & var )
{
switch ( type )
{
case AST_ALWAYS :
for ( auto & c : children )
{
switch ( c - > type )
{
case AST_POSEDGE :
case AST_NEGEDGE :
return false ;
2020-07-10 11:41:13 -05:00
case AST_EDGE :
break ;
2020-06-04 16:10:03 -05:00
case AST_BLOCK :
if ( ! c - > detect_latch ( var ) )
return false ;
break ;
default :
log_abort ( ) ;
}
}
return true ;
case AST_BLOCK :
for ( auto & c : children )
if ( ! c - > detect_latch ( var ) )
return false ;
return true ;
case AST_CASE :
{
bool r = true ;
for ( auto & c : children ) {
if ( c - > type = = AST_COND ) {
if ( c - > children . at ( 1 ) - > detect_latch ( var ) )
return true ;
r = false ;
}
if ( c - > type = = AST_DEFAULT ) {
if ( c - > children . at ( 0 ) - > detect_latch ( var ) )
return true ;
r = false ;
}
}
return r ;
}
case AST_ASSIGN_EQ :
case AST_ASSIGN_LE :
if ( children . at ( 0 ) - > type = = AST_IDENTIFIER & &
children . at ( 0 ) - > children . empty ( ) & & children . at ( 0 ) - > str = = var )
return false ;
return true ;
default :
return true ;
}
}
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 ;
}
2019-03-02 14:36:46 -06:00
bool AstNode : : is_simple_const_expr ( )
{
if ( type = = AST_IDENTIFIER )
return false ;
for ( auto child : children )
if ( ! child - > is_simple_const_expr ( ) )
return false ;
return true ;
}
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Memory access in constant function is not supported \n %s:%d.%d-%d.%d: ...called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-06-06 10:40:45 -05:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Non-constant range \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2015-10-25 13:30:49 -05:00
offset = min ( children . at ( 0 ) - > range_left , children . at ( 0 ) - > range_right ) ;
width = 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 ;
2019-08-06 11:06:14 -05:00
AstNode * block = new AstNode ( AST_BLOCK ) ;
2014-02-14 12:56:44 -06:00
size_t argidx = 0 ;
for ( auto child : children )
{
if ( child - > type = = AST_WIRE )
{
while ( child - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( ! child - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( child - > filename , child - > location . first_line , " Can't determine size of variable %s \n %s:%d.%d-%d.%d: ... called from here. \n " ,
child - > str . c_str ( ) , fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 12:56:44 -06:00
variables [ child - > str ] . val = RTLIL : : Const ( RTLIL : : State : : Sx , abs ( child - > range_left - child - > range_right ) + 1 ) ;
2015-10-25 13:30:49 -05:00
variables [ child - > str ] . offset = min ( child - > range_left , child - > range_right ) ;
2014-02-14 12:56:44 -06:00
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
block - > children . push_back ( child - > clone ( ) ) ;
2014-02-14 12:56:44 -06:00
}
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 )
{
2015-10-01 05:15:35 -05:00
if ( stmt - > children . at ( 0 ) - > type = = AST_IDENTIFIER & & stmt - > children . at ( 0 ) - > children . size ( ) ! = 0 & &
stmt - > children . at ( 0 ) - > children . at ( 0 ) - > type = = AST_RANGE )
stmt - > children . at ( 0 ) - > children . at ( 0 ) - > replace_variables ( variables , fcall ) ;
2014-02-14 12:56:44 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Non-constant expression in constant function \n %s:%d.%d-%d.%d: ... called from here. X \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 12:56:44 -06:00
2014-06-06 15:55:02 -05:00
if ( stmt - > children . at ( 0 ) - > type ! = AST_IDENTIFIER )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Unsupported composite left hand side in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 12:56:44 -06:00
if ( ! variables . count ( stmt - > children . at ( 0 ) - > str ) )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Assignment to non-local variable in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 12:56:44 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( range - > filename , range - > location . first_line , " Non-constant range \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2015-10-25 13:30:49 -05:00
int offset = 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 )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Non-constant expression in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 13:33:22 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Non-constant expression in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-06-07 03:47:53 -05:00
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 ;
2016-04-21 08:31:54 -05:00
log_assert ( stmt - > children . at ( i ) - > type = = AST_COND | | stmt - > children . at ( i ) - > type = = AST_CONDX | | stmt - > children . at ( i ) - > type = = AST_CONDZ ) ;
2014-02-16 06:16:38 -06:00
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 )
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Non-constant expression in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-16 06:16:38 -06:00
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 ;
}
2020-02-23 01:19:52 -06:00
log_file_error ( stmt - > filename , stmt - > location . first_line , " Unsupported language construct in constant function \n %s:%d.%d-%d.%d: ... called from here. \n " ,
fcall - > filename . c_str ( ) , fcall - > location . first_line , fcall - > location . first_column , fcall - > location . last_line , fcall - > location . last_column ) ;
2014-02-14 12:56:44 -06:00
log_abort ( ) ;
}
2019-08-06 11:06:14 -05:00
delete block ;
2014-06-06 10:40:45 -05:00
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 ) ;
}
2018-03-09 06:47:11 -06:00
void AstNode : : allocateDefaultEnumValues ( )
{
log_assert ( type = = AST_ENUM ) ;
int last_enum_int = - 1 ;
for ( auto node : children ) {
log_assert ( node - > type = = AST_ENUM_ITEM ) ;
2020-05-04 12:48:37 -05:00
node - > attributes [ ID : : enum_base_type ] = mkconst_str ( str ) ;
2018-03-09 06:47:11 -06:00
for ( size_t i = 0 ; i < node - > children . size ( ) ; i + + ) {
switch ( node - > children [ i ] - > type ) {
case AST_NONE :
// replace with auto-incremented constant
delete node - > children [ i ] ;
node - > children [ i ] = AstNode : : mkconst_int ( + + last_enum_int , true ) ;
break ;
case AST_CONSTANT :
// explicit constant (or folded expression)
// TODO: can't extend 'x or 'z item
last_enum_int = node - > children [ i ] - > integer ;
break ;
default :
// ignore ranges
break ;
}
// TODO: range check
}
}
}
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_END