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"
2014-08-16 17:57:24 -05:00
# include "kernel/utils.h"
2013-02-27 02:32:19 -06:00
# include "libs/sha1/sha1.h"
2013-01-05 04:13:26 -06:00
# include "ast.h"
# include <sstream>
# include <stdarg.h>
2013-07-09 07:31:57 -05:00
# include <algorithm>
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 ;
// helper function for creating RTLIL code for unary operations
2020-04-02 11:51:32 -05:00
static RTLIL : : SigSpec uniop2rtlil ( AstNode * that , IdString type , int result_width , const RTLIL : : SigSpec & arg , bool gen_attributes = true )
2013-01-05 04:13:26 -06:00
{
2020-04-24 03:08:25 -05:00
IdString name = stringf ( " %s$%s:%d$%d " , type . c_str ( ) , that - > filename . c_str ( ) , that - > location . first_line , autoidx + + ) ;
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( name , type ) ;
2020-04-24 03:08:25 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
2014-08-02 06:11:01 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , result_width ) ;
2020-04-24 03:08:25 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2021-02-05 18:38:10 -06:00
wire - > is_signed = that - > is_signed ;
2013-01-05 04:13:26 -06:00
if ( gen_attributes )
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( that - > filename , that - > location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_SIGNED ] = RTLIL : : Const ( that - > children [ 0 ] - > is_signed ) ;
cell - > parameters [ ID : : A_WIDTH ] = RTLIL : : Const ( arg . size ( ) ) ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , arg ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : Y_WIDTH ] = result_width ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 13:39:13 -05:00
return wire ;
2013-01-05 04:13:26 -06:00
}
2013-11-06 13:50:53 -06:00
// helper function for extending bit width (preferred over SigSpec::extend() because of correct undef propagation in ConstEval)
2014-09-03 19:07:52 -05:00
static void widthExtend ( AstNode * that , RTLIL : : SigSpec & sig , int width , bool is_signed )
2013-11-06 13:50:53 -06:00
{
2014-07-22 13:15:14 -05:00
if ( width < = sig . size ( ) ) {
2014-12-24 02:51:17 -06:00
sig . extend_u0 ( width , is_signed ) ;
2013-11-06 13:50:53 -06:00
return ;
}
2020-04-24 03:08:25 -05:00
IdString name = stringf ( " $extend$%s:%d$%d " , that - > filename . c_str ( ) , that - > location . first_line , autoidx + + ) ;
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( name , ID ( $ pos ) ) ;
2020-04-24 03:08:25 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2013-11-06 13:50:53 -06:00
2014-08-02 06:11:01 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , width ) ;
2020-04-24 03:08:25 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2021-02-05 18:38:10 -06:00
wire - > is_signed = that - > is_signed ;
2013-11-06 13:50:53 -06:00
if ( that ! = NULL )
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( that - > filename , that - > location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-11-06 13:50:53 -06:00
}
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_SIGNED ] = RTLIL : : Const ( is_signed ) ;
cell - > parameters [ ID : : A_WIDTH ] = RTLIL : : Const ( sig . size ( ) ) ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , sig ) ;
2013-11-06 13:50:53 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : Y_WIDTH ] = width ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 13:39:13 -05:00
sig = wire ;
2013-11-06 13:50:53 -06:00
}
2013-01-05 04:13:26 -06:00
// helper function for creating RTLIL code for binary operations
2020-04-02 11:51:32 -05:00
static RTLIL : : SigSpec binop2rtlil ( AstNode * that , IdString type , int result_width , const RTLIL : : SigSpec & left , const RTLIL : : SigSpec & right )
2013-01-05 04:13:26 -06:00
{
2020-04-24 03:08:25 -05:00
IdString name = stringf ( " %s$%s:%d$%d " , type . c_str ( ) , that - > filename . c_str ( ) , that - > location . first_line , autoidx + + ) ;
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( name , type ) ;
2020-04-24 03:08:25 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
2014-08-02 06:11:01 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , result_width ) ;
2020-04-24 03:08:25 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2020-12-18 13:59:08 -06:00
wire - > is_signed = that - > is_signed ;
2013-01-05 04:13:26 -06:00
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( that - > filename , that - > location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_SIGNED ] = RTLIL : : Const ( that - > children [ 0 ] - > is_signed ) ;
cell - > parameters [ ID : : B_SIGNED ] = RTLIL : : Const ( that - > children [ 1 ] - > is_signed ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : A_WIDTH ] = RTLIL : : Const ( left . size ( ) ) ;
cell - > parameters [ ID : : B_WIDTH ] = RTLIL : : Const ( right . size ( ) ) ;
2013-01-05 04:13:26 -06:00
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , left ) ;
cell - > setPort ( ID : : B , right ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : Y_WIDTH ] = result_width ;
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 13:39:13 -05:00
return wire ;
2013-01-05 04:13:26 -06:00
}
// helper function for creating RTLIL code for multiplexers
static RTLIL : : SigSpec mux2rtlil ( AstNode * that , const RTLIL : : SigSpec & cond , const RTLIL : : SigSpec & left , const RTLIL : : SigSpec & right )
{
2014-07-28 04:08:55 -05:00
log_assert ( cond . size ( ) = = 1 ) ;
2013-01-05 04:13:26 -06:00
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < " $ternary$ " < < that - > filename < < " : " < < that - > location . first_line < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ mux ) ) ;
2020-04-24 03:08:25 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
2014-08-02 06:11:01 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , left . size ( ) ) ;
2020-04-24 03:08:25 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , that - > filename . c_str ( ) , that - > location . first_line , that - > location . first_column , that - > location . last_line , that - > location . last_column ) ;
2020-12-22 18:38:51 -06:00
wire - > is_signed = that - > is_signed ;
2013-01-05 04:13:26 -06:00
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( that - > filename , that - > location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : WIDTH ] = RTLIL : : Const ( left . size ( ) ) ;
2013-01-05 04:13:26 -06:00
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , right ) ;
cell - > setPort ( ID : : B , left ) ;
cell - > setPort ( ID : : S , cond ) ;
cell - > setPort ( ID : : Y , wire ) ;
2013-01-05 04:13:26 -06:00
2014-07-22 13:39:13 -05:00
return wire ;
2013-01-05 04:13:26 -06:00
}
2020-04-15 13:36:40 -05:00
// helper class for rewriting simple lookahead references in AST always blocks
struct AST_INTERNAL : : LookaheadRewriter
{
dict < IdString , pair < AstNode * , AstNode * > > lookaheadids ;
void collect_lookaheadids ( AstNode * node )
{
if ( node - > lookahead ) {
log_assert ( node - > type = = AST_IDENTIFIER ) ;
if ( ! lookaheadids . count ( node - > str ) ) {
AstNode * wire = new AstNode ( AST_WIRE ) ;
for ( auto c : node - > id2ast - > children )
wire - > children . push_back ( c - > clone ( ) ) ;
wire - > str = stringf ( " $lookahead%s$%d " , node - > str . c_str ( ) , autoidx + + ) ;
2020-05-04 12:48:37 -05:00
wire - > attributes [ ID : : nosync ] = AstNode : : mkconst_int ( 1 , false ) ;
2020-04-15 13:36:40 -05:00
wire - > is_logic = true ;
while ( wire - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
current_ast_mod - > children . push_back ( wire ) ;
lookaheadids [ node - > str ] = make_pair ( node - > id2ast , wire ) ;
wire - > genRTLIL ( ) ;
}
}
for ( auto child : node - > children )
collect_lookaheadids ( child ) ;
}
bool has_lookaheadids ( AstNode * node )
{
if ( node - > type = = AST_IDENTIFIER & & lookaheadids . count ( node - > str ) ! = 0 )
return true ;
for ( auto child : node - > children )
if ( has_lookaheadids ( child ) )
return true ;
return false ;
}
bool has_nonlookaheadids ( AstNode * node )
{
if ( node - > type = = AST_IDENTIFIER & & lookaheadids . count ( node - > str ) = = 0 )
return true ;
for ( auto child : node - > children )
if ( has_nonlookaheadids ( child ) )
return true ;
return false ;
}
void rewrite_lookaheadids ( AstNode * node , bool lhs = false )
{
if ( node - > type = = AST_ASSIGN_LE )
{
if ( has_lookaheadids ( node - > children [ 0 ] ) )
{
if ( has_nonlookaheadids ( node - > children [ 0 ] ) )
log_error ( " incompatible mix of lookahead and non-lookahead IDs in LHS expression. \n " ) ;
rewrite_lookaheadids ( node - > children [ 0 ] , true ) ;
node - > type = AST_ASSIGN_EQ ;
}
rewrite_lookaheadids ( node - > children [ 1 ] , lhs ) ;
return ;
}
if ( node - > type = = AST_IDENTIFIER & & ( node - > lookahead | | lhs ) ) {
AstNode * newwire = lookaheadids . at ( node - > str ) . second ;
node - > str = newwire - > str ;
node - > id2ast = newwire ;
lhs = false ;
}
for ( auto child : node - > children )
rewrite_lookaheadids ( child , lhs ) ;
}
LookaheadRewriter ( AstNode * top )
{
// top->dumpAst(NULL, "REWRITE-BEFORE> ");
// top->dumpVlog(NULL, "REWRITE-BEFORE> ");
AstNode * block = nullptr ;
for ( auto c : top - > children )
if ( c - > type = = AST_BLOCK ) {
log_assert ( block = = nullptr ) ;
block = c ;
}
log_assert ( block ! = nullptr ) ;
collect_lookaheadids ( block ) ;
rewrite_lookaheadids ( block ) ;
for ( auto it : lookaheadids )
{
AstNode * ref_orig = new AstNode ( AST_IDENTIFIER ) ;
ref_orig - > str = it . second . first - > str ;
ref_orig - > id2ast = it . second . first ;
ref_orig - > was_checked = true ;
AstNode * ref_temp = new AstNode ( AST_IDENTIFIER ) ;
ref_temp - > str = it . second . second - > str ;
ref_temp - > id2ast = it . second . second ;
ref_temp - > was_checked = true ;
AstNode * init_assign = new AstNode ( AST_ASSIGN_EQ , ref_temp - > clone ( ) , ref_orig - > clone ( ) ) ;
AstNode * final_assign = new AstNode ( AST_ASSIGN_LE , ref_orig , ref_temp ) ;
block - > children . insert ( block - > children . begin ( ) , init_assign ) ;
block - > children . push_back ( final_assign ) ;
}
// top->dumpAst(NULL, "REWRITE-AFTER> ");
// top->dumpVlog(NULL, "REWRITE-AFTER> ");
}
} ;
2013-01-05 04:13:26 -06:00
// helper class for converting AST always nodes to RTLIL processes
struct AST_INTERNAL : : ProcessGenerator
{
// input and output structures
AstNode * always ;
2013-11-21 06:49:00 -06:00
RTLIL : : SigSpec initSyncSignals ;
2013-01-05 04:13:26 -06:00
RTLIL : : Process * proc ;
2014-08-14 16:02:07 -05:00
RTLIL : : SigSpec outputSignals ;
2013-01-05 04:13:26 -06:00
2015-08-14 03:56:05 -05:00
// This always points to the RTLIL::CaseRule being filled at the moment
2013-01-05 04:13:26 -06:00
RTLIL : : CaseRule * current_case ;
2014-08-16 12:31:59 -05:00
// This map contains the replacement pattern to be used in the right hand side
2013-01-05 04:13:26 -06:00
// of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right
// hand side of the 2nd assignment needs to be replace with the temporary signal holding
2015-08-14 03:56:05 -05:00
// the value assigned in the first assignment. So when the first assignment is processed
2013-01-05 04:13:26 -06:00
// the according information is appended to subst_rvalue_from and subst_rvalue_to.
2014-08-16 17:57:24 -05:00
stackmap < RTLIL : : SigBit , RTLIL : : SigBit > subst_rvalue_map ;
2013-01-05 04:13:26 -06:00
2014-08-16 12:31:59 -05:00
// This map contains the replacement pattern to be used in the left hand side
2013-01-05 04:13:26 -06:00
// of an assignment. E.g. in the code "always @(posedge clk) foo <= bar" the signal bar
// should not be connected to the signal foo. Instead it must be connected to the temporary
// signal that is used as input for the register that drives the signal foo.
2014-08-16 17:57:24 -05:00
stackmap < RTLIL : : SigBit , RTLIL : : SigBit > subst_lvalue_map ;
2013-01-05 04:13:26 -06:00
2015-08-14 03:56:05 -05:00
// The code here generates a number of temporary signal for each output register. This
2013-01-05 04:13:26 -06:00
// map helps generating nice numbered names for all this temporary signals.
std : : map < RTLIL : : Wire * , int > new_temp_count ;
2013-11-21 06:49:00 -06:00
// Buffer for generating the init action
RTLIL : : SigSpec init_lvalue , init_rvalue ;
2014-08-14 16:02:07 -05:00
ProcessGenerator ( AstNode * always , RTLIL : : SigSpec initSyncSignalsArg = RTLIL : : SigSpec ( ) ) : always ( always ) , initSyncSignals ( initSyncSignalsArg )
2013-01-05 04:13:26 -06:00
{
2020-04-15 13:36:40 -05:00
// rewrite lookahead references
LookaheadRewriter la_rewriter ( always ) ;
2013-01-05 04:13:26 -06:00
// generate process and simple root case
proc = new RTLIL : : Process ;
2020-03-12 14:57:01 -05:00
proc - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , always - > filename . c_str ( ) , always - > location . first_line , always - > location . first_column , always - > location . last_line , always - > location . last_column ) ;
2020-02-23 01:19:52 -06:00
proc - > name = stringf ( " $proc$%s:%d$%d " , always - > filename . c_str ( ) , always - > location . first_line , autoidx + + ) ;
2013-01-05 04:13:26 -06:00
for ( auto & attr : always - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( always - > filename , always - > location . first_line , " Attribute `%s' with non-constant value! \n " ,
2018-07-20 11:37:44 -05:00
attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
proc - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
current_module - > processes [ proc - > name ] = proc ;
current_case = & proc - > root_case ;
// create initial temporary signal for all output registers
2014-08-16 12:31:59 -05:00
RTLIL : : SigSpec subst_lvalue_from , subst_lvalue_to ;
2013-01-05 04:13:26 -06:00
collect_lvalues ( subst_lvalue_from , always , true , true ) ;
subst_lvalue_to = new_temp_signal ( subst_lvalue_from ) ;
2014-08-16 12:31:59 -05:00
subst_lvalue_map = subst_lvalue_from . to_sigbit_map ( subst_lvalue_to ) ;
2013-01-05 04:13:26 -06:00
2016-10-14 05:33:56 -05:00
bool found_global_syncs = false ;
2013-01-05 04:13:26 -06:00
bool found_anyedge_syncs = false ;
for ( auto child : always - > children )
2018-06-01 06:25:42 -05:00
{
if ( ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE ) & & GetSize ( child - > children ) = = 1 & & child - > children . at ( 0 ) - > type = = AST_IDENTIFIER & &
2020-03-12 14:57:01 -05:00
child - > children . at ( 0 ) - > id2ast & & child - > children . at ( 0 ) - > id2ast - > type = = AST_WIRE & & child - > children . at ( 0 ) - > id2ast - > get_bool_attribute ( ID : : gclk ) ) {
2018-06-01 06:25:42 -05:00
found_global_syncs = true ;
}
2016-10-14 05:33:56 -05:00
if ( child - > type = = AST_EDGE ) {
if ( GetSize ( child - > children ) = = 1 & & child - > children . at ( 0 ) - > type = = AST_IDENTIFIER & & child - > children . at ( 0 ) - > str = = " \\ $global_clock " )
found_global_syncs = true ;
else
found_anyedge_syncs = true ;
}
2018-06-01 06:25:42 -05:00
}
2013-01-05 04:13:26 -06:00
if ( found_anyedge_syncs ) {
2016-10-14 05:33:56 -05:00
if ( found_global_syncs )
2020-02-23 01:19:52 -06:00
log_file_error ( always - > filename , always - > location . first_line , " Found non-synthesizable event list! \n " ) ;
log ( " Note: Assuming pure combinatorial block at %s:%d.%d-%d.%d in \n " , always - > filename . c_str ( ) , always - > location . first_line , always - > location . first_column , always - > location . last_line , always - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
log ( " compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending \n " ) ;
log ( " use of @* instead of @(...) for better match of synthesis and simulation. \n " ) ;
}
// create syncs for the process
bool found_clocked_sync = false ;
for ( auto child : always - > children )
if ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE ) {
2018-06-01 06:25:42 -05:00
if ( GetSize ( child - > children ) = = 1 & & child - > children . at ( 0 ) - > type = = AST_IDENTIFIER & & child - > children . at ( 0 ) - > id2ast & &
2020-03-12 14:57:01 -05:00
child - > children . at ( 0 ) - > id2ast - > type = = AST_WIRE & & child - > children . at ( 0 ) - > id2ast - > get_bool_attribute ( ID : : gclk ) )
2018-06-01 06:25:42 -05:00
continue ;
2013-01-05 04:13:26 -06:00
found_clocked_sync = true ;
2016-10-14 05:33:56 -05:00
if ( found_global_syncs | | found_anyedge_syncs )
2020-02-23 01:19:52 -06:00
log_file_error ( always - > filename , always - > location . first_line , " Found non-synthesizable event list! \n " ) ;
2013-01-05 04:13:26 -06:00
RTLIL : : SyncRule * syncrule = new RTLIL : : SyncRule ;
syncrule - > type = child - > type = = AST_POSEDGE ? RTLIL : : STp : RTLIL : : STn ;
syncrule - > signal = child - > children [ 0 ] - > genRTLIL ( ) ;
2016-08-10 12:32:11 -05:00
if ( GetSize ( syncrule - > signal ) ! = 1 )
2020-02-23 01:19:52 -06:00
log_file_error ( always - > filename , always - > location . first_line , " Found posedge/negedge event on a signal that is not 1 bit wide! \n " ) ;
2013-03-25 11:13:14 -05:00
addChunkActions ( syncrule - > actions , subst_lvalue_from , subst_lvalue_to , true ) ;
2013-01-05 04:13:26 -06:00
proc - > syncs . push_back ( syncrule ) ;
}
if ( proc - > syncs . empty ( ) ) {
RTLIL : : SyncRule * syncrule = new RTLIL : : SyncRule ;
2016-10-14 05:33:56 -05:00
syncrule - > type = found_global_syncs ? RTLIL : : STg : RTLIL : : STa ;
2013-01-05 04:13:26 -06:00
syncrule - > signal = RTLIL : : SigSpec ( ) ;
2013-03-25 11:13:14 -05:00
addChunkActions ( syncrule - > actions , subst_lvalue_from , subst_lvalue_to , true ) ;
2013-01-05 04:13:26 -06:00
proc - > syncs . push_back ( syncrule ) ;
}
// create initial assignments for the temporary signals
2020-04-02 11:51:32 -05:00
if ( ( flag_nolatches | | always - > get_bool_attribute ( ID : : nolatches ) | | current_module - > get_bool_attribute ( ID : : nolatches ) ) & & ! found_clocked_sync ) {
2014-12-28 12:24:24 -06:00
subst_rvalue_map = subst_lvalue_from . to_sigbit_dict ( RTLIL : : SigSpec ( RTLIL : : State : : Sx , GetSize ( subst_lvalue_from ) ) ) ;
2013-01-05 04:13:26 -06:00
} else {
addChunkActions ( current_case - > actions , subst_lvalue_to , subst_lvalue_from ) ;
}
// process the AST
for ( auto child : always - > children )
if ( child - > type = = AST_BLOCK )
processAst ( child ) ;
2013-11-21 06:49:00 -06:00
2014-07-22 13:15:14 -05:00
if ( initSyncSignals . size ( ) > 0 )
2013-11-21 06:49:00 -06:00
{
RTLIL : : SyncRule * sync = new RTLIL : : SyncRule ;
sync - > type = RTLIL : : SyncType : : STi ;
proc - > syncs . push_back ( sync ) ;
2014-07-28 04:08:55 -05:00
log_assert ( init_lvalue . size ( ) = = init_rvalue . size ( ) ) ;
2013-11-21 06:49:00 -06:00
int offset = 0 ;
2014-07-24 15:47:57 -05:00
for ( auto & init_lvalue_c : init_lvalue . chunks ( ) ) {
RTLIL : : SigSpec lhs = init_lvalue_c ;
RTLIL : : SigSpec rhs = init_rvalue . extract ( offset , init_lvalue_c . width ) ;
2014-09-06 10:58:27 -05:00
remove_unwanted_lvalue_bits ( lhs , rhs ) ;
2013-11-21 06:49:00 -06:00
sync - > actions . push_back ( RTLIL : : SigSig ( lhs , rhs ) ) ;
2014-07-22 13:15:14 -05:00
offset + = lhs . size ( ) ;
2013-11-21 06:49:00 -06:00
}
}
2014-08-14 16:02:07 -05:00
outputSignals = RTLIL : : SigSpec ( subst_lvalue_from ) ;
2013-01-05 04:13:26 -06:00
}
2014-09-06 10:58:27 -05:00
void remove_unwanted_lvalue_bits ( RTLIL : : SigSpec & lhs , RTLIL : : SigSpec & rhs )
{
RTLIL : : SigSpec new_lhs , new_rhs ;
2014-10-10 09:59:44 -05:00
log_assert ( GetSize ( lhs ) = = GetSize ( rhs ) ) ;
for ( int i = 0 ; i < GetSize ( lhs ) ; i + + ) {
2014-09-06 10:58:27 -05:00
if ( lhs [ i ] . wire = = nullptr )
continue ;
new_lhs . append ( lhs [ i ] ) ;
new_rhs . append ( rhs [ i ] ) ;
}
lhs = new_lhs ;
rhs = new_rhs ;
}
2013-01-05 04:13:26 -06:00
// create new temporary signals
RTLIL : : SigSpec new_temp_signal ( RTLIL : : SigSpec sig )
{
2014-07-22 16:50:21 -05:00
std : : vector < RTLIL : : SigChunk > chunks = sig . chunks ( ) ;
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( chunks ) ; i + + )
2013-01-05 04:13:26 -06:00
{
2014-07-22 16:50:21 -05:00
RTLIL : : SigChunk & chunk = chunks [ i ] ;
2013-01-05 04:13:26 -06:00
if ( chunk . wire = = NULL )
continue ;
2014-07-26 13:12:50 -05:00
std : : string wire_name ;
2013-01-05 04:13:26 -06:00
do {
2014-07-26 13:12:50 -05:00
wire_name = stringf ( " $%d%s[%d:%d] " , new_temp_count [ chunk . wire ] + + ,
2013-01-05 04:13:26 -06:00
chunk . wire - > name . c_str ( ) , chunk . width + chunk . offset - 1 , chunk . offset ) ; ;
2014-08-02 06:11:01 -05:00
if ( chunk . wire - > name . str ( ) . find ( ' $ ' ) ! = std : : string : : npos )
2014-07-31 06:19:47 -05:00
wire_name + = stringf ( " $%d " , autoidx + + ) ;
2014-07-26 18:49:51 -05:00
} while ( current_module - > wires_ . count ( wire_name ) > 0 ) ;
2014-07-26 13:12:50 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( wire_name , chunk . width ) ;
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , always - > filename . c_str ( ) , always - > location . first_line , always - > location . first_column , always - > location . last_line , always - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
chunk . wire = wire ;
chunk . offset = 0 ;
}
2014-07-22 16:50:21 -05:00
return chunks ;
2013-01-05 04:13:26 -06:00
}
2020-04-15 13:36:40 -05:00
// recursively traverse the AST and collect all assigned signals
2013-01-05 04:13:26 -06:00
void collect_lvalues ( RTLIL : : SigSpec & reg , AstNode * ast , bool type_eq , bool type_le , bool run_sort_and_unify = true )
{
switch ( ast - > type )
{
case AST_CASE :
for ( auto child : ast - > children )
if ( child ! = ast - > children [ 0 ] ) {
2016-04-21 08:31:54 -05:00
log_assert ( child - > type = = AST_COND | | child - > type = = AST_CONDX | | child - > type = = AST_CONDZ ) ;
2013-01-05 04:13:26 -06:00
collect_lvalues ( reg , child , type_eq , type_le , false ) ;
}
break ;
case AST_COND :
2016-04-21 08:31:54 -05:00
case AST_CONDX :
case AST_CONDZ :
2013-01-05 04:13:26 -06:00
case AST_ALWAYS :
2013-03-31 04:19:11 -05:00
case AST_INITIAL :
2013-01-05 04:13:26 -06:00
for ( auto child : ast - > children )
if ( child - > type = = AST_BLOCK )
collect_lvalues ( reg , child , type_eq , type_le , false ) ;
break ;
case AST_BLOCK :
for ( auto child : ast - > children ) {
if ( child - > type = = AST_ASSIGN_EQ & & type_eq )
reg . append ( child - > children [ 0 ] - > genRTLIL ( ) ) ;
if ( child - > type = = AST_ASSIGN_LE & & type_le )
reg . append ( child - > children [ 0 ] - > genRTLIL ( ) ) ;
if ( child - > type = = AST_CASE | | child - > type = = AST_BLOCK )
collect_lvalues ( reg , child , type_eq , type_le , false ) ;
}
break ;
default :
2014-07-28 04:08:55 -05:00
log_abort ( ) ;
2013-01-05 04:13:26 -06:00
}
2014-09-06 10:58:27 -05:00
if ( run_sort_and_unify ) {
std : : set < RTLIL : : SigBit > sorted_reg ;
for ( auto bit : reg )
if ( bit . wire )
sorted_reg . insert ( bit ) ;
reg = RTLIL : : SigSpec ( sorted_reg ) ;
}
2013-01-05 04:13:26 -06:00
}
2013-04-13 14:19:10 -05:00
// remove all assignments to the given signal pattern in a case and all its children.
// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
// function is called to clean up the first two assignments as they are overwritten by
2013-01-05 04:13:26 -06:00
// the third assignment.
2016-01-30 21:26:46 -06:00
void removeSignalFromCaseTree ( const RTLIL : : SigSpec & pattern , RTLIL : : CaseRule * cs )
2013-01-05 04:13:26 -06:00
{
for ( auto it = cs - > actions . begin ( ) ; it ! = cs - > actions . end ( ) ; it + + )
it - > first . remove2 ( pattern , & it - > second ) ;
for ( auto it = cs - > switches . begin ( ) ; it ! = cs - > switches . end ( ) ; it + + )
for ( auto it2 = ( * it ) - > cases . begin ( ) ; it2 ! = ( * it ) - > cases . end ( ) ; it2 + + )
removeSignalFromCaseTree ( pattern , * it2 ) ;
}
// add an assignment (aka "action") but split it up in chunks. this way huge assignments
// are avoided and the generated $mux cells have a more "natural" size.
2013-03-31 04:51:12 -05:00
void addChunkActions ( std : : vector < RTLIL : : SigSig > & actions , RTLIL : : SigSpec lvalue , RTLIL : : SigSpec rvalue , bool inSyncRule = false )
2013-01-05 04:13:26 -06:00
{
2014-07-22 13:15:14 -05:00
if ( inSyncRule & & initSyncSignals . size ( ) > 0 ) {
2013-11-21 06:49:00 -06:00
init_lvalue . append ( lvalue . extract ( initSyncSignals ) ) ;
init_rvalue . append ( lvalue . extract ( initSyncSignals , & rvalue ) ) ;
lvalue . remove2 ( initSyncSignals , & rvalue ) ;
}
2014-07-28 04:08:55 -05:00
log_assert ( lvalue . size ( ) = = rvalue . size ( ) ) ;
2013-01-05 04:13:26 -06:00
int offset = 0 ;
2014-07-24 15:47:57 -05:00
for ( auto & lvalue_c : lvalue . chunks ( ) ) {
RTLIL : : SigSpec lhs = lvalue_c ;
RTLIL : : SigSpec rhs = rvalue . extract ( offset , lvalue_c . width ) ;
2020-04-02 11:51:32 -05:00
if ( inSyncRule & & lvalue_c . wire & & lvalue_c . wire - > get_bool_attribute ( ID : : nosync ) )
2014-07-22 13:15:14 -05:00
rhs = RTLIL : : SigSpec ( RTLIL : : State : : Sx , rhs . size ( ) ) ;
2014-09-06 10:58:27 -05:00
remove_unwanted_lvalue_bits ( lhs , rhs ) ;
2013-01-05 04:13:26 -06:00
actions . push_back ( RTLIL : : SigSig ( lhs , rhs ) ) ;
2014-07-22 13:15:14 -05:00
offset + = lhs . size ( ) ;
2013-01-05 04:13:26 -06:00
}
}
// recursively process the AST and fill the RTLIL::Process
void processAst ( AstNode * ast )
{
switch ( ast - > type )
{
case AST_BLOCK :
for ( auto child : ast - > children )
processAst ( child ) ;
break ;
case AST_ASSIGN_EQ :
case AST_ASSIGN_LE :
{
RTLIL : : SigSpec unmapped_lvalue = ast - > children [ 0 ] - > genRTLIL ( ) , lvalue = unmapped_lvalue ;
2014-08-16 17:57:24 -05:00
RTLIL : : SigSpec rvalue = ast - > children [ 1 ] - > genWidthRTLIL ( lvalue . size ( ) , & subst_rvalue_map . stdmap ( ) ) ;
2016-05-27 10:55:03 -05:00
pool < SigBit > lvalue_sigbits ;
for ( int i = 0 ; i < GetSize ( lvalue ) ; i + + ) {
if ( lvalue_sigbits . count ( lvalue [ i ] ) > 0 ) {
unmapped_lvalue . remove ( i ) ;
lvalue . remove ( i ) ;
rvalue . remove ( i - - ) ;
} else
lvalue_sigbits . insert ( lvalue [ i ] ) ;
}
2014-08-16 17:57:24 -05:00
lvalue . replace ( subst_lvalue_map . stdmap ( ) ) ;
2013-01-05 04:13:26 -06:00
if ( ast - > type = = AST_ASSIGN_EQ ) {
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( unmapped_lvalue ) ; i + + )
2014-08-16 17:57:24 -05:00
subst_rvalue_map . set ( unmapped_lvalue [ i ] , rvalue [ i ] ) ;
2013-01-05 04:13:26 -06:00
}
2016-01-30 21:26:46 -06:00
removeSignalFromCaseTree ( lvalue , current_case ) ;
2014-09-06 10:58:27 -05:00
remove_unwanted_lvalue_bits ( lvalue , rvalue ) ;
2013-01-05 04:13:26 -06:00
current_case - > actions . push_back ( RTLIL : : SigSig ( lvalue , rvalue ) ) ;
}
break ;
case AST_CASE :
{
RTLIL : : SwitchRule * sw = new RTLIL : : SwitchRule ;
2020-03-12 14:57:01 -05:00
sw - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , ast - > filename . c_str ( ) , ast - > location . first_line , ast - > location . first_column , ast - > location . last_line , ast - > location . last_column ) ;
2014-08-16 17:57:24 -05:00
sw - > signal = ast - > children [ 0 ] - > genWidthRTLIL ( - 1 , & subst_rvalue_map . stdmap ( ) ) ;
2013-01-05 04:13:26 -06:00
current_case - > switches . push_back ( sw ) ;
for ( auto & attr : ast - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( ast - > filename , ast - > location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
sw - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
RTLIL : : SigSpec this_case_eq_lvalue ;
collect_lvalues ( this_case_eq_lvalue , ast , true , false ) ;
RTLIL : : SigSpec this_case_eq_ltemp = new_temp_signal ( this_case_eq_lvalue ) ;
RTLIL : : SigSpec this_case_eq_rvalue = this_case_eq_lvalue ;
2014-08-16 17:57:24 -05:00
this_case_eq_rvalue . replace ( subst_rvalue_map . stdmap ( ) ) ;
2013-01-05 04:13:26 -06:00
2013-11-18 09:10:50 -06:00
RTLIL : : CaseRule * default_case = NULL ;
2013-01-05 04:13:26 -06:00
RTLIL : : CaseRule * last_generated_case = NULL ;
for ( auto child : ast - > children )
{
2013-11-18 09:10:50 -06:00
if ( child = = ast - > children [ 0 ] )
2013-01-05 04:13:26 -06:00
continue ;
2016-04-21 08:31:54 -05:00
log_assert ( child - > type = = AST_COND | | child - > type = = AST_CONDX | | child - > type = = AST_CONDZ ) ;
2013-01-05 04:13:26 -06:00
2014-08-16 17:57:24 -05:00
subst_lvalue_map . save ( ) ;
subst_rvalue_map . save ( ) ;
2013-01-05 04:13:26 -06:00
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( this_case_eq_lvalue ) ; i + + )
2014-08-16 17:57:24 -05:00
subst_lvalue_map . set ( this_case_eq_lvalue [ i ] , this_case_eq_ltemp [ i ] ) ;
2013-01-05 04:13:26 -06:00
RTLIL : : CaseRule * backup_case = current_case ;
current_case = new RTLIL : : CaseRule ;
2020-03-12 14:57:01 -05:00
current_case - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , child - > filename . c_str ( ) , child - > location . first_line , child - > location . first_column , child - > location . last_line , child - > location . last_column ) ;
2013-01-05 04:13:26 -06:00
last_generated_case = current_case ;
addChunkActions ( current_case - > actions , this_case_eq_ltemp , this_case_eq_rvalue ) ;
for ( auto node : child - > children ) {
2013-11-18 09:10:50 -06:00
if ( node - > type = = AST_DEFAULT )
default_case = current_case ;
else if ( node - > type = = AST_BLOCK )
2013-01-05 04:13:26 -06:00
processAst ( node ) ;
2014-08-16 12:31:59 -05:00
else
2014-08-16 17:57:24 -05:00
current_case - > compare . push_back ( node - > genWidthRTLIL ( sw - > signal . size ( ) , & subst_rvalue_map . stdmap ( ) ) ) ;
2013-01-05 04:13:26 -06:00
}
2013-11-18 09:10:50 -06:00
if ( default_case ! = current_case )
sw - > cases . push_back ( current_case ) ;
else
log_assert ( current_case - > compare . size ( ) = = 0 ) ;
2013-01-05 04:13:26 -06:00
current_case = backup_case ;
2014-08-16 17:57:24 -05:00
subst_lvalue_map . restore ( ) ;
subst_rvalue_map . restore ( ) ;
2013-01-05 04:13:26 -06:00
}
2020-03-12 14:57:01 -05:00
if ( last_generated_case ! = NULL & & ast - > get_bool_attribute ( ID : : full_case ) & & default_case = = NULL ) {
2019-03-14 11:51:21 -05:00
#if 0
// this is a valid transformation, but as optimization it is premature.
// better: add a default case that assigns 'x' to everything, and let later
// optimizations take care of the rest
2013-01-05 04:13:26 -06:00
last_generated_case - > compare . clear ( ) ;
2019-03-14 11:51:21 -05:00
# else
default_case = new RTLIL : : CaseRule ;
addChunkActions ( default_case - > actions , this_case_eq_ltemp , SigSpec ( State : : Sx , GetSize ( this_case_eq_rvalue ) ) ) ;
sw - > cases . push_back ( default_case ) ;
# endif
2013-11-18 09:10:50 -06:00
} else {
if ( default_case = = NULL ) {
default_case = new RTLIL : : CaseRule ;
addChunkActions ( default_case - > actions , this_case_eq_ltemp , this_case_eq_rvalue ) ;
}
2013-01-05 04:13:26 -06:00
sw - > cases . push_back ( default_case ) ;
}
2014-10-10 09:59:44 -05:00
for ( int i = 0 ; i < GetSize ( this_case_eq_lvalue ) ; i + + )
2014-08-16 17:57:24 -05:00
subst_rvalue_map . set ( this_case_eq_lvalue [ i ] , this_case_eq_ltemp [ i ] ) ;
2013-01-05 04:13:26 -06:00
2014-08-16 17:57:24 -05:00
this_case_eq_lvalue . replace ( subst_lvalue_map . stdmap ( ) ) ;
2016-01-30 21:26:46 -06:00
removeSignalFromCaseTree ( this_case_eq_lvalue , current_case ) ;
2013-01-05 04:13:26 -06:00
addChunkActions ( current_case - > actions , this_case_eq_lvalue , this_case_eq_ltemp ) ;
}
break ;
2013-12-04 02:10:16 -06:00
case AST_WIRE :
2020-02-23 01:19:52 -06:00
log_file_error ( ast - > filename , ast - > location . first_line , " Found reg declaration in block without label! \n " ) ;
2019-03-02 13:40:57 -06:00
break ;
case AST_ASSIGN :
2020-02-23 01:19:52 -06:00
log_file_error ( ast - > filename , ast - > location . first_line , " Found continous assignment in always/initial block! \n " ) ;
2013-12-04 02:10:16 -06:00
break ;
2015-11-11 03:54:35 -06:00
case AST_PARAMETER :
case AST_LOCALPARAM :
2020-02-23 01:19:52 -06:00
log_file_error ( ast - > filename , ast - > location . first_line , " Found parameter declaration in block without label! \n " ) ;
2015-11-11 03:54:35 -06:00
break ;
2016-08-21 06:23:58 -05:00
case AST_NONE :
2013-01-05 04:13:26 -06:00
case AST_TCALL :
case AST_FOR :
break ;
default :
2017-12-02 11:52:05 -06:00
// ast->dumpAst(NULL, "ast> ");
// current_ast_mod->dumpAst(NULL, "mod> ");
2014-06-06 15:55:02 -05:00
log_abort ( ) ;
2013-01-05 04:13:26 -06:00
}
}
} ;
2013-07-09 07:31:57 -05:00
// detect sign and width of an expression
2014-06-16 08:00:57 -05:00
void AstNode : : detectSignWidthWorker ( int & width_hint , bool & sign_hint , bool * found_real )
2013-07-09 07:31:57 -05:00
{
std : : string type_name ;
2013-11-02 07:00:17 -05:00
bool sub_sign_hint = true ;
int sub_width_hint = - 1 ;
int this_width = 0 ;
AstNode * range = NULL ;
2013-11-07 02:58:15 -06:00
AstNode * id_ast = NULL ;
2013-07-09 07:31:57 -05:00
2014-06-21 14:41:13 -05:00
bool local_found_real = false ;
if ( found_real = = NULL )
found_real = & local_found_real ;
2013-07-09 07:31:57 -05:00
switch ( type )
{
2018-03-09 06:47:11 -06:00
case AST_NONE :
// unallocated enum, ignore
break ;
2013-07-09 07:31:57 -05:00
case AST_CONSTANT :
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , int ( bits . size ( ) ) ) ;
2013-07-09 07:31:57 -05:00
if ( ! is_signed )
sign_hint = false ;
break ;
2014-06-14 00:44:19 -05:00
case AST_REALVALUE :
2014-06-21 14:41:13 -05:00
* found_real = true ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , 32 ) ;
2014-06-14 00:44:19 -05:00
break ;
2013-07-09 07:31:57 -05:00
case AST_IDENTIFIER :
2013-11-07 02:58:15 -06:00
id_ast = id2ast ;
if ( id_ast = = NULL & & current_scope . count ( str ) )
id_ast = current_scope . at ( 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 " , str . c_str ( ) ) ;
2018-03-09 06:47:11 -06:00
if ( id_ast - > type = = AST_PARAMETER | | id_ast - > type = = AST_LOCALPARAM | | id_ast - > type = = AST_ENUM_ITEM ) {
2013-11-07 02:58:15 -06:00
if ( id_ast - > children . size ( ) > 1 & & id_ast - > children [ 1 ] - > range_valid ) {
this_width = id_ast - > children [ 1 ] - > range_left - id_ast - > children [ 1 ] - > range_right + 1 ;
} else
2015-03-01 04:20:22 -06:00
if ( id_ast - > children [ 0 ] - > type ! = AST_CONSTANT )
while ( id_ast - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( id_ast - > children [ 0 ] - > type = = AST_CONSTANT )
2013-11-07 02:58:15 -06:00
this_width = id_ast - > children [ 0 ] - > bits . size ( ) ;
2015-03-01 04:20:22 -06:00
else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width for parameter %s! \n " , str . c_str ( ) ) ;
2013-11-02 07:00:17 -05:00
if ( children . size ( ) ! = 0 )
range = children [ 0 ] ;
2013-11-07 02:58:15 -06:00
} else if ( id_ast - > type = = AST_WIRE | | id_ast - > type = = AST_AUTOWIRE ) {
if ( ! id_ast - > range_valid ) {
if ( id_ast - > type = = AST_AUTOWIRE )
2013-11-02 07:00:17 -05:00
this_width = 1 ;
else {
2014-06-06 17:02:05 -05:00
// current_ast_mod->dumpAst(NULL, "mod> ");
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width of signal access `%s'! \n " , str . c_str ( ) ) ;
2013-11-02 07:00:17 -05:00
}
} else {
2013-11-07 02:58:15 -06:00
this_width = id_ast - > range_left - id_ast - > range_right + 1 ;
2013-11-02 07:00:17 -05:00
if ( children . size ( ) ! = 0 )
range = children [ 0 ] ;
}
2013-11-07 02:58:15 -06:00
} else if ( id_ast - > type = = AST_GENVAR ) {
2013-11-02 07:00:17 -05:00
this_width = 32 ;
2013-11-07 02:58:15 -06:00
} else if ( id_ast - > type = = AST_MEMORY ) {
if ( ! id_ast - > children [ 0 ] - > 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 " , str . c_str ( ) ) ;
2013-11-07 02:58:15 -06:00
this_width = id_ast - > children [ 0 ] - > range_left - id_ast - > children [ 0 ] - > range_right + 1 ;
2019-05-01 02:57:26 -05:00
if ( children . size ( ) > 1 )
range = children [ 1 ] ;
2013-11-02 07:00:17 -05:00
} else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width for identifier %s! \n " , str . c_str ( ) ) ;
2013-11-02 07:00:17 -05:00
if ( range ) {
if ( range - > children . size ( ) = = 1 )
this_width = 1 ;
else if ( ! range - > range_valid ) {
AstNode * left_at_zero_ast = children [ 0 ] - > children [ 0 ] - > clone ( ) ;
AstNode * right_at_zero_ast = children [ 0 ] - > children . size ( ) > = 2 ? children [ 0 ] - > children [ 1 ] - > clone ( ) : left_at_zero_ast - > clone ( ) ;
2014-02-14 12:56:44 -06: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 ) ) { }
2013-11-02 07:00:17 -05: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 ( ) ) ;
2019-02-21 11:40:11 -06:00
this_width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2013-11-02 07:00:17 -05:00
delete left_at_zero_ast ;
delete right_at_zero_ast ;
} else
this_width = range - > range_left - range - > range_right + 1 ;
2014-07-28 03:10:08 -05:00
sign_hint = false ;
2014-07-28 08:19:34 -05:00
}
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , this_width ) ;
2013-11-07 02:58:15 -06:00
if ( ! id_ast - > is_signed )
2013-11-02 15:13:01 -05:00
sign_hint = false ;
2013-07-09 07:31:57 -05:00
break ;
2014-02-01 06:50:23 -06:00
case AST_TO_BITS :
2014-02-14 12:56:44 -06:00
while ( children [ 0 ] - > simplify ( true , false , false , 1 , - 1 , false , false ) = = true ) { }
2014-02-01 06:50:23 -06:00
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Left operand of tobits expression is not constant! \n " ) ;
2014-02-01 06:50:23 -06:00
children [ 1 ] - > detectSignWidthWorker ( sub_width_hint , sign_hint ) ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , children [ 0 ] - > bitsAsConst ( ) . as_int ( ) ) ;
2014-02-01 06:50:23 -06:00
break ;
2013-07-09 07:31:57 -05:00
case AST_TO_SIGNED :
2013-11-02 07:00:17 -05:00
children . at ( 0 ) - > detectSignWidthWorker ( width_hint , sub_sign_hint ) ;
2013-07-09 07:31:57 -05:00
break ;
case AST_TO_UNSIGNED :
2013-11-02 07:00:17 -05:00
children . at ( 0 ) - > detectSignWidthWorker ( width_hint , sub_sign_hint ) ;
2013-07-09 07:31:57 -05:00
sign_hint = false ;
break ;
2020-04-29 07:28:04 -05:00
case AST_SELFSZ :
sub_width_hint = 0 ;
children . at ( 0 ) - > detectSignWidthWorker ( sub_width_hint , sign_hint ) ;
break ;
2020-06-14 17:15:59 -05:00
case AST_CAST_SIZE :
while ( children . at ( 0 ) - > simplify ( true , false , false , 1 , - 1 , false , false ) ) { }
if ( children . at ( 0 ) - > type ! = AST_CONSTANT )
log_file_error ( filename , location . first_line , " Static cast with non constant expression! \n " ) ;
children . at ( 1 ) - > detectSignWidthWorker ( width_hint , sign_hint ) ;
width_hint = children . at ( 0 ) - > bitsAsConst ( ) . as_int ( ) ;
if ( width_hint < = 0 )
log_file_error ( filename , location . first_line , " Static cast with zero or negative size! \n " ) ;
break ;
2013-07-09 07:31:57 -05:00
case AST_CONCAT :
2013-11-02 07:00:17 -05:00
for ( auto child : children ) {
sub_width_hint = 0 ;
sub_sign_hint = true ;
2013-11-03 11:56:45 -06:00
child - > detectSignWidthWorker ( sub_width_hint , sub_sign_hint ) ;
2013-11-02 07:00:17 -05:00
this_width + = sub_width_hint ;
}
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , this_width ) ;
2013-11-02 07:00:17 -05:00
sign_hint = false ;
break ;
2013-07-09 07:31:57 -05:00
case AST_REPLICATE :
2014-06-06 17:02:05 -05:00
while ( children [ 0 ] - > simplify ( true , false , false , 1 , - 1 , false , true ) = = true ) { }
2013-11-02 07:00:17 -05:00
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Left operand of replicate expression is not constant! \n " ) ;
2013-11-02 07:00:17 -05:00
children [ 1 ] - > detectSignWidthWorker ( sub_width_hint , sub_sign_hint ) ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , children [ 0 ] - > bitsAsConst ( ) . as_int ( ) * sub_width_hint ) ;
2013-07-09 07:31:57 -05:00
sign_hint = false ;
break ;
case AST_NEG :
case AST_BIT_NOT :
case AST_POS :
2014-06-24 08:08:48 -05:00
children [ 0 ] - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
break ;
case AST_BIT_AND :
case AST_BIT_OR :
case AST_BIT_XOR :
case AST_BIT_XNOR :
for ( auto child : children )
2014-06-24 08:08:48 -05:00
child - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
break ;
case AST_REDUCE_AND :
case AST_REDUCE_OR :
case AST_REDUCE_XOR :
case AST_REDUCE_XNOR :
case AST_REDUCE_BOOL :
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 07:31:57 -05:00
sign_hint = false ;
break ;
case AST_SHIFT_LEFT :
case AST_SHIFT_RIGHT :
case AST_SHIFT_SLEFT :
case AST_SHIFT_SRIGHT :
2020-04-27 10:04:47 -05:00
case AST_SHIFTX :
case AST_SHIFT :
2013-08-19 13:58:01 -05:00
case AST_POW :
2014-06-24 08:08:48 -05:00
children [ 0 ] - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
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-07-09 07:31:57 -05:00
case AST_GE :
case AST_GT :
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 07:31:57 -05:00
sign_hint = false ;
break ;
case AST_ADD :
case AST_SUB :
case AST_MUL :
case AST_DIV :
case AST_MOD :
for ( auto child : children )
2014-06-24 08:08:48 -05:00
child - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
break ;
case AST_LOGIC_AND :
case AST_LOGIC_OR :
case AST_LOGIC_NOT :
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 16:41:28 -05:00
sign_hint = false ;
2013-07-09 07:31:57 -05:00
break ;
case AST_TERNARY :
2014-06-24 08:08:48 -05:00
children . at ( 1 ) - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
children . at ( 2 ) - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
break ;
case AST_MEMRD :
2013-11-03 23:04:42 -06:00
if ( ! id2ast - > is_signed )
2013-07-09 07:31:57 -05:00
sign_hint = false ;
2013-11-03 23:04:42 -06:00
if ( ! id2ast - > children [ 0 ] - > 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 " , str . c_str ( ) ) ;
2013-11-03 23:04:42 -06:00
this_width = id2ast - > children [ 0 ] - > range_left - id2ast - > children [ 0 ] - > range_right + 1 ;
2015-10-25 13:30:49 -05:00
width_hint = max ( width_hint , this_width ) ;
2013-07-09 07:31:57 -05:00
break ;
2016-07-27 08:41:22 -05:00
case AST_FCALL :
2018-02-23 06:14:47 -06:00
if ( str = = " \\ $anyconst " | | str = = " \\ $anyseq " | | str = = " \\ $allconst " | | str = = " \\ $allseq " ) {
2016-07-27 08:41:22 -05:00
if ( GetSize ( children ) = = 1 ) {
while ( children [ 0 ] - > simplify ( true , false , false , 1 , - 1 , false , true ) = = true ) { }
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s called with non-const argument! \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
2016-07-27 08:41:22 -05:00
width_hint = max ( width_hint , int ( children [ 0 ] - > asInt ( true ) ) ) ;
}
break ;
}
2016-09-18 18:30:07 -05:00
if ( str = = " \\ $past " ) {
if ( GetSize ( children ) > 0 ) {
sub_width_hint = 0 ;
sub_sign_hint = true ;
children . at ( 0 ) - > detectSignWidthWorker ( sub_width_hint , sub_sign_hint ) ;
width_hint = max ( width_hint , sub_width_hint ) ;
sign_hint = false ;
}
break ;
}
2021-02-12 13:25:34 -06:00
if ( current_scope . count ( str ) )
{
// This width detection is needed for function calls which are
// unelaborated, which currently only applies to calls to recursive
// functions reached by unevaluated ternary branches.
const AstNode * func = current_scope . at ( str ) ;
if ( func - > type ! = AST_FUNCTION )
log_file_error ( filename , location . first_line , " Function call to %s resolved to something that isn't a function! \n " , RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
const AstNode * wire = nullptr ;
for ( const AstNode * child : func - > children )
if ( child - > str = = func - > str ) {
wire = child ;
break ;
}
log_assert ( wire & & wire - > type = = AST_WIRE ) ;
sign_hint = wire - > is_signed ;
width_hint = 1 ;
if ( ! wire - > children . empty ( ) )
{
log_assert ( wire - > children . size ( ) = = 1 ) ;
const AstNode * range = wire - > children . at ( 0 ) ;
log_assert ( range - > type = = AST_RANGE & & range - > children . size ( ) = = 2 ) ;
AstNode * left = range - > children . at ( 0 ) - > clone ( ) ;
AstNode * right = range - > children . at ( 1 ) - > clone ( ) ;
while ( left - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
while ( right - > simplify ( true , false , false , 1 , - 1 , false , true ) ) { }
if ( left - > type ! = AST_CONSTANT | | right - > type ! = AST_CONSTANT )
log_file_error ( filename , location . first_line , " Function %s has non-constant width! " ,
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
width_hint = abs ( int ( left - > asInt ( true ) - right - > asInt ( true ) ) ) ;
delete left ;
delete right ;
}
break ;
}
2020-05-04 14:12:30 -05:00
YS_FALLTHROUGH
2016-07-27 08:41:22 -05:00
2013-07-09 07:31:57 -05:00
// everything should have been handled above -> print error if not.
default :
for ( auto f : log_files )
2019-02-21 10:36:51 -06:00
current_ast_mod - > dumpAst ( f , " verilog-ast> " ) ;
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Don't know how to detect sign and width for %s node! \n " , type2str ( type ) . c_str ( ) ) ;
2013-07-09 07:31:57 -05:00
}
2014-06-21 14:41:13 -05:00
if ( * found_real )
sign_hint = true ;
2013-07-09 07:31:57 -05:00
}
// detect sign and width of an expression
2014-06-16 08:00:57 -05:00
void AstNode : : detectSignWidth ( int & width_hint , bool & sign_hint , bool * found_real )
2013-07-09 07:31:57 -05:00
{
2014-06-16 08:00:57 -05:00
width_hint = - 1 ;
sign_hint = true ;
if ( found_real )
* found_real = false ;
detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 07:31:57 -05:00
}
2013-01-05 04:13:26 -06:00
// create RTLIL from an AST node
// all generated cells, wires and processes are added to the module pointed to by 'current_module'
// when the AST node is an expression (AST_ADD, AST_BIT_XOR, etc.), the result signal is returned.
//
// note that this function is influenced by a number of global variables that might be set when
// called from genWidthRTLIL(). also note that this function recursively calls itself to transform
// larger expressions into a netlist of cells.
2013-07-09 07:31:57 -05:00
RTLIL : : SigSpec AstNode : : genRTLIL ( int width_hint , bool sign_hint )
2013-01-05 04:13:26 -06:00
{
// in the following big switch() statement there are some uses of
// Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this
// cases this variable is used to hold the type of the cell that should
2015-08-14 03:56:05 -05:00
// be instantiated for this type of AST node.
2020-04-02 11:51:32 -05:00
IdString type_name ;
2013-01-05 04:13:26 -06:00
current_filename = filename ;
switch ( type )
{
// simply ignore this nodes.
2015-08-14 03:56:05 -05:00
// they are either leftovers from simplify() or are referenced by other nodes
2013-01-05 04:13:26 -06:00
// and are only accessed here thru this references
2016-08-21 06:23:58 -05:00
case AST_NONE :
2013-01-05 04:13:26 -06:00
case AST_TASK :
case AST_FUNCTION :
2014-08-21 05:43:51 -05:00
case AST_DPI_FUNCTION :
2013-01-05 04:13:26 -06:00
case AST_AUTOWIRE :
2013-07-04 07:12:33 -05:00
case AST_DEFPARAM :
2013-01-05 04:13:26 -06:00
case AST_GENVAR :
case AST_GENFOR :
2013-03-26 03:44:54 -05:00
case AST_GENBLOCK :
2013-01-05 04:13:26 -06:00
case AST_GENIF :
2013-12-04 14:06:54 -06:00
case AST_GENCASE :
2016-06-18 03:24:21 -05:00
case AST_PACKAGE :
2018-03-09 06:47:11 -06:00
case AST_ENUM :
2018-10-12 13:58:37 -05:00
case AST_MODPORT :
case AST_MODPORTMEMBER :
2019-09-19 14:43:13 -05:00
case AST_TYPEDEF :
2020-05-08 08:40:49 -05:00
case AST_STRUCT :
2020-05-12 08:25:33 -05:00
case AST_UNION :
2013-01-05 04:13:26 -06:00
break ;
2018-10-11 16:33:31 -05:00
case AST_INTERFACEPORT : {
2018-10-13 13:34:44 -05:00
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
2018-10-11 16:33:31 -05:00
// This is used by the hierarchy pass to know when it can replace interface connection with the individual
// signals.
RTLIL : : Wire * wire = current_module - > addWire ( str , 1 ) ;
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2018-10-11 16:33:31 -05:00
wire - > start_offset = 0 ;
wire - > port_id = port_id ;
wire - > port_input = true ;
wire - > port_output = true ;
2020-03-12 14:57:01 -05:00
wire - > set_bool_attribute ( ID : : is_interface ) ;
2018-10-12 13:58:37 -05:00
if ( children . size ( ) > 0 ) {
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
if ( children [ i ] - > type = = AST_INTERFACEPORTTYPE ) {
2018-10-20 05:45:51 -05:00
std : : pair < std : : string , std : : string > res = AST : : split_modport_from_type ( children [ i ] - > str ) ;
2020-04-02 11:51:32 -05:00
wire - > attributes [ ID : : interface_type ] = res . first ;
2018-10-20 05:45:51 -05:00
if ( res . second ! = " " )
2020-04-02 11:51:32 -05:00
wire - > attributes [ ID : : interface_modport ] = res . second ;
2018-10-12 13:58:37 -05:00
break ;
}
}
}
2018-10-11 16:33:31 -05:00
wire - > upto = 0 ;
}
break ;
case AST_INTERFACEPORTTYPE :
break ;
2013-01-05 04:13:26 -06:00
2013-11-24 13:29:07 -06:00
// remember the parameter, needed for example in techmap
case AST_PARAMETER :
2020-04-16 08:51:03 -05:00
current_module - > avail_parameters ( str ) ;
if ( GetSize ( children ) > = 1 & & children [ 0 ] - > type = = AST_CONSTANT ) {
current_module - > parameter_default_values [ str ] = children [ 0 ] - > asParaConst ( ) ;
}
2020-05-04 14:12:30 -05:00
YS_FALLTHROUGH
2019-06-19 07:38:50 -05:00
case AST_LOCALPARAM :
if ( flag_pwires )
{
if ( GetSize ( children ) < 1 | | children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Parameter `%s' with non-constant value! \n " , str . c_str ( ) ) ;
2019-06-19 07:38:50 -05:00
RTLIL : : Const val = children [ 0 ] - > bitsAsConst ( ) ;
RTLIL : : Wire * wire = current_module - > addWire ( str , GetSize ( val ) ) ;
current_module - > connect ( wire , val ) ;
2021-02-05 18:38:10 -06:00
wire - > is_signed = children [ 0 ] - > is_signed ;
2019-06-19 07:38:50 -05:00
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2020-04-02 11:51:32 -05:00
wire - > attributes [ type = = AST_PARAMETER ? ID : : parameter : ID : : localparam ] = 1 ;
2019-06-19 07:38:50 -05:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2019-06-19 07:38:50 -05:00
wire - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
}
}
2013-11-24 13:29:07 -06:00
break ;
2013-01-05 04:13:26 -06:00
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE : {
2014-07-26 18:49:51 -05:00
if ( current_module - > wires_ . count ( str ) ! = 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Re-definition of signal `%s'! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
if ( ! range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Signal `%s' with non-constant width! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
2020-05-18 11:15:03 -05:00
if ( ! ( range_left + 1 > = range_right ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Signal `%s' with invalid width range %d! \n " , str . c_str ( ) , range_left - range_right + 1 ) ;
2013-01-05 04:13:26 -06:00
2014-07-26 13:12:50 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( str , range_left - range_right + 1 ) ;
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
wire - > start_offset = range_right ;
wire - > port_id = port_id ;
wire - > port_input = is_input ;
wire - > port_output = is_output ;
2014-07-28 07:25:03 -05:00
wire - > upto = range_swapped ;
2020-04-27 11:44:24 -05:00
wire - > is_signed = is_signed ;
2013-01-05 04:13:26 -06:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
wire - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
2019-05-23 03:16:41 -05:00
2020-03-12 14:57:01 -05:00
if ( is_wand ) wire - > set_bool_attribute ( ID : : wand ) ;
if ( is_wor ) wire - > set_bool_attribute ( ID : : wor ) ;
2013-01-05 04:13:26 -06:00
}
break ;
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY : {
if ( current_module - > memories . count ( str ) ! = 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Re-definition of memory `%s'! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
2014-07-28 04:08:55 -05:00
log_assert ( children . size ( ) > = 2 ) ;
log_assert ( children [ 0 ] - > type = = AST_RANGE ) ;
log_assert ( children [ 1 ] - > type = = AST_RANGE ) ;
2013-01-05 04:13:26 -06:00
if ( ! children [ 0 ] - > range_valid | | ! children [ 1 ] - > range_valid )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Memory `%s' with non-constant width or size! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
RTLIL : : Memory * memory = new RTLIL : : Memory ;
2020-03-12 14:57:01 -05:00
memory - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
memory - > name = str ;
memory - > width = children [ 0 ] - > range_left - children [ 0 ] - > range_right + 1 ;
2015-01-01 05:56:01 -06:00
if ( children [ 1 ] - > range_right < children [ 1 ] - > range_left ) {
memory - > start_offset = children [ 1 ] - > range_right ;
memory - > size = children [ 1 ] - > range_left - children [ 1 ] - > range_right + 1 ;
} else {
memory - > start_offset = children [ 1 ] - > range_left ;
memory - > size = children [ 1 ] - > range_right - children [ 1 ] - > range_left + 1 ;
}
2013-01-05 04:13:26 -06:00
current_module - > memories [ memory - > name ] = memory ;
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
memory - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
}
break ;
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
case AST_CONSTANT :
2019-02-13 05:36:47 -06:00
case AST_REALVALUE :
2013-01-05 04:13:26 -06:00
{
2013-07-09 07:31:57 -05:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
is_signed = sign_hint ;
2013-01-05 04:13:26 -06:00
2019-05-27 04:42:10 -05:00
if ( type = = AST_CONSTANT ) {
if ( is_unsized ) {
return RTLIL : : SigSpec ( bitsAsUnsizedConst ( width_hint ) ) ;
} else {
return RTLIL : : SigSpec ( bitsAsConst ( ) ) ;
}
}
2019-02-13 05:36:47 -06:00
2014-06-14 13:38:05 -05:00
RTLIL : : SigSpec sig = realAsConst ( width_hint ) ;
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " converting real value %e to binary %s. \n " , realvalue , log_signal ( sig ) ) ;
2014-06-14 13:38:05 -05:00
return sig ;
2014-06-14 00:44:19 -05:00
}
2013-01-05 04:13:26 -06:00
// simply return the corresponding RTLIL::SigSpec for an AST_IDENTIFIER node
// for identifiers with dynamic bit ranges (e.g. "foo[bar]" or "foo[bar+3:bar]") a
// shifter cell is created and the output signal of this cell is returned
case AST_IDENTIFIER :
{
2013-06-10 06:19:04 -05:00
RTLIL : : Wire * wire = NULL ;
RTLIL : : SigChunk chunk ;
2018-10-11 16:33:31 -05:00
bool is_interface = false ;
2013-06-10 06:19:04 -05:00
2014-07-28 09:09:50 -05:00
int add_undef_bits_msb = 0 ;
int add_undef_bits_lsb = 0 ;
2020-04-15 13:36:40 -05:00
log_assert ( id2ast ! = nullptr ) ;
if ( id2ast - > type = = AST_AUTOWIRE & & current_module - > wires_ . count ( str ) = = 0 ) {
2014-07-26 13:12:50 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( str ) ;
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
wire - > name = str ;
2014-02-17 07:28:52 -06:00
if ( flag_autowire )
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Identifier `%s' is implicitly declared. \n " , str . c_str ( ) ) ;
2014-02-17 07:28:52 -06:00
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 ( ) ) ;
2013-01-05 04:13:26 -06:00
}
2018-03-09 06:47:11 -06:00
else if ( id2ast - > type = = AST_PARAMETER | | id2ast - > type = = AST_LOCALPARAM | | id2ast - > type = = AST_ENUM_ITEM ) {
2013-11-07 07:08:53 -06:00
if ( id2ast - > children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Parameter %s does not evaluate to constant value! \n " , str . c_str ( ) ) ;
2013-06-10 06:56:03 -05:00
chunk = RTLIL : : Const ( id2ast - > children [ 0 ] - > bits ) ;
2013-06-10 06:19:04 -05:00
goto use_const_chunk ;
}
2020-04-15 13:36:40 -05:00
else if ( ( id2ast - > type = = AST_WIRE | | id2ast - > type = = AST_AUTOWIRE | | id2ast - > type = = AST_MEMORY ) & & current_module - > wires_ . count ( str ) ! = 0 ) {
2018-10-11 16:33:31 -05:00
RTLIL : : Wire * current_wire = current_module - > wire ( str ) ;
2020-03-12 14:57:01 -05:00
if ( current_wire - > get_bool_attribute ( ID : : is_interface ) )
2018-10-11 16:33:31 -05:00
is_interface = true ;
// Ignore
}
// If an identifier is found that is not already known, assume that it is an interface:
else if ( 1 ) { // FIXME: Check if sv_mode first?
is_interface = true ;
}
else {
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Identifier `%s' doesn't map to any signal! \n " , str . c_str ( ) ) ;
2018-10-11 16:33:31 -05:00
}
2013-01-05 04:13:26 -06:00
if ( id2ast - > type = = AST_MEMORY )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Identifier `%s' does map to an unexpanded memory! \n " , str . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
2018-10-13 13:34:44 -05:00
// If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface'
2018-10-11 16:33:31 -05:00
// This makes it possible for the hierarchy pass to see what are interface connections and then replace them
// with the individual signals:
if ( is_interface ) {
2020-04-02 11:51:32 -05:00
IdString dummy_wire_name = stringf ( " $dummywireforinterface%s " , str . c_str ( ) ) ;
RTLIL : : Wire * dummy_wire = current_module - > wire ( dummy_wire_name ) ;
if ( ! dummy_wire ) {
2018-10-11 16:33:31 -05:00
dummy_wire = current_module - > addWire ( dummy_wire_name ) ;
2020-03-12 14:57:01 -05:00
dummy_wire - > set_bool_attribute ( ID : : is_interface ) ;
2018-10-11 16:33:31 -05:00
}
2020-04-02 11:51:32 -05:00
return dummy_wire ;
2018-10-11 16:33:31 -05:00
}
2014-07-26 18:49:51 -05:00
wire = current_module - > wires_ [ str ] ;
2013-01-05 04:13:26 -06:00
chunk . wire = wire ;
chunk . width = wire - > width ;
chunk . offset = 0 ;
2013-06-10 06:19:04 -05:00
use_const_chunk :
2013-01-05 04:13:26 -06:00
if ( children . size ( ) ! = 0 ) {
2018-10-02 02:44:23 -05:00
if ( children [ 0 ] - > type ! = AST_RANGE )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Single range expected. \n " ) ;
2014-07-28 09:45:26 -05:00
int source_width = id2ast - > range_left - id2ast - > range_right + 1 ;
int source_offset = id2ast - > range_right ;
2013-01-05 04:13:26 -06:00
if ( ! children [ 0 ] - > range_valid ) {
AstNode * left_at_zero_ast = children [ 0 ] - > children [ 0 ] - > clone ( ) ;
AstNode * right_at_zero_ast = children [ 0 ] - > children . size ( ) > = 2 ? children [ 0 ] - > children [ 1 ] - > clone ( ) : left_at_zero_ast - > clone ( ) ;
2014-02-14 12:56:44 -06: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 ) ) { }
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 ( ) ) ;
2019-02-21 11:40:11 -06:00
int width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2013-01-05 04:13:26 -06:00
AstNode * fake_ast = new AstNode ( AST_NONE , clone ( ) , children [ 0 ] - > children . size ( ) > = 2 ?
children [ 0 ] - > children [ 1 ] - > clone ( ) : children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
fake_ast - > children [ 0 ] - > delete_children ( ) ;
2020-05-01 10:25:33 -05:00
int fake_ast_width = 0 ;
bool fake_ast_sign = true ;
fake_ast - > children [ 1 ] - > detectSignWidth ( fake_ast_width , fake_ast_sign ) ;
RTLIL : : SigSpec shift_val = fake_ast - > children [ 1 ] - > genRTLIL ( fake_ast_width , fake_ast_sign ) ;
2014-07-29 07:42:33 -05:00
if ( id2ast - > range_right ! = 0 ) {
2020-05-01 10:25:33 -05:00
shift_val = current_module - > Sub ( NEW_ID , shift_val , id2ast - > range_right , fake_ast_sign ) ;
2014-07-29 07:42:33 -05:00
fake_ast - > children [ 1 ] - > is_signed = true ;
}
if ( id2ast - > range_swapped ) {
2020-05-01 10:25:33 -05:00
shift_val = current_module - > Sub ( NEW_ID , RTLIL : : SigSpec ( source_width - width ) , shift_val , fake_ast_sign ) ;
2014-07-29 07:42:33 -05:00
fake_ast - > children [ 1 ] - > is_signed = true ;
}
2014-10-10 09:59:44 -05:00
if ( GetSize ( shift_val ) > = 32 )
2014-07-29 07:42:33 -05:00
fake_ast - > children [ 1 ] - > is_signed = true ;
2020-04-02 11:51:32 -05:00
RTLIL : : SigSpec sig = binop2rtlil ( fake_ast , ID ( $ shiftx ) , width , fake_ast - > children [ 0 ] - > genRTLIL ( ) , shift_val ) ;
2013-01-05 04:13:26 -06:00
delete left_at_zero_ast ;
delete right_at_zero_ast ;
delete fake_ast ;
return sig ;
} else {
2014-07-28 07:25:03 -05:00
chunk . width = children [ 0 ] - > range_left - children [ 0 ] - > range_right + 1 ;
2014-07-28 09:45:26 -05:00
chunk . offset = children [ 0 ] - > range_right - source_offset ;
2014-07-28 08:31:19 -05:00
if ( id2ast - > range_swapped )
2014-07-28 09:09:50 -05:00
chunk . offset = ( id2ast - > range_left - id2ast - > range_right + 1 ) - ( chunk . offset + chunk . width ) ;
if ( chunk . offset > = source_width | | chunk . offset + chunk . width < 0 ) {
if ( chunk . width = = 1 )
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Range select out of bounds on signal `%s': Setting result bit to undef. \n " ,
2018-11-04 03:19:32 -06:00
str . c_str ( ) ) ;
2014-07-28 09:09:50 -05:00
else
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef. \n " ,
2018-10-20 16:48:53 -05:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , chunk . width ) ;
2014-07-28 09:09:50 -05:00
chunk = RTLIL : : SigChunk ( RTLIL : : State : : Sx , chunk . width ) ;
} else {
if ( chunk . width + chunk . offset > source_width ) {
add_undef_bits_msb = ( chunk . width + chunk . offset ) - source_width ;
chunk . width - = add_undef_bits_msb ;
}
if ( chunk . offset < 0 ) {
add_undef_bits_lsb = - chunk . offset ;
chunk . width - = add_undef_bits_lsb ;
chunk . offset + = add_undef_bits_lsb ;
}
if ( add_undef_bits_lsb )
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef. \n " ,
2018-11-04 03:19:32 -06:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , add_undef_bits_lsb ) ;
2014-07-28 09:09:50 -05:00
if ( add_undef_bits_msb )
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef. \n " ,
2018-11-04 03:19:32 -06:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , add_undef_bits_msb ) ;
2014-07-28 09:09:50 -05:00
}
2013-01-05 04:13:26 -06:00
}
}
2014-07-28 09:09:50 -05:00
RTLIL : : SigSpec sig = { RTLIL : : SigSpec ( RTLIL : : State : : Sx , add_undef_bits_msb ) , chunk , RTLIL : : SigSpec ( RTLIL : : State : : Sx , add_undef_bits_lsb ) } ;
2013-01-05 04:13:26 -06:00
2014-08-14 16:02:07 -05:00
if ( genRTLIL_subst_ptr )
sig . replace ( * genRTLIL_subst_ptr ) ;
2013-01-05 04:13:26 -06:00
2013-07-09 07:31:57 -05:00
is_signed = children . size ( ) > 0 ? false : id2ast - > is_signed & & sign_hint ;
2013-01-05 04:13:26 -06:00
return sig ;
}
2013-11-07 12:19:53 -06:00
// just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly
2013-01-05 04:13:26 -06:00
case AST_TO_SIGNED :
2020-04-29 07:28:04 -05:00
case AST_TO_UNSIGNED :
case AST_SELFSZ : {
2013-11-06 20:01:28 -06:00
RTLIL : : SigSpec sig = children [ 0 ] - > genRTLIL ( ) ;
2014-07-22 13:15:14 -05:00
if ( sig . size ( ) < width_hint )
2013-11-07 11:17:10 -06:00
sig . extend_u0 ( width_hint , sign_hint ) ;
2013-07-11 12:24:59 -05:00
is_signed = sign_hint ;
2013-01-05 04:13:26 -06:00
return sig ;
}
2020-06-14 17:15:59 -05:00
// changing the size of signal can be done directly using RTLIL::SigSpec
case AST_CAST_SIZE : {
RTLIL : : SigSpec size = children [ 0 ] - > genRTLIL ( ) ;
RTLIL : : SigSpec sig = children [ 1 ] - > genRTLIL ( ) ;
if ( ! size . is_fully_const ( ) )
log_file_error ( filename , location . first_line , " Static cast with non constant expression! \n " ) ;
int width = size . as_int ( ) ;
if ( width < = 0 )
log_file_error ( filename , location . first_line , " Static cast with zero or negative size! \n " ) ;
sig . extend_u0 ( width , sign_hint ) ;
is_signed = sign_hint ;
return sig ;
}
2013-01-05 04:13:26 -06:00
// concatenation of signals can be done directly using RTLIL::SigSpec
case AST_CONCAT : {
RTLIL : : SigSpec sig ;
2014-07-22 13:39:13 -05:00
for ( auto it = children . begin ( ) ; it ! = children . end ( ) ; it + + )
sig . append ( ( * it ) - > genRTLIL ( ) ) ;
2014-07-22 13:15:14 -05:00
if ( sig . size ( ) < width_hint )
2013-11-07 11:17:10 -06:00
sig . extend_u0 ( width_hint , false ) ;
2013-01-05 04:13:26 -06:00
return sig ;
}
// replication of signals can be done directly using RTLIL::SigSpec
case AST_REPLICATE : {
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( ) ;
if ( ! left . is_fully_const ( ) )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Left operand of replicate expression is not constant! \n " ) ;
2013-01-05 04:13:26 -06:00
int count = left . as_int ( ) ;
RTLIL : : SigSpec sig ;
for ( int i = 0 ; i < count ; i + + )
sig . append ( right ) ;
2014-07-22 13:15:14 -05:00
if ( sig . size ( ) < width_hint )
2013-11-07 11:17:10 -06:00
sig . extend_u0 ( width_hint , false ) ;
2013-01-05 04:13:26 -06:00
is_signed = false ;
return sig ;
}
// generate cells for unary operations: $not, $pos, $neg
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_BIT_NOT : type_name = ID ( $ not ) ; }
if ( 0 ) { case AST_POS : type_name = ID ( $ pos ) ; }
if ( 0 ) { case AST_NEG : type_name = ID ( $ neg ) ; }
2013-01-05 04:13:26 -06:00
{
2013-07-09 07:31:57 -05:00
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
is_signed = children [ 0 ] - > is_signed ;
2014-07-22 13:15:14 -05:00
int width = arg . size ( ) ;
2013-07-09 07:31:57 -05:00
if ( width_hint > 0 ) {
2013-01-05 04:13:26 -06:00
width = width_hint ;
2014-09-03 19:07:52 -05:00
widthExtend ( this , arg , width , is_signed ) ;
2013-07-09 07:31:57 -05:00
}
2013-01-05 04:13:26 -06:00
return uniop2rtlil ( this , type_name , width , arg ) ;
}
// generate cells for binary operations: $and, $or, $xor, $xnor
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_BIT_AND : type_name = ID ( $ and ) ; }
if ( 0 ) { case AST_BIT_OR : type_name = ID ( $ or ) ; }
if ( 0 ) { case AST_BIT_XOR : type_name = ID ( $ xor ) ; }
if ( 0 ) { case AST_BIT_XNOR : type_name = ID ( $ xnor ) ; }
2013-01-05 04:13:26 -06:00
{
2013-07-09 16:41:28 -05:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
2013-07-09 07:31:57 -05:00
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2015-10-25 13:30:49 -05:00
int width = max ( left . size ( ) , right . size ( ) ) ;
2013-06-13 04:18:45 -05:00
if ( width_hint > 0 )
2013-06-10 10:10:06 -05:00
width = width_hint ;
2013-07-09 16:53:55 -05:00
is_signed = children [ 0 ] - > is_signed & & children [ 1 ] - > is_signed ;
2013-01-05 04:13:26 -06:00
return binop2rtlil ( this , type_name , width , left , right ) ;
}
// generate cells for unary operations: $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_REDUCE_AND : type_name = ID ( $ reduce_and ) ; }
if ( 0 ) { case AST_REDUCE_OR : type_name = ID ( $ reduce_or ) ; }
if ( 0 ) { case AST_REDUCE_XOR : type_name = ID ( $ reduce_xor ) ; }
if ( 0 ) { case AST_REDUCE_XNOR : type_name = ID ( $ reduce_xnor ) ; }
2013-01-05 04:13:26 -06:00
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2015-10-25 13:30:49 -05:00
RTLIL : : SigSpec sig = uniop2rtlil ( this , type_name , max ( width_hint , 1 ) , arg ) ;
2013-01-05 04:13:26 -06:00
return sig ;
}
// generate cells for unary operations: $reduce_bool
2015-08-14 03:56:05 -05:00
// (this is actually just an $reduce_or, but for clarity a different cell type is used)
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_REDUCE_BOOL : type_name = ID ( $ reduce_bool ) ; }
2013-01-05 04:13:26 -06:00
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2015-10-25 13:30:49 -05:00
RTLIL : : SigSpec sig = arg . size ( ) > 1 ? uniop2rtlil ( this , type_name , max ( width_hint , 1 ) , arg ) : arg ;
2013-01-05 04:13:26 -06:00
return sig ;
}
// generate cells for binary operations: $shl, $shr, $sshl, $sshr
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_SHIFT_LEFT : type_name = ID ( $ shl ) ; }
if ( 0 ) { case AST_SHIFT_RIGHT : type_name = ID ( $ shr ) ; }
if ( 0 ) { case AST_SHIFT_SLEFT : type_name = ID ( $ sshl ) ; }
if ( 0 ) { case AST_SHIFT_SRIGHT : type_name = ID ( $ sshr ) ; }
2020-04-27 10:04:47 -05:00
if ( 0 ) { case AST_SHIFTX : type_name = ID ( $ shiftx ) ; }
if ( 0 ) { case AST_SHIFT : type_name = ID ( $ shift ) ; }
2013-01-05 04:13:26 -06:00
{
2013-07-09 07:31:57 -05:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( ) ;
2014-07-22 13:15:14 -05:00
int width = width_hint > 0 ? width_hint : left . size ( ) ;
2013-07-09 07:31:57 -05:00
is_signed = children [ 0 ] - > is_signed ;
2013-01-05 04:13:26 -06:00
return binop2rtlil ( this , type_name , width , left , right ) ;
}
2013-11-07 15:20:00 -06:00
// generate cells for binary operations: $pow
case AST_POW :
{
int right_width ;
bool right_signed ;
children [ 1 ] - > detectSignWidth ( right_width , right_signed ) ;
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( right_width , right_signed ) ;
2014-07-22 13:15:14 -05:00
int width = width_hint > 0 ? width_hint : left . size ( ) ;
2013-11-07 15:20:00 -06:00
is_signed = children [ 0 ] - > is_signed ;
if ( ! flag_noopt & & left . is_fully_const ( ) & & left . as_int ( ) = = 2 & & ! right_signed )
2020-04-02 11:51:32 -05:00
return binop2rtlil ( this , ID ( $ shl ) , width , RTLIL : : SigSpec ( 1 , left . size ( ) ) , right ) ;
return binop2rtlil ( this , ID ( $ pow ) , width , left , right ) ;
2013-11-07 15:20:00 -06:00
}
2013-01-05 04:13:26 -06:00
// generate cells for binary operations: $lt, $le, $eq, $ne, $ge, $gt
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_LT : type_name = ID ( $ lt ) ; }
if ( 0 ) { case AST_LE : type_name = ID ( $ le ) ; }
if ( 0 ) { case AST_EQ : type_name = ID ( $ eq ) ; }
if ( 0 ) { case AST_NE : type_name = ID ( $ ne ) ; }
if ( 0 ) { case AST_EQX : type_name = ID ( $ eqx ) ; }
if ( 0 ) { case AST_NEX : type_name = ID ( $ nex ) ; }
if ( 0 ) { case AST_GE : type_name = ID ( $ ge ) ; }
if ( 0 ) { case AST_GT : type_name = ID ( $ gt ) ; }
2013-01-05 04:13:26 -06:00
{
2015-10-25 13:30:49 -05:00
int width = max ( width_hint , 1 ) ;
2013-07-09 07:31:57 -05:00
width_hint = - 1 , sign_hint = true ;
children [ 0 ] - > detectSignWidthWorker ( width_hint , sign_hint ) ;
children [ 1 ] - > detectSignWidthWorker ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-11-06 13:50:53 -06:00
RTLIL : : SigSpec sig = binop2rtlil ( this , type_name , width , left , right ) ;
2013-01-05 04:13:26 -06:00
return sig ;
}
2013-11-07 15:20:00 -06:00
// generate cells for binary operations: $add, $sub, $mul, $div, $mod
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_ADD : type_name = ID ( $ add ) ; }
if ( 0 ) { case AST_SUB : type_name = ID ( $ sub ) ; }
if ( 0 ) { case AST_MUL : type_name = ID ( $ mul ) ; }
if ( 0 ) { case AST_DIV : type_name = ID ( $ div ) ; }
if ( 0 ) { case AST_MOD : type_name = ID ( $ mod ) ; }
2013-01-05 04:13:26 -06:00
{
2013-07-09 07:31:57 -05:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-11-07 15:20:00 -06:00
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-11-08 04:40:36 -06:00
#if 0
2015-10-25 13:30:49 -05:00
int width = max ( left . size ( ) , right . size ( ) ) ;
2013-01-05 04:13:26 -06:00
if ( width > width_hint & & width_hint > 0 )
width = width_hint ;
if ( width < width_hint ) {
2013-08-09 10:09:24 -05:00
if ( type = = AST_ADD | | type = = AST_SUB | | type = = AST_DIV )
2013-01-05 04:13:26 -06:00
width + + ;
2013-07-09 16:41:28 -05:00
if ( type = = AST_SUB & & ( ! children [ 0 ] - > is_signed | | ! children [ 1 ] - > is_signed ) )
2013-01-05 04:13:26 -06:00
width = width_hint ;
if ( type = = AST_MUL )
2015-10-25 13:30:49 -05:00
width = min ( left . size ( ) + right . size ( ) , width_hint ) ;
2013-01-05 04:13:26 -06:00
}
2013-11-08 04:40:36 -06:00
# else
2015-10-25 13:30:49 -05:00
int width = max ( max ( left . size ( ) , right . size ( ) ) , width_hint ) ;
2013-11-08 04:40:36 -06:00
# endif
2013-07-09 07:31:57 -05:00
is_signed = children [ 0 ] - > is_signed & & children [ 1 ] - > is_signed ;
2013-01-05 04:13:26 -06:00
return binop2rtlil ( this , type_name , width , left , right ) ;
}
// generate cells for binary operations: $logic_and, $logic_or
2020-04-02 11:51:32 -05:00
if ( 0 ) { case AST_LOGIC_AND : type_name = ID ( $ logic_and ) ; }
if ( 0 ) { case AST_LOGIC_OR : type_name = ID ( $ logic_or ) ; }
2013-01-05 04:13:26 -06:00
{
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( ) ;
2015-10-25 13:30:49 -05:00
return binop2rtlil ( this , type_name , max ( width_hint , 1 ) , left , right ) ;
2013-01-05 04:13:26 -06:00
}
// generate cells for unary operations: $logic_not
case AST_LOGIC_NOT :
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 11:51:32 -05:00
return uniop2rtlil ( this , ID ( $ logic_not ) , max ( width_hint , 1 ) , arg ) ;
2013-01-05 04:13:26 -06:00
}
// generate multiplexer for ternary operator (aka ?:-operator)
case AST_TERNARY :
{
2013-07-12 06:13:04 -05:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
2020-04-14 14:05:07 -05:00
is_signed = sign_hint ;
2013-07-12 06:13:04 -05:00
2013-01-05 04:13:26 -06:00
RTLIL : : SigSpec cond = children [ 0 ] - > genRTLIL ( ) ;
2020-02-27 18:55:55 -06:00
RTLIL : : SigSpec sig ;
2020-04-14 14:05:07 -05:00
if ( cond . is_fully_def ( ) )
{
2020-02-27 18:55:55 -06:00
if ( cond . as_bool ( ) ) {
sig = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2020-04-14 14:05:07 -05:00
log_assert ( is_signed = = children [ 1 ] - > is_signed ) ;
} else {
2020-02-27 18:55:55 -06:00
sig = children [ 2 ] - > genRTLIL ( width_hint , sign_hint ) ;
2020-04-14 14:05:07 -05:00
log_assert ( is_signed = = children [ 2 ] - > is_signed ) ;
2020-02-27 18:55:55 -06:00
}
2020-04-14 14:05:07 -05:00
widthExtend ( this , sig , sig . size ( ) , is_signed ) ;
2020-02-27 18:55:55 -06:00
}
2020-04-14 14:05:07 -05:00
else
{
2020-02-27 18:55:55 -06:00
RTLIL : : SigSpec val1 = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec val2 = children [ 2 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-01-05 04:13:26 -06:00
2020-02-27 18:55:55 -06:00
if ( cond . size ( ) > 1 )
2020-04-02 11:51:32 -05:00
cond = uniop2rtlil ( this , ID ( $ reduce_bool ) , 1 , cond , false ) ;
2013-01-05 04:13:26 -06:00
2020-02-27 18:55:55 -06:00
int width = max ( val1 . size ( ) , val2 . size ( ) ) ;
2020-04-14 14:05:07 -05:00
log_assert ( is_signed = = children [ 1 ] - > is_signed ) ;
log_assert ( is_signed = = children [ 2 ] - > is_signed ) ;
2020-02-27 18:55:55 -06:00
widthExtend ( this , val1 , width , is_signed ) ;
widthExtend ( this , val2 , width , is_signed ) ;
2013-01-05 04:13:26 -06:00
2020-02-27 18:55:55 -06:00
sig = mux2rtlil ( this , cond , val1 , val2 ) ;
}
2013-11-07 11:17:10 -06:00
2014-07-22 13:15:14 -05:00
if ( sig . size ( ) < width_hint )
2013-11-07 11:17:10 -06:00
sig . extend_u0 ( width_hint , sign_hint ) ;
return sig ;
2013-01-05 04:13:26 -06:00
}
// generate $memrd cells for memory read ports
case AST_MEMRD :
{
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < " $memrd$ " < < str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ memrd ) ) ;
2020-04-24 03:08:25 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
2014-08-02 06:11:01 -05:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _DATA " , current_module - > memories [ str ] - > width ) ;
2020-04-24 03:08:25 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
2015-02-14 07:21:15 -06:00
int mem_width , mem_size , addr_bits ;
2016-11-01 17:17:43 -05:00
is_signed = id2ast - > is_signed ;
2021-02-05 18:38:10 -06:00
wire - > is_signed = is_signed ;
2015-02-14 07:21:15 -06:00
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
2013-01-05 04:13:26 -06:00
2016-08-19 11:38:25 -05:00
RTLIL : : SigSpec addr_sig = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CLK , RTLIL : : SigSpec ( RTLIL : : State : : Sx , 1 ) ) ;
cell - > setPort ( ID : : EN , RTLIL : : SigSpec ( RTLIL : : State : : Sx , 1 ) ) ;
cell - > setPort ( ID : : ADDR , addr_sig ) ;
cell - > setPort ( ID : : DATA , RTLIL : : SigSpec ( wire ) ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : MEMID ] = RTLIL : : Const ( str ) ;
cell - > parameters [ ID : : ABITS ] = RTLIL : : Const ( GetSize ( addr_sig ) ) ;
cell - > parameters [ ID : : WIDTH ] = RTLIL : : Const ( wire - > width ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : CLK_ENABLE ] = RTLIL : : Const ( 0 ) ;
cell - > parameters [ ID : : CLK_POLARITY ] = RTLIL : : Const ( 0 ) ;
cell - > parameters [ ID : : TRANSPARENT ] = RTLIL : : Const ( 0 ) ;
2013-01-05 04:13:26 -06:00
2018-06-28 09:57:03 -05:00
if ( ! sign_hint )
is_signed = false ;
2013-01-05 04:13:26 -06:00
return RTLIL : : SigSpec ( wire ) ;
}
// generate $memwr cells for memory write ports
case AST_MEMWR :
2015-02-14 03:49:30 -06:00
case AST_MEMINIT :
2013-01-05 04:13:26 -06:00
{
std : : stringstream sstr ;
2020-02-23 01:19:52 -06:00
sstr < < ( type = = AST_MEMWR ? " $memwr$ " : " $meminit$ " ) < < str < < " $ " < < filename < < " : " < < location . first_line < < " $ " < < ( autoidx + + ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , type = = AST_MEMWR ? ID ( $ memwr ) : ID ( $ meminit ) ) ;
2020-03-12 14:57:01 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2013-01-05 04:13:26 -06:00
2015-02-14 07:21:15 -06:00
int mem_width , mem_size , addr_bits ;
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
2013-01-05 04:13:26 -06:00
2015-07-31 03:40:09 -05:00
int num_words = 1 ;
if ( type = = AST_MEMINIT ) {
if ( children [ 2 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Memory init with non-constant word count! \n " ) ;
2016-02-13 10:31:24 -06:00
num_words = int ( children [ 2 ] - > asInt ( false ) ) ;
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : WORDS ] = RTLIL : : Const ( num_words ) ;
2015-07-31 03:40:09 -05:00
}
2016-08-19 11:38:25 -05:00
SigSpec addr_sig = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : ADDR , addr_sig ) ;
cell - > setPort ( ID : : DATA , children [ 1 ] - > genWidthRTLIL ( current_module - > memories [ str ] - > width * num_words ) ) ;
2013-01-05 04:13:26 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : MEMID ] = RTLIL : : Const ( str ) ;
cell - > parameters [ ID : : ABITS ] = RTLIL : : Const ( GetSize ( addr_sig ) ) ;
cell - > parameters [ ID : : WIDTH ] = RTLIL : : Const ( current_module - > memories [ str ] - > width ) ;
2013-01-05 04:13:26 -06:00
2015-02-14 03:49:30 -06:00
if ( type = = AST_MEMWR ) {
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : CLK , RTLIL : : SigSpec ( RTLIL : : State : : Sx , 1 ) ) ;
cell - > setPort ( ID : : EN , children [ 2 ] - > genRTLIL ( ) ) ;
cell - > parameters [ ID : : CLK_ENABLE ] = RTLIL : : Const ( 0 ) ;
cell - > parameters [ ID : : CLK_POLARITY ] = RTLIL : : Const ( 0 ) ;
2015-02-14 03:49:30 -06:00
}
2014-01-02 17:22:17 -06:00
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : PRIORITY ] = RTLIL : : Const ( autoidx - 1 ) ;
2013-01-05 04:13:26 -06:00
}
break ;
2014-01-19 07:03:40 -06:00
// generate $assert cells
case AST_ASSERT :
2015-02-26 11:47:39 -06:00
case AST_ASSUME :
2017-02-25 03:36:39 -06:00
case AST_LIVE :
case AST_FAIR :
2017-02-04 07:14:26 -06:00
case AST_COVER :
2014-01-19 07:03:40 -06:00
{
2020-04-02 11:51:32 -05:00
IdString celltype ;
if ( type = = AST_ASSERT ) celltype = ID ( $ assert ) ;
if ( type = = AST_ASSUME ) celltype = ID ( $ assume ) ;
if ( type = = AST_LIVE ) celltype = ID ( $ live ) ;
if ( type = = AST_FAIR ) celltype = ID ( $ fair ) ;
if ( type = = AST_COVER ) celltype = ID ( $ cover ) ;
2016-07-13 09:56:17 -05:00
2014-01-19 07:03:40 -06:00
log_assert ( children . size ( ) = = 2 ) ;
RTLIL : : SigSpec check = children [ 0 ] - > genRTLIL ( ) ;
2015-02-26 11:47:39 -06:00
if ( GetSize ( check ) ! = 1 )
check = current_module - > ReduceBool ( NEW_ID , check ) ;
2014-01-19 07:03:40 -06:00
RTLIL : : SigSpec en = children [ 1 ] - > genRTLIL ( ) ;
2015-02-26 11:47:39 -06:00
if ( GetSize ( en ) ! = 1 )
en = current_module - > ReduceBool ( NEW_ID , en ) ;
2014-01-19 07:03:40 -06:00
2019-03-07 13:17:32 -06:00
IdString cellname ;
2020-04-02 11:51:32 -05:00
if ( str . empty ( ) )
cellname = stringf ( " %s$%s:%d$%d " , celltype . c_str ( ) , filename . c_str ( ) , location . first_line , autoidx + + ) ;
else
2019-03-07 13:17:32 -06:00
cellname = str ;
2014-01-19 07:03:40 -06:00
2019-03-07 13:17:32 -06:00
RTLIL : : Cell * cell = current_module - > addCell ( cellname , celltype ) ;
2020-03-12 14:57:01 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2014-01-19 07:03:40 -06:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `%s' with non-constant value! \n " , attr . first . c_str ( ) ) ;
2014-01-19 07:03:40 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
}
2020-03-12 14:57:01 -05:00
cell - > setPort ( ID : : A , check ) ;
2020-04-02 11:51:32 -05:00
cell - > setPort ( ID : : EN , en ) ;
2014-01-19 07:03:40 -06:00
}
break ;
2013-01-05 04:13:26 -06:00
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN :
{
2015-02-07 17:48:23 -06:00
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genWidthRTLIL ( left . size ( ) ) ;
2019-05-27 11:00:22 -05:00
if ( left . has_const ( ) ) {
RTLIL : : SigSpec new_left , new_right ;
for ( int i = 0 ; i < GetSize ( left ) ; i + + )
if ( left [ i ] . wire ) {
2019-05-23 06:42:30 -05:00
new_left . append ( left [ i ] ) ;
2019-05-27 11:00:22 -05:00
new_right . append ( right [ i ] ) ;
2019-05-23 06:42:30 -05:00
}
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Ignoring assignment to constant bits: \n "
2019-05-23 06:42:30 -05:00
" old assignment: %s = %s \n new assignment: %s = %s. \n " ,
log_signal ( left ) , log_signal ( right ) ,
log_signal ( new_left ) , log_signal ( new_right ) ) ;
2019-05-27 11:00:22 -05:00
left = new_left ;
right = new_right ;
}
current_module - > connect ( RTLIL : : SigSig ( left , right ) ) ;
2013-01-05 04:13:26 -06:00
}
break ;
// create an RTLIL::Cell for an AST_CELL
case AST_CELL :
{
int port_counter = 0 , para_counter = 0 ;
2014-07-25 08:05:18 -05:00
if ( current_module - > count_id ( str ) ! = 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Re-definition of cell `%s'! \n " , str . c_str ( ) ) ;
2014-07-25 08:05:18 -05:00
RTLIL : : Cell * cell = current_module - > addCell ( str , " " ) ;
2020-03-12 14:57:01 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2018-10-13 13:34:44 -05:00
// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
2020-04-02 11:51:32 -05:00
cell - > set_bool_attribute ( ID : : module_not_derived ) ;
2014-07-25 08:05:18 -05:00
2013-01-05 04:13:26 -06:00
for ( auto it = children . begin ( ) ; it ! = children . end ( ) ; it + + ) {
AstNode * child = * it ;
if ( child - > type = = AST_CELLTYPE ) {
cell - > type = child - > str ;
2019-08-07 14:20:08 -05:00
if ( flag_icells & & cell - > type . begins_with ( " \\ $ " ) )
2014-01-28 17:59:28 -06:00
cell - > type = cell - > type . substr ( 1 ) ;
2013-01-05 04:13:26 -06:00
continue ;
}
if ( child - > type = = AST_PARASET ) {
2019-05-04 01:46:24 -05:00
int extra_const_flags = 0 ;
2015-02-18 16:35:23 -06:00
IdString paraname = child - > str . empty ( ) ? stringf ( " $%d " , + + para_counter ) : child - > str ;
if ( child - > children [ 0 ] - > type = = AST_REALVALUE ) {
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " Replacing floating point parameter %s.%s = %f with string. \n " ,
2018-11-04 03:19:32 -06:00
log_id ( cell ) , log_id ( paraname ) , child - > children [ 0 ] - > realvalue ) ;
2019-05-04 01:46:24 -05:00
extra_const_flags = RTLIL : : CONST_FLAG_REAL ;
2015-02-18 16:35:23 -06:00
auto strnode = AstNode : : mkconst_str ( stringf ( " %f " , child - > children [ 0 ] - > realvalue ) ) ;
strnode - > cloneInto ( child - > children [ 0 ] ) ;
delete strnode ;
2013-01-05 04:13:26 -06:00
}
2015-02-18 16:35:23 -06:00
if ( child - > children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Parameter %s.%s with non-constant value! \n " ,
2018-11-04 03:19:32 -06:00
log_id ( cell ) , log_id ( paraname ) ) ;
2015-02-18 16:35:23 -06:00
cell - > parameters [ paraname ] = child - > children [ 0 ] - > asParaConst ( ) ;
2019-05-04 01:46:24 -05:00
cell - > parameters [ paraname ] . flags | = extra_const_flags ;
2013-01-05 04:13:26 -06:00
continue ;
}
if ( child - > type = = AST_ARGUMENT ) {
RTLIL : : SigSpec sig ;
2020-12-18 13:59:08 -06:00
if ( child - > children . size ( ) > 0 ) {
AstNode * arg = child - > children [ 0 ] ;
int local_width_hint = - 1 ;
bool local_sign_hint = false ;
// don't inadvertently attempt to detect the width of interfaces
if ( arg - > type ! = AST_IDENTIFIER | | ! arg - > id2ast | | arg - > id2ast - > type ! = AST_CELL )
arg - > detectSignWidth ( local_width_hint , local_sign_hint ) ;
sig = arg - > genRTLIL ( local_width_hint , local_sign_hint ) ;
log_assert ( local_sign_hint = = arg - > is_signed ) ;
if ( sig . is_wire ( ) ) {
// if the resulting SigSpec is a wire, its
// signedness should match that of the AstNode
log_assert ( arg - > is_signed = = sig . as_wire ( ) - > is_signed ) ;
} else if ( arg - > is_signed ) {
// non-trivial signed nodes are indirected through
// signed wires to enable sign extension
RTLIL : : IdString wire_name = NEW_ID ;
2021-02-05 18:38:10 -06:00
RTLIL : : Wire * wire = current_module - > addWire ( wire_name , GetSize ( sig ) ) ;
2020-12-18 13:59:08 -06:00
wire - > is_signed = true ;
current_module - > connect ( wire , sig ) ;
sig = wire ;
}
}
2013-01-05 04:13:26 -06:00
if ( child - > str . size ( ) = = 0 ) {
char buf [ 100 ] ;
snprintf ( buf , 100 , " $%d " , + + port_counter ) ;
2019-05-27 11:00:22 -05:00
cell - > setPort ( buf , sig ) ;
2013-01-05 04:13:26 -06:00
} else {
2019-05-27 11:00:22 -05:00
cell - > setPort ( child - > str , sig ) ;
2013-01-05 04:13:26 -06:00
}
continue ;
}
2014-07-28 04:08:55 -05:00
log_abort ( ) ;
2013-01-05 04:13:26 -06:00
}
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `%s' with non-constant value. \n " , attr . first . c_str ( ) ) ;
2013-12-04 07:14:05 -06:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 04:13:26 -06:00
}
2020-04-02 11:51:32 -05:00
if ( cell - > type = = ID ( $ specify2 ) ) {
int src_width = GetSize ( cell - > getPort ( ID : : SRC ) ) ;
int dst_width = GetSize ( cell - > getPort ( ID : : DST ) ) ;
bool full = cell - > getParam ( ID : : FULL ) . as_bool ( ) ;
2019-04-21 19:33:12 -05:00
if ( ! full & & src_width ! = dst_width )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Parallel specify SRC width does not match DST width. \n " ) ;
2020-04-02 11:51:32 -05:00
cell - > setParam ( ID : : SRC_WIDTH , Const ( src_width ) ) ;
cell - > setParam ( ID : : DST_WIDTH , Const ( dst_width ) ) ;
2019-04-23 08:46:40 -05:00
}
2020-04-02 11:51:32 -05:00
else if ( cell - > type = = ID ( $ specify3 ) ) {
int dat_width = GetSize ( cell - > getPort ( ID : : DAT ) ) ;
int dst_width = GetSize ( cell - > getPort ( ID : : DST ) ) ;
2020-02-12 14:16:01 -06:00
if ( dat_width ! = dst_width )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Specify DAT width does not match DST width. \n " ) ;
2020-04-02 11:51:32 -05:00
int src_width = GetSize ( cell - > getPort ( ID : : SRC ) ) ;
cell - > setParam ( ID : : SRC_WIDTH , Const ( src_width ) ) ;
cell - > setParam ( ID : : DST_WIDTH , Const ( dst_width ) ) ;
2020-02-12 14:16:01 -06:00
}
2020-04-02 11:51:32 -05:00
else if ( cell - > type = = ID ( $ specrule ) ) {
int src_width = GetSize ( cell - > getPort ( ID : : SRC ) ) ;
int dst_width = GetSize ( cell - > getPort ( ID : : DST ) ) ;
cell - > setParam ( ID : : SRC_WIDTH , Const ( src_width ) ) ;
cell - > setParam ( ID : : DST_WIDTH , Const ( dst_width ) ) ;
2019-04-21 19:33:12 -05:00
}
2013-01-05 04:13:26 -06:00
}
break ;
// use ProcessGenerator for always blocks
2013-03-31 04:51:12 -05:00
case AST_ALWAYS : {
2013-01-05 04:13:26 -06:00
AstNode * always = this - > clone ( ) ;
ProcessGenerator generator ( always ) ;
2013-03-31 04:51:12 -05:00
ignoreThisSignalsInInitial . append ( generator . outputSignals ) ;
delete always ;
} break ;
case AST_INITIAL : {
AstNode * always = this - > clone ( ) ;
ProcessGenerator generator ( always , ignoreThisSignalsInInitial ) ;
2013-01-05 04:13:26 -06:00
delete always ;
} break ;
2019-06-07 05:41:09 -05:00
case AST_TECALL : {
int sz = children . size ( ) ;
if ( str = = " $info " ) {
if ( sz > 0 )
2020-02-23 01:19:52 -06:00
log_file_info ( filename , location . first_line , " %s. \n " , children [ 0 ] - > str . c_str ( ) ) ;
2019-06-07 05:41:09 -05:00
else
2020-02-23 01:19:52 -06:00
log_file_info ( filename , location . first_line , " \n " ) ;
2019-06-07 05:41:09 -05:00
} else if ( str = = " $warning " ) {
if ( sz > 0 )
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " %s. \n " , children [ 0 ] - > str . c_str ( ) ) ;
2019-06-07 05:41:09 -05:00
else
2020-02-23 01:19:52 -06:00
log_file_warning ( filename , location . first_line , " \n " ) ;
2019-06-07 05:41:09 -05:00
} else if ( str = = " $error " ) {
if ( sz > 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " %s. \n " , children [ 0 ] - > str . c_str ( ) ) ;
2019-06-07 05:41:09 -05:00
else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " \n " ) ;
2019-06-07 05:41:09 -05:00
} else if ( str = = " $fatal " ) {
// TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()
// if no parameter is given, default value is 1
// dollar_finish(sz ? children[0] : 1);
// perhaps create & use log_file_fatal()
if ( sz > 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " FATAL: %s. \n " , children [ 0 ] - > str . c_str ( ) ) ;
2019-06-07 05:41:09 -05:00
else
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " FATAL. \n " ) ;
2019-06-07 05:41:09 -05:00
} else {
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Unknown elabortoon system task '%s'. \n " , str . c_str ( ) ) ;
2019-06-07 05:41:09 -05:00
}
} break ;
2016-07-27 08:41:22 -05:00
case AST_FCALL : {
2018-02-23 06:14:47 -06:00
if ( str = = " \\ $anyconst " | | str = = " \\ $anyseq " | | str = = " \\ $allconst " | | str = = " \\ $allseq " )
2016-07-27 08:41:22 -05:00
{
2016-08-30 12:09:56 -05:00
string myid = stringf ( " %s$%d " , str . c_str ( ) + 1 , autoidx + + ) ;
2016-07-27 08:41:22 -05:00
int width = width_hint ;
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 or 0. \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) , GetSize ( children ) ) ;
2016-07-27 08:41:22 -05:00
if ( GetSize ( children ) = = 1 ) {
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " System function %s called with non-const argument! \n " ,
2018-11-04 03:19:32 -06:00
RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
2016-07-27 08:41:22 -05:00
width = children [ 0 ] - > asInt ( true ) ;
}
if ( width < = 0 )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Failed to detect width of %s! \n " , RTLIL : : unescape_id ( str ) . c_str ( ) ) ;
2016-07-27 08:41:22 -05:00
Cell * cell = current_module - > addCell ( myid , str . substr ( 1 ) ) ;
2020-03-12 14:57:01 -05:00
cell - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
2020-04-02 11:51:32 -05:00
cell - > parameters [ ID : : WIDTH ] = width ;
2016-07-27 08:41:22 -05:00
2020-04-02 11:51:32 -05:00
if ( attributes . count ( ID : : reg ) ) {
auto & attr = attributes . at ( ID : : reg ) ;
2017-06-07 05:30:24 -05:00
if ( attr - > type ! = AST_CONSTANT )
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Attribute `reg' with non-constant value! \n " ) ;
2020-04-02 11:51:32 -05:00
cell - > attributes [ ID : : reg ] = attr - > asAttrConst ( ) ;
2017-06-07 05:30:24 -05:00
}
2016-07-27 08:41:22 -05:00
Wire * wire = current_module - > addWire ( myid + " _wire " , width ) ;
2020-03-12 14:57:01 -05:00
wire - > attributes [ ID : : src ] = stringf ( " %s:%d.%d-%d.%d " , filename . c_str ( ) , location . first_line , location . first_column , location . last_line , location . last_column ) ;
cell - > setPort ( ID : : Y , wire ) ;
2016-07-27 08:41:22 -05:00
is_signed = sign_hint ;
return SigSpec ( wire ) ;
}
2020-05-04 14:12:30 -05:00
}
YS_FALLTHROUGH
2016-07-27 08:41:22 -05:00
2013-01-05 04:13:26 -06:00
// everything should have been handled above -> print error if not.
default :
for ( auto f : log_files )
2019-02-21 10:36:51 -06:00
current_ast_mod - > dumpAst ( f , " verilog-ast> " ) ;
2013-01-05 04:13:26 -06:00
type_name = type2str ( type ) ;
2020-02-23 01:19:52 -06:00
log_file_error ( filename , location . first_line , " Don't know how to generate RTLIL code for %s node! \n " , type_name . c_str ( ) ) ;
2013-01-05 04:13:26 -06:00
}
return RTLIL : : SigSpec ( ) ;
}
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
2015-08-14 03:56:05 -05:00
// signals must be substituted before being used as input values (used by ProcessGenerator)
2013-01-05 04:13:26 -06:00
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
2014-12-28 12:24:24 -06:00
RTLIL : : SigSpec AstNode : : genWidthRTLIL ( int width , const dict < RTLIL : : SigBit , RTLIL : : SigBit > * new_subst_ptr )
2013-01-05 04:13:26 -06:00
{
2014-12-28 12:24:24 -06:00
const dict < RTLIL : : SigBit , RTLIL : : SigBit > * backup_subst_ptr = genRTLIL_subst_ptr ;
2013-01-05 04:13:26 -06:00
2014-08-14 16:02:07 -05:00
if ( new_subst_ptr )
genRTLIL_subst_ptr = new_subst_ptr ;
2013-01-05 04:13:26 -06:00
2013-07-09 07:31:57 -05:00
bool sign_hint = true ;
int width_hint = width ;
detectSignWidthWorker ( width_hint , sign_hint ) ;
RTLIL : : SigSpec sig = genRTLIL ( width_hint , sign_hint ) ;
2013-01-05 04:13:26 -06:00
2014-08-14 16:02:07 -05:00
genRTLIL_subst_ptr = backup_subst_ptr ;
2013-01-05 04:13:26 -06:00
if ( width > = 0 )
2013-11-07 12:19:53 -06:00
sig . extend_u0 ( width , is_signed ) ;
2013-01-05 04:13:26 -06:00
return sig ;
}
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_END