2013-01-05 11:13:26 +01:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-08 00:39:36 +02:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2015-07-02 11:14:30 +02:00
*
2013-01-05 11:13:26 +01: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 11:14:30 +02:00
*
2013-01-05 11:13:26 +01: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-17 00:57:24 +02:00
# include "kernel/utils.h"
2020-04-20 17:06:53 +02:00
# include "kernel/binding.h"
2013-02-27 09:32:19 +01:00
# include "libs/sha1/sha1.h"
2013-01-05 11:13:26 +01:00
# include "ast.h"
2020-04-20 17:06:53 +02:00
# include "ast_binding.h"
2013-01-05 11:13:26 +01:00
# include <sstream>
# include <stdarg.h>
2013-07-09 14:31:57 +02:00
# include <algorithm>
2013-01-05 11:13:26 +01:00
2014-07-31 13:19:47 +02:00
YOSYS_NAMESPACE_BEGIN
2013-01-05 11:13:26 +01:00
using namespace AST ;
using namespace AST_INTERNAL ;
// helper function for creating RTLIL code for unary operations
2020-04-02 18:51:32 +02:00
static RTLIL : : SigSpec uniop2rtlil ( AstNode * that , IdString type , int result_width , const RTLIL : : SigSpec & arg , bool gen_attributes = true )
2013-01-05 11:13:26 +01:00
{
2025-08-20 00:45:26 +02:00
IdString name = stringf ( " %s$%s:%d$%d " , type , RTLIL : : encode_filename ( * that - > location . begin . filename ) , that - > location . begin . line , autoidx + + ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : Cell * cell = current_module - > addCell ( name , type ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , that ) ;
2013-01-05 11:13:26 +01:00
2014-08-02 13:11:01 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , result_width ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , that ) ;
2021-02-06 01:38:10 +01:00
wire - > is_signed = that - > is_signed ;
2013-01-05 11:13:26 +01:00
if ( gen_attributes )
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
that - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
2020-04-02 18:51:32 +02: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 20:57:01 +01:00
cell - > setPort ( ID : : A , arg ) ;
2013-01-05 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : Y_WIDTH ] = result_width ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 20:39:13 +02:00
return wire ;
2013-01-05 11:13:26 +01:00
}
2013-11-06 20:50:53 +01:00
// helper function for extending bit width (preferred over SigSpec::extend() because of correct undef propagation in ConstEval)
2014-09-04 02:07:52 +02:00
static void widthExtend ( AstNode * that , RTLIL : : SigSpec & sig , int width , bool is_signed )
2013-11-06 20:50:53 +01:00
{
2014-07-22 20:15:14 +02:00
if ( width < = sig . size ( ) ) {
2014-12-24 09:51:17 +01:00
sig . extend_u0 ( width , is_signed ) ;
2013-11-06 20:50:53 +01:00
return ;
}
2025-08-20 00:45:26 +02:00
IdString name = stringf ( " $extend$%s:%d$%d " , RTLIL : : encode_filename ( * that - > location . begin . filename ) , that - > location . begin . line , autoidx + + ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : Cell * cell = current_module - > addCell ( name , ID ( $ pos ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , that ) ;
2013-11-06 20:50:53 +01:00
2014-08-02 13:11:01 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , width ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , that ) ;
2021-02-06 01:38:10 +01:00
wire - > is_signed = that - > is_signed ;
2013-11-06 20:50:53 +01:00
2025-06-16 22:55:24 +02:00
if ( that ! = nullptr )
2013-11-06 20:50:53 +01:00
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
that - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-11-06 20:50:53 +01:00
}
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : A_SIGNED ] = RTLIL : : Const ( is_signed ) ;
cell - > parameters [ ID : : A_WIDTH ] = RTLIL : : Const ( sig . size ( ) ) ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : A , sig ) ;
2013-11-06 20:50:53 +01:00
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : Y_WIDTH ] = width ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 20:39:13 +02:00
sig = wire ;
2013-11-06 20:50:53 +01:00
}
2013-01-05 11:13:26 +01:00
// helper function for creating RTLIL code for binary operations
2020-04-02 18:51:32 +02:00
static RTLIL : : SigSpec binop2rtlil ( AstNode * that , IdString type , int result_width , const RTLIL : : SigSpec & left , const RTLIL : : SigSpec & right )
2013-01-05 11:13:26 +01:00
{
2025-08-20 00:45:26 +02:00
IdString name = stringf ( " %s$%s:%d$%d " , type , RTLIL : : encode_filename ( * that - > location . begin . filename ) , that - > location . begin . line , autoidx + + ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : Cell * cell = current_module - > addCell ( name , type ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , that ) ;
2013-01-05 11:13:26 +01:00
2014-08-02 13:11:01 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , result_width ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , that ) ;
2020-12-18 20:59:08 +01:00
wire - > is_signed = that - > is_signed ;
2013-01-05 11:13:26 +01:00
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
that - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : A_WIDTH ] = RTLIL : : Const ( left . size ( ) ) ;
cell - > parameters [ ID : : B_WIDTH ] = RTLIL : : Const ( right . size ( ) ) ;
2013-01-05 11:13:26 +01:00
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : A , left ) ;
cell - > setPort ( ID : : B , right ) ;
2013-01-05 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : Y_WIDTH ] = result_width ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : Y , wire ) ;
2014-07-22 20:39:13 +02:00
return wire ;
2013-01-05 11:13:26 +01: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 11:08:55 +02:00
log_assert ( cond . size ( ) = = 1 ) ;
2013-01-05 11:13:26 +01:00
std : : stringstream sstr ;
2025-06-18 22:50:46 +02:00
sstr < < " $ternary$ " < < RTLIL : : encode_filename ( * that - > location . begin . filename ) < < " : " < < that - > location . begin . line < < " $ " < < ( autoidx + + ) ;
2013-01-05 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ mux ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , that ) ;
2013-01-05 11:13:26 +01:00
2014-08-02 13:11:01 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _Y " , left . size ( ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , that ) ;
2020-12-23 01:38:51 +01:00
wire - > is_signed = that - > is_signed ;
2013-01-05 11:13:26 +01:00
for ( auto & attr : that - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
that - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : WIDTH ] = RTLIL : : Const ( left . size ( ) ) ;
2013-01-05 11:13:26 +01:00
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : A , right ) ;
cell - > setPort ( ID : : B , left ) ;
cell - > setPort ( ID : : S , cond ) ;
cell - > setPort ( ID : : Y , wire ) ;
2013-01-05 11:13:26 +01:00
2014-07-22 20:39:13 +02:00
return wire ;
2013-01-05 11:13:26 +01:00
}
2024-01-11 10:39:28 +01:00
static void check_unique_id ( RTLIL : : Module * module , RTLIL : : IdString id ,
const AstNode * node , const char * to_add_kind )
{
auto already_exists = [ & ] ( const RTLIL : : AttrObject * existing , const char * existing_kind ) {
std : : string src = existing - > get_string_attribute ( ID : : src ) ;
std : : string location_str = " earlier " ;
if ( ! src . empty ( ) )
location_str = " at " + src ;
node - > input_error ( " Cannot add %s `%s' because a %s with the same name was already created %s! \n " ,
to_add_kind , id . c_str ( ) , existing_kind , location_str . c_str ( ) ) ;
} ;
if ( const RTLIL : : Wire * wire = module - > wire ( id ) )
already_exists ( wire , " signal " ) ;
if ( const RTLIL : : Cell * cell = module - > cell ( id ) )
already_exists ( cell , " cell " ) ;
if ( module - > processes . count ( id ) )
already_exists ( module - > processes . at ( id ) , " process " ) ;
if ( module - > memories . count ( id ) )
already_exists ( module - > memories . at ( id ) , " memory " ) ;
}
2020-04-15 20:36:40 +02: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 ) ) {
2025-06-18 22:50:46 +02:00
auto wire = std : : make_unique < AstNode > ( node - > location , AST_WIRE ) ;
2025-06-16 22:55:24 +02:00
for ( auto & c : node - > id2ast - > children )
2020-04-15 20:36:40 +02:00
wire - > children . push_back ( c - > clone ( ) ) ;
2023-04-05 11:00:07 +02:00
wire - > fixup_hierarchy_flags ( ) ;
2025-08-20 00:45:26 +02:00
wire - > str = stringf ( " $lookahead%s$%d " , node - > str , autoidx + + ) ;
2025-06-18 22:50:46 +02:00
wire - > set_attribute ( ID : : nosync , AstNode : : mkconst_int ( node - > location , 1 , false ) ) ;
2020-04-15 20:36:40 +02:00
wire - > is_logic = true ;
2023-04-04 22:59:44 +02:00
while ( wire - > simplify ( true , 1 , - 1 , false ) ) { }
2025-06-16 22:55:24 +02:00
lookaheadids [ node - > str ] = make_pair ( node - > id2ast , wire . get ( ) ) ;
2020-04-15 20:36:40 +02:00
wire - > genRTLIL ( ) ;
2025-06-16 22:55:24 +02:00
current_ast_mod - > children . push_back ( std : : move ( wire ) ) ;
2020-04-15 20:36:40 +02:00
}
}
2025-06-16 22:55:24 +02:00
for ( auto & child : node - > children )
collect_lookaheadids ( child . get ( ) ) ;
2020-04-15 20:36:40 +02:00
}
bool has_lookaheadids ( AstNode * node )
{
if ( node - > type = = AST_IDENTIFIER & & lookaheadids . count ( node - > str ) ! = 0 )
return true ;
2025-06-16 22:55:24 +02:00
for ( auto & child : node - > children )
if ( has_lookaheadids ( child . get ( ) ) )
2020-04-15 20:36:40 +02:00
return true ;
return false ;
}
bool has_nonlookaheadids ( AstNode * node )
{
if ( node - > type = = AST_IDENTIFIER & & lookaheadids . count ( node - > str ) = = 0 )
return true ;
2025-06-16 22:55:24 +02:00
for ( auto & child : node - > children )
if ( has_nonlookaheadids ( child . get ( ) ) )
2020-04-15 20:36:40 +02:00
return true ;
return false ;
}
void rewrite_lookaheadids ( AstNode * node , bool lhs = false )
{
if ( node - > type = = AST_ASSIGN_LE )
{
2025-06-16 22:55:24 +02:00
if ( has_lookaheadids ( node - > children [ 0 ] . get ( ) ) )
2020-04-15 20:36:40 +02:00
{
2025-06-16 22:55:24 +02:00
if ( has_nonlookaheadids ( node - > children [ 0 ] . get ( ) ) )
2020-04-15 20:36:40 +02:00
log_error ( " incompatible mix of lookahead and non-lookahead IDs in LHS expression. \n " ) ;
2025-06-16 22:55:24 +02:00
rewrite_lookaheadids ( node - > children [ 0 ] . get ( ) , true ) ;
2020-04-15 20:36:40 +02:00
node - > type = AST_ASSIGN_EQ ;
}
2025-06-16 22:55:24 +02:00
rewrite_lookaheadids ( node - > children [ 1 ] . get ( ) , lhs ) ;
2020-04-15 20:36:40 +02:00
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 ;
}
2025-06-16 22:55:24 +02:00
for ( auto & child : node - > children )
rewrite_lookaheadids ( child . get ( ) , lhs ) ;
2020-04-15 20:36:40 +02:00
}
LookaheadRewriter ( AstNode * top )
{
2025-06-16 22:55:24 +02:00
// top->dumpAst(nullptr, "REWRITE-BEFORE> ");
// top->dumpVlog(nullptr, "REWRITE-BEFORE> ");
2020-04-15 20:36:40 +02:00
AstNode * block = nullptr ;
2025-06-18 22:50:46 +02:00
auto loc = top - > location ;
2020-04-15 20:36:40 +02:00
2025-06-16 22:55:24 +02:00
for ( auto & c : top - > children )
2020-04-15 20:36:40 +02:00
if ( c - > type = = AST_BLOCK ) {
log_assert ( block = = nullptr ) ;
2025-06-16 22:55:24 +02:00
block = c . get ( ) ;
2020-04-15 20:36:40 +02:00
}
log_assert ( block ! = nullptr ) ;
collect_lookaheadids ( block ) ;
rewrite_lookaheadids ( block ) ;
for ( auto it : lookaheadids )
{
2025-06-18 22:50:46 +02:00
auto ref_orig = std : : make_unique < AstNode > ( loc , AST_IDENTIFIER ) ;
2020-04-15 20:36:40 +02:00
ref_orig - > str = it . second . first - > str ;
ref_orig - > id2ast = it . second . first ;
ref_orig - > was_checked = true ;
2025-06-18 22:50:46 +02:00
auto ref_temp = std : : make_unique < AstNode > ( loc , AST_IDENTIFIER ) ;
2020-04-15 20:36:40 +02:00
ref_temp - > str = it . second . second - > str ;
ref_temp - > id2ast = it . second . second ;
ref_temp - > was_checked = true ;
2025-06-18 22:50:46 +02:00
auto init_assign = std : : make_unique < AstNode > ( loc , AST_ASSIGN_EQ , ref_temp - > clone ( ) , ref_orig - > clone ( ) ) ;
auto final_assign = std : : make_unique < AstNode > ( loc , AST_ASSIGN_LE , std : : move ( ref_orig ) , std : : move ( ref_temp ) ) ;
2020-04-15 20:36:40 +02:00
2025-06-16 22:55:24 +02:00
block - > children . insert ( block - > children . begin ( ) , std : : move ( init_assign ) ) ;
block - > children . push_back ( std : : move ( final_assign ) ) ;
2020-04-15 20:36:40 +02:00
}
2025-06-16 22:55:24 +02:00
// top->dumpAst(nullptr, "REWRITE-AFTER> ");
// top->dumpVlog(nullptr, "REWRITE-AFTER> ");
2020-04-15 20:36:40 +02:00
}
} ;
2013-01-05 11:13:26 +01:00
// helper class for converting AST always nodes to RTLIL processes
struct AST_INTERNAL : : ProcessGenerator
{
// input and output structures
2025-06-16 22:55:24 +02:00
std : : unique_ptr < AstNode > always ;
2013-11-21 13:49:00 +01:00
RTLIL : : SigSpec initSyncSignals ;
2013-01-05 11:13:26 +01:00
RTLIL : : Process * proc ;
2014-08-14 23:02:07 +02:00
RTLIL : : SigSpec outputSignals ;
2013-01-05 11:13:26 +01:00
2015-08-14 10:56:05 +02:00
// This always points to the RTLIL::CaseRule being filled at the moment
2013-01-05 11:13:26 +01:00
RTLIL : : CaseRule * current_case ;
2014-08-16 19:31:59 +02:00
// This map contains the replacement pattern to be used in the right hand side
2013-01-05 11:13:26 +01: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 10:56:05 +02:00
// the value assigned in the first assignment. So when the first assignment is processed
2013-01-05 11:13:26 +01:00
// the according information is appended to subst_rvalue_from and subst_rvalue_to.
2014-08-17 00:57:24 +02:00
stackmap < RTLIL : : SigBit , RTLIL : : SigBit > subst_rvalue_map ;
2013-01-05 11:13:26 +01:00
2014-08-16 19:31:59 +02:00
// This map contains the replacement pattern to be used in the left hand side
2013-01-05 11:13:26 +01: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-17 00:57:24 +02:00
stackmap < RTLIL : : SigBit , RTLIL : : SigBit > subst_lvalue_map ;
2013-01-05 11:13:26 +01:00
2015-08-14 10:56:05 +02:00
// The code here generates a number of temporary signal for each output register. This
2013-01-05 11:13:26 +01:00
// map helps generating nice numbered names for all this temporary signals.
std : : map < RTLIL : : Wire * , int > new_temp_count ;
2013-11-21 13:49:00 +01:00
// Buffer for generating the init action
RTLIL : : SigSpec init_lvalue , init_rvalue ;
2024-01-11 10:39:28 +01:00
// The most recently assigned $print or $check cell \PRIORITY.
int last_effect_priority ;
2023-06-28 03:51:31 +02:00
2025-06-16 22:55:24 +02:00
ProcessGenerator ( std : : unique_ptr < AstNode > a , RTLIL : : SigSpec initSyncSignalsArg = RTLIL : : SigSpec ( ) ) : always ( std : : move ( a ) ) , initSyncSignals ( initSyncSignalsArg ) , last_effect_priority ( 0 )
2013-01-05 11:13:26 +01:00
{
2020-04-15 20:36:40 +02:00
// rewrite lookahead references
2025-06-16 22:55:24 +02:00
LookaheadRewriter la_rewriter ( always . get ( ) ) ;
2020-04-15 20:36:40 +02:00
2013-01-05 11:13:26 +01:00
// generate process and simple root case
2025-08-20 00:45:26 +02:00
proc = current_module - > addProcess ( stringf ( " $proc$%s:%d$%d " , RTLIL : : encode_filename ( * always - > location . begin . filename ) , always - > location . begin . line , autoidx + + ) ) ;
2025-06-16 22:55:24 +02:00
set_src_attr ( proc , always . get ( ) ) ;
2013-01-05 11:13:26 +01:00
for ( auto & attr : always - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
always - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
proc - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
current_case = & proc - > root_case ;
// create initial temporary signal for all output registers
2014-08-16 19:31:59 +02:00
RTLIL : : SigSpec subst_lvalue_from , subst_lvalue_to ;
2025-06-16 22:55:24 +02:00
collect_lvalues ( subst_lvalue_from , always . get ( ) , true , true ) ;
2013-01-05 11:13:26 +01:00
subst_lvalue_to = new_temp_signal ( subst_lvalue_from ) ;
2014-08-16 19:31:59 +02:00
subst_lvalue_map = subst_lvalue_from . to_sigbit_map ( subst_lvalue_to ) ;
2013-01-05 11:13:26 +01:00
2016-10-14 12:33:56 +02:00
bool found_global_syncs = false ;
2013-01-05 11:13:26 +01:00
bool found_anyedge_syncs = false ;
2025-06-16 22:55:24 +02:00
for ( auto & child : always - > children )
2018-06-01 13:25:42 +02:00
{
if ( ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE ) & & GetSize ( child - > children ) = = 1 & & child - > children . at ( 0 ) - > type = = AST_IDENTIFIER & &
2020-03-12 20:57:01 +01: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 13:25:42 +02:00
found_global_syncs = true ;
}
2016-10-14 12:33:56 +02: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 13:25:42 +02:00
}
2013-01-05 11:13:26 +01:00
if ( found_anyedge_syncs ) {
2016-10-14 12:33:56 +02:00
if ( found_global_syncs )
2023-04-04 11:53:50 +02:00
always - > input_error ( " Found non-synthesizable event list! \n " ) ;
2025-09-11 07:25:26 +02:00
log ( " Note: Assuming pure combinatorial block at %s in \n " , always - > loc_string ( ) ) ;
2013-01-05 11:13:26 +01: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 ;
2025-06-16 22:55:24 +02:00
for ( auto & child : always - > children )
2013-01-05 11:13:26 +01:00
if ( child - > type = = AST_POSEDGE | | child - > type = = AST_NEGEDGE ) {
2018-06-01 13:25:42 +02:00
if ( GetSize ( child - > children ) = = 1 & & child - > children . at ( 0 ) - > type = = AST_IDENTIFIER & & child - > children . at ( 0 ) - > id2ast & &
2020-03-12 20:57:01 +01:00
child - > children . at ( 0 ) - > id2ast - > type = = AST_WIRE & & child - > children . at ( 0 ) - > id2ast - > get_bool_attribute ( ID : : gclk ) )
2018-06-01 13:25:42 +02:00
continue ;
2013-01-05 11:13:26 +01:00
found_clocked_sync = true ;
2016-10-14 12:33:56 +02:00
if ( found_global_syncs | | found_anyedge_syncs )
2023-04-04 11:53:50 +02:00
always - > input_error ( " Found non-synthesizable event list! \n " ) ;
2013-01-05 11:13:26 +01: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 19:32:11 +02:00
if ( GetSize ( syncrule - > signal ) ! = 1 )
2023-04-04 11:53:50 +02:00
always - > input_error ( " Found posedge/negedge event on a signal that is not 1 bit wide! \n " ) ;
2013-03-25 17:13:14 +01:00
addChunkActions ( syncrule - > actions , subst_lvalue_from , subst_lvalue_to , true ) ;
2013-01-05 11:13:26 +01:00
proc - > syncs . push_back ( syncrule ) ;
}
if ( proc - > syncs . empty ( ) ) {
RTLIL : : SyncRule * syncrule = new RTLIL : : SyncRule ;
2016-10-14 12:33:56 +02:00
syncrule - > type = found_global_syncs ? RTLIL : : STg : RTLIL : : STa ;
2013-01-05 11:13:26 +01:00
syncrule - > signal = RTLIL : : SigSpec ( ) ;
2013-03-25 17:13:14 +01:00
addChunkActions ( syncrule - > actions , subst_lvalue_from , subst_lvalue_to , true ) ;
2013-01-05 11:13:26 +01:00
proc - > syncs . push_back ( syncrule ) ;
}
// create initial assignments for the temporary signals
2020-04-02 18:51:32 +02:00
if ( ( flag_nolatches | | always - > get_bool_attribute ( ID : : nolatches ) | | current_module - > get_bool_attribute ( ID : : nolatches ) ) & & ! found_clocked_sync ) {
2014-12-28 19:24:24 +01:00
subst_rvalue_map = subst_lvalue_from . to_sigbit_dict ( RTLIL : : SigSpec ( RTLIL : : State : : Sx , GetSize ( subst_lvalue_from ) ) ) ;
2013-01-05 11:13:26 +01:00
} else {
addChunkActions ( current_case - > actions , subst_lvalue_to , subst_lvalue_from ) ;
}
// process the AST
2025-06-16 22:55:24 +02:00
for ( auto & child : always - > children )
2013-01-05 11:13:26 +01:00
if ( child - > type = = AST_BLOCK )
2025-06-16 22:55:24 +02:00
processAst ( child . get ( ) ) ;
2013-11-21 13:49:00 +01:00
2021-02-23 16:48:29 +01:00
for ( auto sync : proc - > syncs )
processMemWrites ( sync ) ;
2014-07-22 20:15:14 +02:00
if ( initSyncSignals . size ( ) > 0 )
2013-11-21 13:49:00 +01:00
{
RTLIL : : SyncRule * sync = new RTLIL : : SyncRule ;
sync - > type = RTLIL : : SyncType : : STi ;
proc - > syncs . push_back ( sync ) ;
2014-07-28 11:08:55 +02:00
log_assert ( init_lvalue . size ( ) = = init_rvalue . size ( ) ) ;
2013-11-21 13:49:00 +01:00
int offset = 0 ;
2014-07-24 22:47:57 +02: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 17:58:27 +02:00
remove_unwanted_lvalue_bits ( lhs , rhs ) ;
2013-11-21 13:49:00 +01:00
sync - > actions . push_back ( RTLIL : : SigSig ( lhs , rhs ) ) ;
2014-07-22 20:15:14 +02:00
offset + = lhs . size ( ) ;
2013-11-21 13:49:00 +01:00
}
}
2014-08-14 23:02:07 +02:00
outputSignals = RTLIL : : SigSpec ( subst_lvalue_from ) ;
2013-01-05 11:13:26 +01:00
}
2014-09-06 17:58:27 +02:00
void remove_unwanted_lvalue_bits ( RTLIL : : SigSpec & lhs , RTLIL : : SigSpec & rhs )
{
RTLIL : : SigSpec new_lhs , new_rhs ;
2014-10-10 16:59:44 +02:00
log_assert ( GetSize ( lhs ) = = GetSize ( rhs ) ) ;
for ( int i = 0 ; i < GetSize ( lhs ) ; i + + ) {
2014-09-06 17:58:27 +02: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 11:13:26 +01:00
// create new temporary signals
RTLIL : : SigSpec new_temp_signal ( RTLIL : : SigSpec sig )
{
2014-07-22 23:50:21 +02:00
std : : vector < RTLIL : : SigChunk > chunks = sig . chunks ( ) ;
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( chunks ) ; i + + )
2013-01-05 11:13:26 +01:00
{
2014-07-22 23:50:21 +02:00
RTLIL : : SigChunk & chunk = chunks [ i ] ;
2025-06-16 22:55:24 +02:00
if ( chunk . wire = = nullptr )
2013-01-05 11:13:26 +01:00
continue ;
2014-07-26 20:12:50 +02:00
std : : string wire_name ;
2013-01-05 11:13:26 +01:00
do {
2014-07-26 20:12:50 +02:00
wire_name = stringf ( " $%d%s[%d:%d] " , new_temp_count [ chunk . wire ] + + ,
2013-01-05 11:13:26 +01:00
chunk . wire - > name . c_str ( ) , chunk . width + chunk . offset - 1 , chunk . offset ) ; ;
2014-08-02 13:11:01 +02:00
if ( chunk . wire - > name . str ( ) . find ( ' $ ' ) ! = std : : string : : npos )
2014-07-31 13:19:47 +02:00
wire_name + = stringf ( " $%d " , autoidx + + ) ;
2014-07-27 01:49:51 +02:00
} while ( current_module - > wires_ . count ( wire_name ) > 0 ) ;
2014-07-26 20:12:50 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( wire_name , chunk . width ) ;
2025-06-16 22:55:24 +02:00
set_src_attr ( wire , always . get ( ) ) ;
2013-01-05 11:13:26 +01:00
chunk . wire = wire ;
chunk . offset = 0 ;
}
2014-07-22 23:50:21 +02:00
return chunks ;
2013-01-05 11:13:26 +01:00
}
2020-04-15 20:36:40 +02:00
// recursively traverse the AST and collect all assigned signals
2013-01-05 11:13:26 +01: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 :
2025-06-16 22:55:24 +02:00
for ( auto & child : ast - > children )
2013-01-05 11:13:26 +01:00
if ( child ! = ast - > children [ 0 ] ) {
2016-04-21 15:31:54 +02:00
log_assert ( child - > type = = AST_COND | | child - > type = = AST_CONDX | | child - > type = = AST_CONDZ ) ;
2025-06-16 22:55:24 +02:00
collect_lvalues ( reg , child . get ( ) , type_eq , type_le , false ) ;
2013-01-05 11:13:26 +01:00
}
break ;
case AST_COND :
2016-04-21 15:31:54 +02:00
case AST_CONDX :
case AST_CONDZ :
2013-01-05 11:13:26 +01:00
case AST_ALWAYS :
2013-03-31 11:19:11 +02:00
case AST_INITIAL :
2025-06-16 22:55:24 +02:00
for ( auto & child : ast - > children )
2013-01-05 11:13:26 +01:00
if ( child - > type = = AST_BLOCK )
2025-06-16 22:55:24 +02:00
collect_lvalues ( reg , child . get ( ) , type_eq , type_le , false ) ;
2013-01-05 11:13:26 +01:00
break ;
case AST_BLOCK :
2025-06-16 22:55:24 +02:00
for ( auto & child : ast - > children ) {
2013-01-05 11:13:26 +01:00
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 )
2025-06-16 22:55:24 +02:00
collect_lvalues ( reg , child . get ( ) , type_eq , type_le , false ) ;
2013-01-05 11:13:26 +01:00
}
break ;
default :
2014-07-28 11:08:55 +02:00
log_abort ( ) ;
2013-01-05 11:13:26 +01:00
}
2014-09-06 17:58:27 +02: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 11:13:26 +01:00
}
2013-04-13 21:19:10 +02: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 11:13:26 +01:00
// the third assignment.
2016-01-31 04:26:46 +01:00
void removeSignalFromCaseTree ( const RTLIL : : SigSpec & pattern , RTLIL : : CaseRule * cs )
2013-01-05 11:13:26 +01: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 11:51:12 +02:00
void addChunkActions ( std : : vector < RTLIL : : SigSig > & actions , RTLIL : : SigSpec lvalue , RTLIL : : SigSpec rvalue , bool inSyncRule = false )
2013-01-05 11:13:26 +01:00
{
2014-07-22 20:15:14 +02:00
if ( inSyncRule & & initSyncSignals . size ( ) > 0 ) {
2013-11-21 13:49:00 +01:00
init_lvalue . append ( lvalue . extract ( initSyncSignals ) ) ;
init_rvalue . append ( lvalue . extract ( initSyncSignals , & rvalue ) ) ;
lvalue . remove2 ( initSyncSignals , & rvalue ) ;
}
2014-07-28 11:08:55 +02:00
log_assert ( lvalue . size ( ) = = rvalue . size ( ) ) ;
2013-01-05 11:13:26 +01:00
int offset = 0 ;
2014-07-24 22:47:57 +02:00
for ( auto & lvalue_c : lvalue . chunks ( ) ) {
RTLIL : : SigSpec lhs = lvalue_c ;
RTLIL : : SigSpec rhs = rvalue . extract ( offset , lvalue_c . width ) ;
2020-04-02 18:51:32 +02:00
if ( inSyncRule & & lvalue_c . wire & & lvalue_c . wire - > get_bool_attribute ( ID : : nosync ) )
2014-07-22 20:15:14 +02:00
rhs = RTLIL : : SigSpec ( RTLIL : : State : : Sx , rhs . size ( ) ) ;
2014-09-06 17:58:27 +02:00
remove_unwanted_lvalue_bits ( lhs , rhs ) ;
2013-01-05 11:13:26 +01:00
actions . push_back ( RTLIL : : SigSig ( lhs , rhs ) ) ;
2014-07-22 20:15:14 +02:00
offset + = lhs . size ( ) ;
2013-01-05 11:13:26 +01:00
}
}
// recursively process the AST and fill the RTLIL::Process
void processAst ( AstNode * ast )
{
switch ( ast - > type )
{
case AST_BLOCK :
2025-06-16 22:55:24 +02:00
for ( auto & child : ast - > children )
processAst ( child . get ( ) ) ;
2013-01-05 11:13:26 +01:00
break ;
case AST_ASSIGN_EQ :
case AST_ASSIGN_LE :
{
RTLIL : : SigSpec unmapped_lvalue = ast - > children [ 0 ] - > genRTLIL ( ) , lvalue = unmapped_lvalue ;
2021-03-25 19:06:05 +01:00
RTLIL : : SigSpec rvalue = ast - > children [ 1 ] - > genWidthRTLIL ( lvalue . size ( ) , true , & subst_rvalue_map . stdmap ( ) ) ;
2016-05-27 17:55:03 +02: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-17 00:57:24 +02:00
lvalue . replace ( subst_lvalue_map . stdmap ( ) ) ;
2013-01-05 11:13:26 +01:00
if ( ast - > type = = AST_ASSIGN_EQ ) {
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( unmapped_lvalue ) ; i + + )
2014-08-17 00:57:24 +02:00
subst_rvalue_map . set ( unmapped_lvalue [ i ] , rvalue [ i ] ) ;
2013-01-05 11:13:26 +01:00
}
2016-01-31 04:26:46 +01:00
removeSignalFromCaseTree ( lvalue , current_case ) ;
2014-09-06 17:58:27 +02:00
remove_unwanted_lvalue_bits ( lvalue , rvalue ) ;
2013-01-05 11:13:26 +01:00
current_case - > actions . push_back ( RTLIL : : SigSig ( lvalue , rvalue ) ) ;
}
break ;
case AST_CASE :
{
2021-03-25 19:06:05 +01:00
int width_hint ;
bool sign_hint ;
ast - > detectSignWidth ( width_hint , sign_hint ) ;
2013-01-05 11:13:26 +01:00
RTLIL : : SwitchRule * sw = new RTLIL : : SwitchRule ;
2021-02-23 19:22:53 +01:00
set_src_attr ( sw , ast ) ;
2021-03-25 19:06:05 +01:00
sw - > signal = ast - > children [ 0 ] - > genWidthRTLIL ( width_hint , sign_hint , & subst_rvalue_map . stdmap ( ) ) ;
2013-01-05 11:13:26 +01:00
current_case - > switches . push_back ( sw ) ;
for ( auto & attr : ast - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
ast - > input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
sw - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01: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-17 00:57:24 +02:00
this_case_eq_rvalue . replace ( subst_rvalue_map . stdmap ( ) ) ;
2013-01-05 11:13:26 +01:00
2025-06-16 22:55:24 +02:00
RTLIL : : CaseRule * default_case = nullptr ;
RTLIL : : CaseRule * last_generated_case = nullptr ;
for ( auto & child : ast - > children )
2013-01-05 11:13:26 +01:00
{
2013-11-18 16:10:50 +01:00
if ( child = = ast - > children [ 0 ] )
2013-01-05 11:13:26 +01:00
continue ;
2016-04-21 15:31:54 +02:00
log_assert ( child - > type = = AST_COND | | child - > type = = AST_CONDX | | child - > type = = AST_CONDZ ) ;
2013-01-05 11:13:26 +01:00
2014-08-17 00:57:24 +02:00
subst_lvalue_map . save ( ) ;
subst_rvalue_map . save ( ) ;
2013-01-05 11:13:26 +01:00
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( this_case_eq_lvalue ) ; i + + )
2014-08-17 00:57:24 +02:00
subst_lvalue_map . set ( this_case_eq_lvalue [ i ] , this_case_eq_ltemp [ i ] ) ;
2013-01-05 11:13:26 +01:00
RTLIL : : CaseRule * backup_case = current_case ;
current_case = new RTLIL : : CaseRule ;
2025-06-16 22:55:24 +02:00
set_src_attr ( current_case , child . get ( ) ) ;
2013-01-05 11:13:26 +01:00
last_generated_case = current_case ;
addChunkActions ( current_case - > actions , this_case_eq_ltemp , this_case_eq_rvalue ) ;
2025-06-16 22:55:24 +02:00
for ( auto & node : child - > children ) {
2013-11-18 16:10:50 +01:00
if ( node - > type = = AST_DEFAULT )
default_case = current_case ;
else if ( node - > type = = AST_BLOCK )
2025-06-16 22:55:24 +02:00
processAst ( node . get ( ) ) ;
2014-08-16 19:31:59 +02:00
else
2021-03-25 19:06:05 +01:00
current_case - > compare . push_back ( node - > genWidthRTLIL ( width_hint , sign_hint , & subst_rvalue_map . stdmap ( ) ) ) ;
2013-01-05 11:13:26 +01:00
}
2013-11-18 16:10:50 +01:00
if ( default_case ! = current_case )
sw - > cases . push_back ( current_case ) ;
else
log_assert ( current_case - > compare . size ( ) = = 0 ) ;
2013-01-05 11:13:26 +01:00
current_case = backup_case ;
2014-08-17 00:57:24 +02:00
subst_lvalue_map . restore ( ) ;
subst_rvalue_map . restore ( ) ;
2013-01-05 11:13:26 +01:00
}
2025-06-16 22:55:24 +02:00
if ( last_generated_case ! = nullptr & & ast - > get_bool_attribute ( ID : : full_case ) & & default_case = = nullptr ) {
2019-03-14 17:51:21 +01: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 11:13:26 +01:00
last_generated_case - > compare . clear ( ) ;
2019-03-14 17:51:21 +01: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 16:10:50 +01:00
} else {
2025-06-16 22:55:24 +02:00
if ( default_case = = nullptr ) {
2013-11-18 16:10:50 +01:00
default_case = new RTLIL : : CaseRule ;
addChunkActions ( default_case - > actions , this_case_eq_ltemp , this_case_eq_rvalue ) ;
}
2013-01-05 11:13:26 +01:00
sw - > cases . push_back ( default_case ) ;
}
2014-10-10 16:59:44 +02:00
for ( int i = 0 ; i < GetSize ( this_case_eq_lvalue ) ; i + + )
2014-08-17 00:57:24 +02:00
subst_rvalue_map . set ( this_case_eq_lvalue [ i ] , this_case_eq_ltemp [ i ] ) ;
2013-01-05 11:13:26 +01:00
2014-08-17 00:57:24 +02:00
this_case_eq_lvalue . replace ( subst_lvalue_map . stdmap ( ) ) ;
2016-01-31 04:26:46 +01:00
removeSignalFromCaseTree ( this_case_eq_lvalue , current_case ) ;
2013-01-05 11:13:26 +01:00
addChunkActions ( current_case - > actions , this_case_eq_lvalue , this_case_eq_ltemp ) ;
}
break ;
2013-12-04 09:10:16 +01:00
case AST_WIRE :
2023-04-04 11:53:50 +02:00
ast - > input_error ( " Found reg declaration in block without label! \n " ) ;
2019-03-02 20:40:57 +01:00
break ;
case AST_ASSIGN :
2023-04-04 11:53:50 +02:00
ast - > input_error ( " Found continous assignment in always/initial block! \n " ) ;
2013-12-04 09:10:16 +01:00
break ;
2015-11-11 10:54:35 +01:00
case AST_PARAMETER :
case AST_LOCALPARAM :
2023-04-04 11:53:50 +02:00
ast - > input_error ( " Found parameter declaration in block without label! \n " ) ;
2015-11-11 10:54:35 +01:00
break ;
2013-01-05 11:13:26 +01:00
case AST_TCALL :
2020-11-29 15:34:17 +01:00
if ( ast - > str = = " $display " | | ast - > str = = " $displayb " | | ast - > str = = " $displayh " | | ast - > str = = " $displayo " | |
ast - > str = = " $write " | | ast - > str = = " $writeb " | | ast - > str = = " $writeh " | | ast - > str = = " $writeo " ) {
std : : stringstream sstr ;
2025-06-18 22:50:46 +02:00
sstr < < ast - > str < < " $ " < < ast - > location . begin . filename < < " : " < < ast - > location . begin . line < < " $ " < < ( autoidx + + ) ;
2020-11-29 15:34:17 +01:00
2024-01-11 10:39:28 +01:00
Wire * en = current_module - > addWire ( sstr . str ( ) + " _EN " , 1 ) ;
set_src_attr ( en , ast ) ;
proc - > root_case . actions . push_back ( SigSig ( en , false ) ) ;
current_case - > actions . push_back ( SigSig ( en , true ) ) ;
2020-11-29 15:34:17 +01:00
RTLIL : : SigSpec triggers ;
2025-08-28 03:55:26 +02:00
RTLIL : : Const : : Builder polarity_builder ;
2020-11-29 15:34:17 +01:00
for ( auto sync : proc - > syncs ) {
if ( sync - > type = = RTLIL : : STp ) {
triggers . append ( sync - > signal ) ;
2025-08-28 03:55:26 +02:00
polarity_builder . push_back ( RTLIL : : S1 ) ;
2020-11-29 15:34:17 +01:00
} else if ( sync - > type = = RTLIL : : STn ) {
triggers . append ( sync - > signal ) ;
2025-08-28 03:55:26 +02:00
polarity_builder . push_back ( RTLIL : : S0 ) ;
2020-11-29 15:34:17 +01:00
}
}
2025-08-28 03:55:26 +02:00
RTLIL : : Const polarity = polarity_builder . build ( ) ;
2020-11-29 15:34:17 +01:00
2024-01-11 10:39:28 +01:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ print ) ) ;
set_src_attr ( cell , ast ) ;
cell - > setParam ( ID : : TRG_WIDTH , triggers . size ( ) ) ;
cell - > setParam ( ID : : TRG_ENABLE , ( always - > type = = AST_INITIAL ) | | ! triggers . empty ( ) ) ;
cell - > setParam ( ID : : TRG_POLARITY , polarity ) ;
cell - > setParam ( ID : : PRIORITY , - - last_effect_priority ) ;
cell - > setPort ( ID : : TRG , triggers ) ;
cell - > setPort ( ID : : EN , en ) ;
2020-11-29 15:34:17 +01:00
int default_base = 10 ;
if ( ast - > str . back ( ) = = ' b ' )
default_base = 2 ;
else if ( ast - > str . back ( ) = = ' o ' )
default_base = 8 ;
else if ( ast - > str . back ( ) = = ' h ' )
default_base = 16 ;
std : : vector < VerilogFmtArg > args ;
2025-06-16 22:55:24 +02:00
for ( auto & node : ast - > children ) {
2020-11-29 15:34:17 +01:00
int width ;
bool is_signed ;
node - > detectSignWidth ( width , is_signed , nullptr ) ;
VerilogFmtArg arg = { } ;
2025-06-18 22:50:46 +02:00
arg . filename = * node - > location . begin . filename ;
arg . first_line = node - > location . begin . line ;
2020-11-29 15:34:17 +01:00
if ( node - > type = = AST_CONSTANT & & node - > is_string ) {
arg . type = VerilogFmtArg : : STRING ;
arg . str = node - > bitsAsConst ( ) . decode_string ( ) ;
// and in case this will be used as an argument...
arg . sig = node - > bitsAsConst ( ) ;
arg . signed_ = false ;
2023-06-28 03:51:20 +02:00
} else if ( node - > type = = AST_IDENTIFIER & & node - > str = = " $time " ) {
arg . type = VerilogFmtArg : : TIME ;
} else if ( node - > type = = AST_IDENTIFIER & & node - > str = = " $realtime " ) {
arg . type = VerilogFmtArg : : TIME ;
arg . realtime = true ;
2020-11-29 15:34:17 +01:00
} else {
arg . type = VerilogFmtArg : : INTEGER ;
2023-09-05 21:40:24 +02:00
arg . sig = node - > genWidthRTLIL ( - 1 , false , & subst_rvalue_map . stdmap ( ) ) ;
2020-11-29 15:34:17 +01:00
arg . signed_ = is_signed ;
}
args . push_back ( arg ) ;
}
2024-01-11 10:39:28 +01:00
Fmt fmt ;
2020-11-29 15:34:17 +01:00
fmt . parse_verilog ( args , /*sformat_like=*/ false , default_base , /*task_name=*/ ast - > str , current_module - > name ) ;
if ( ast - > str . substr ( 0 , 8 ) = = " $display " )
2024-03-28 07:30:16 +01:00
fmt . append_literal ( " \n " ) ;
2020-11-29 15:34:17 +01:00
fmt . emit_rtlil ( cell ) ;
} else if ( ! ast - > str . empty ( ) ) {
2025-09-17 00:59:08 +02:00
log_file_error ( * ast - > location . begin . filename , ast - > location . begin . line , " Found unsupported invocation of system task `%s'! \n " , ast - > str ) ;
2020-11-29 15:34:17 +01:00
}
break ;
2024-01-11 10:39:28 +01:00
// generate $check cells
case AST_ASSERT :
case AST_ASSUME :
case AST_LIVE :
case AST_FAIR :
case AST_COVER :
{
std : : string flavor , desc ;
if ( ast - > type = = AST_ASSERT ) { flavor = " assert " ; desc = " assert () " ; }
if ( ast - > type = = AST_ASSUME ) { flavor = " assume " ; desc = " assume () " ; }
if ( ast - > type = = AST_LIVE ) { flavor = " live " ; desc = " assert (eventually) " ; }
if ( ast - > type = = AST_FAIR ) { flavor = " fair " ; desc = " assume (eventually) " ; }
if ( ast - > type = = AST_COVER ) { flavor = " cover " ; desc = " cover () " ; }
IdString cellname ;
if ( ast - > str . empty ( ) )
2025-08-20 00:45:26 +02:00
cellname = stringf ( " $%s$%s:%d$%d " , flavor , RTLIL : : encode_filename ( * ast - > location . begin . filename ) , ast - > location . begin . line , autoidx + + ) ;
2024-01-11 10:39:28 +01:00
else
cellname = ast - > str ;
check_unique_id ( current_module , cellname , ast , " procedural assertion " ) ;
RTLIL : : SigSpec check = ast - > children [ 0 ] - > genWidthRTLIL ( - 1 , false , & subst_rvalue_map . stdmap ( ) ) ;
if ( GetSize ( check ) ! = 1 )
check = current_module - > ReduceBool ( NEW_ID , check ) ;
Wire * en = current_module - > addWire ( cellname . str ( ) + " _EN " , 1 ) ;
set_src_attr ( en , ast ) ;
proc - > root_case . actions . push_back ( SigSig ( en , false ) ) ;
current_case - > actions . push_back ( SigSig ( en , true ) ) ;
RTLIL : : SigSpec triggers ;
2025-08-28 03:55:26 +02:00
RTLIL : : Const : : Builder polarity_builder ;
2024-01-11 10:39:28 +01:00
for ( auto sync : proc - > syncs ) {
if ( sync - > type = = RTLIL : : STp ) {
triggers . append ( sync - > signal ) ;
2025-08-28 03:55:26 +02:00
polarity_builder . push_back ( RTLIL : : S1 ) ;
2024-01-11 10:39:28 +01:00
} else if ( sync - > type = = RTLIL : : STn ) {
triggers . append ( sync - > signal ) ;
2025-08-28 03:55:26 +02:00
polarity_builder . push_back ( RTLIL : : S0 ) ;
2024-01-11 10:39:28 +01:00
}
}
2025-08-28 03:55:26 +02:00
RTLIL : : Const polarity = polarity_builder . build ( ) ;
2024-01-11 10:39:28 +01:00
RTLIL : : Cell * cell = current_module - > addCell ( cellname , ID ( $ check ) ) ;
set_src_attr ( cell , ast ) ;
for ( auto & attr : ast - > attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-17 00:59:08 +02:00
log_file_error ( * ast - > location . begin . filename , ast - > location . begin . line , " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2024-01-11 10:39:28 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
}
cell - > setParam ( ID : : FLAVOR , flavor ) ;
cell - > setParam ( ID : : TRG_WIDTH , triggers . size ( ) ) ;
cell - > setParam ( ID : : TRG_ENABLE , ( always - > type = = AST_INITIAL ) | | ! triggers . empty ( ) ) ;
cell - > setParam ( ID : : TRG_POLARITY , polarity ) ;
cell - > setParam ( ID : : PRIORITY , - - last_effect_priority ) ;
cell - > setPort ( ID : : TRG , triggers ) ;
cell - > setPort ( ID : : EN , en ) ;
cell - > setPort ( ID : : A , check ) ;
// No message is emitted to ensure Verilog code roundtrips correctly.
Fmt fmt ;
fmt . emit_rtlil ( cell ) ;
break ;
}
2020-11-29 15:34:17 +01:00
case AST_NONE :
2013-01-05 11:13:26 +01:00
case AST_FOR :
break ;
default :
2025-06-16 22:55:24 +02:00
// ast->dumpAst(nullptr, "ast> ");
// current_ast_mod->dumpAst(nullptr, "mod> ");
2014-06-06 22:55:02 +02:00
log_abort ( ) ;
2013-01-05 11:13:26 +01:00
}
}
2021-02-23 16:48:29 +01:00
void processMemWrites ( RTLIL : : SyncRule * sync )
{
// Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array.
dict < std : : pair < std : : string , int > , int > port_map ;
2025-06-16 22:55:24 +02:00
for ( auto & child : always - > children )
2021-02-23 16:48:29 +01:00
if ( child - > type = = AST_MEMWR )
{
std : : string memid = child - > str ;
int portid = child - > children [ 3 ] - > asInt ( false ) ;
int cur_idx = GetSize ( sync - > mem_write_actions ) ;
RTLIL : : MemWriteAction action ;
2025-06-16 22:55:24 +02:00
set_src_attr ( & action , child . get ( ) ) ;
2021-02-23 16:48:29 +01:00
action . memid = memid ;
2021-03-25 19:06:05 +01:00
action . address = child - > children [ 0 ] - > genWidthRTLIL ( - 1 , true , & subst_rvalue_map . stdmap ( ) ) ;
action . data = child - > children [ 1 ] - > genWidthRTLIL ( current_module - > memories [ memid ] - > width , true , & subst_rvalue_map . stdmap ( ) ) ;
action . enable = child - > children [ 2 ] - > genWidthRTLIL ( - 1 , true , & subst_rvalue_map . stdmap ( ) ) ;
2021-02-23 16:48:29 +01:00
RTLIL : : Const orig_priority_mask = child - > children [ 4 ] - > bitsAsConst ( ) ;
RTLIL : : Const priority_mask = RTLIL : : Const ( 0 , cur_idx ) ;
for ( int i = 0 ; i < portid ; i + + ) {
int new_bit = port_map [ std : : make_pair ( memid , i ) ] ;
2025-08-28 03:55:26 +02:00
priority_mask . set ( new_bit , orig_priority_mask [ i ] ) ;
2021-02-23 16:48:29 +01:00
}
action . priority_mask = priority_mask ;
sync - > mem_write_actions . push_back ( action ) ;
port_map [ std : : make_pair ( memid , portid ) ] = cur_idx ;
}
}
2013-01-05 11:13:26 +01:00
} ;
2020-04-20 17:06:53 +02:00
// Generate RTLIL for a bind construct
//
// The AST node will have one or more AST_IDENTIFIER children, which were added
// by bind_target_instance in the parser. After these, it will have one or more
// cells, as parsed by single_cell. These have type AST_CELL.
//
// If there is more than one AST_IDENTIFIER, the first one should be considered
// a module identifier. If there is only one AST_IDENTIFIER, we can't tell at
// this point whether it's a module/interface name or the name of an instance
// because the correct interpretation depends on what's visible at elaboration
// time. For now, we just treat it as a target instance with unknown type, and
// we'll deal with the corner case in the hierarchy pass.
//
// To simplify downstream code, RTLIL::Binding only has a single target and
// single bound instance. If we see the syntax that allows more than one of
// either, we split it into multiple Binding objects.
std : : vector < RTLIL : : Binding * > AstNode : : genBindings ( ) const
{
// Partition children into identifiers and cells
int num_ids = 0 ;
for ( int i = 0 ; i < GetSize ( children ) ; + + i ) {
if ( children [ i ] - > type ! = AST_IDENTIFIER ) {
log_assert ( i > 0 ) ;
num_ids = i ;
break ;
}
}
// We should have found at least one child that's not an identifier
log_assert ( num_ids > 0 ) ;
// Make sense of the identifiers, extracting a possible type name and a
// list of hierarchical IDs. We represent an unknown type with an empty
// string.
RTLIL : : IdString tgt_type ;
int first_tgt_inst = 0 ;
if ( num_ids > 1 ) {
tgt_type = children [ 0 ] - > str ;
first_tgt_inst = 1 ;
}
std : : vector < RTLIL : : Binding * > ret ;
// At this point, we know that children with index >= first_tgt_inst and
// index < num_ids are (hierarchical?) names of target instances. Make a
// binding object for each of them, and fill in the generated instance
// cells each time.
for ( int i = first_tgt_inst ; i < num_ids ; + + i ) {
const AstNode & tgt_child = * children [ i ] ;
for ( int j = num_ids ; j < GetSize ( children ) ; + + j ) {
const AstNode & cell_child = * children [ j ] ;
log_assert ( cell_child . type = = AST_CELL ) ;
ret . push_back ( new AST : : Binding ( tgt_type , tgt_child . str ,
cell_child ) ) ;
}
}
return ret ;
}
2013-07-09 14:31:57 +02:00
// detect sign and width of an expression
2014-06-16 15:00:57 +02:00
void AstNode : : detectSignWidthWorker ( int & width_hint , bool & sign_hint , bool * found_real )
2013-07-09 14:31:57 +02:00
{
std : : string type_name ;
2013-11-02 13:00:17 +01:00
bool sub_sign_hint = true ;
int sub_width_hint = - 1 ;
int this_width = 0 ;
2025-06-16 22:55:24 +02:00
AstNode * range = nullptr ;
AstNode * id_ast = nullptr ;
2013-07-09 14:31:57 +02:00
2014-06-21 21:41:13 +02:00
bool local_found_real = false ;
2025-06-16 22:55:24 +02:00
if ( found_real = = nullptr )
2014-06-21 21:41:13 +02:00
found_real = & local_found_real ;
2013-07-09 14:31:57 +02:00
switch ( type )
{
2018-03-09 13:47:11 +01:00
case AST_NONE :
// unallocated enum, ignore
break ;
2013-07-09 14:31:57 +02:00
case AST_CONSTANT :
2024-11-29 00:31:34 +01:00
width_hint = max ( width_hint , GetSize ( bits ) ) ;
2013-07-09 14:31:57 +02:00
if ( ! is_signed )
sign_hint = false ;
break ;
2014-06-14 07:44:19 +02:00
case AST_REALVALUE :
2014-06-21 21:41:13 +02:00
* found_real = true ;
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , 32 ) ;
2014-06-14 07:44:19 +02:00
break ;
2013-07-09 14:31:57 +02:00
case AST_IDENTIFIER :
2013-11-07 09:58:15 +01:00
id_ast = id2ast ;
2021-06-05 22:21:09 +02:00
if ( ! id_ast ) {
if ( current_scope . count ( str ) )
id_ast = current_scope [ str ] ;
else {
std : : string alt = try_pop_module_prefix ( ) ;
if ( current_scope . count ( alt ) )
id_ast = current_scope [ alt ] ;
}
}
2013-11-07 09:58:15 +01:00
if ( ! id_ast )
2025-09-12 08:03:05 +02:00
input_error ( " Failed to resolve identifier %s for width detection! \n " , str ) ;
2018-03-09 13:47:11 +01:00
if ( id_ast - > type = = AST_PARAMETER | | id_ast - > type = = AST_LOCALPARAM | | id_ast - > type = = AST_ENUM_ITEM ) {
2013-11-07 09:58:15 +01: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 ;
2023-03-28 10:53:00 +02:00
} else {
if ( id_ast - > children [ 0 ] - > type ! = AST_CONSTANT )
2023-04-04 22:59:44 +02:00
while ( id_ast - > simplify ( true , 1 , - 1 , false ) ) { }
2023-03-28 10:53:00 +02:00
if ( id_ast - > children [ 0 ] - > type = = AST_CONSTANT )
this_width = id_ast - > children [ 0 ] - > bits . size ( ) ;
else
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width for parameter %s! \n " , str ) ;
2023-03-28 10:53:00 +02:00
}
2013-11-02 13:00:17 +01:00
if ( children . size ( ) ! = 0 )
2025-06-16 22:55:24 +02:00
range = children [ 0 ] . get ( ) ;
2013-11-07 09:58:15 +01: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 13:00:17 +01:00
this_width = 1 ;
else {
2025-06-16 22:55:24 +02:00
// current_ast_mod->dumpAst(nullptr, "mod> ");
2014-06-07 00:02:05 +02:00
// log("---\n");
2025-06-16 22:55:24 +02:00
// id_ast->dumpAst(nullptr, "decl> ");
// dumpAst(nullptr, "ref> ");
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width of signal access `%s'! \n " , str ) ;
2013-11-02 13:00:17 +01:00
}
} else {
2013-11-07 09:58:15 +01:00
this_width = id_ast - > range_left - id_ast - > range_right + 1 ;
2013-11-02 13:00:17 +01:00
if ( children . size ( ) ! = 0 )
2025-06-16 22:55:24 +02:00
range = children [ 0 ] . get ( ) ;
2013-11-02 13:00:17 +01:00
}
2013-11-07 09:58:15 +01:00
} else if ( id_ast - > type = = AST_GENVAR ) {
2013-11-02 13:00:17 +01:00
this_width = 32 ;
2013-11-07 09:58:15 +01:00
} else if ( id_ast - > type = = AST_MEMORY ) {
if ( ! id_ast - > children [ 0 ] - > range_valid )
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width of memory access `%s'! \n " , str ) ;
2013-11-07 09:58:15 +01:00
this_width = id_ast - > children [ 0 ] - > range_left - id_ast - > children [ 0 ] - > range_right + 1 ;
2019-05-01 09:57:26 +02:00
if ( children . size ( ) > 1 )
2025-06-16 22:55:24 +02:00
range = children [ 1 ] . get ( ) ;
2023-01-29 19:45:45 +01:00
} else if ( id_ast - > type = = AST_STRUCT_ITEM | | id_ast - > type = = AST_STRUCT | | id_ast - > type = = AST_UNION ) {
2025-06-16 22:55:24 +02:00
auto tmp_range = make_index_range ( id_ast ) ;
2021-06-22 16:39:57 +02:00
this_width = tmp_range - > range_left - tmp_range - > range_right + 1 ;
2013-11-02 13:00:17 +01:00
} else
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width for identifier %s! \n " , str ) ;
2013-11-02 13:00:17 +01:00
if ( range ) {
if ( range - > children . size ( ) = = 1 )
this_width = 1 ;
else if ( ! range - > range_valid ) {
2025-06-16 22:55:24 +02:00
auto left_at_zero_ast = children [ 0 ] - > children [ 0 ] - > clone_at_zero ( ) ;
auto right_at_zero_ast = children [ 0 ] - > children . size ( ) > = 2 ? children [ 0 ] - > children [ 1 ] - > clone_at_zero ( ) : left_at_zero_ast - > clone ( ) ;
2023-04-04 22:59:44 +02:00
while ( left_at_zero_ast - > simplify ( true , 1 , - 1 , false ) ) { }
while ( right_at_zero_ast - > simplify ( true , 1 , - 1 , false ) ) { }
2013-11-02 13:00:17 +01:00
if ( left_at_zero_ast - > type ! = AST_CONSTANT | | right_at_zero_ast - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Unsupported expression on dynamic range select on signal `%s'! \n " , str ) ;
2019-02-21 18:40:11 +01:00
this_width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2013-11-02 13:00:17 +01:00
} else
this_width = range - > range_left - range - > range_right + 1 ;
2014-07-28 10:10:08 +02:00
sign_hint = false ;
2014-07-28 15:19:34 +02:00
}
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , this_width ) ;
2013-11-07 09:58:15 +01:00
if ( ! id_ast - > is_signed )
2013-11-02 21:13:01 +01:00
sign_hint = false ;
2013-07-09 14:31:57 +02:00
break ;
2014-02-01 13:50:23 +01:00
case AST_TO_BITS :
2023-04-04 22:59:44 +02:00
while ( children [ 0 ] - > simplify ( true , 1 , - 1 , false ) = = true ) { }
2014-02-01 13:50:23 +01:00
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Left operand of tobits expression is not constant! \n " ) ;
2014-02-01 13:50:23 +01:00
children [ 1 ] - > detectSignWidthWorker ( sub_width_hint , sign_hint ) ;
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , children [ 0 ] - > bitsAsConst ( ) . as_int ( ) ) ;
2014-02-01 13:50:23 +01:00
break ;
2013-07-09 14:31:57 +02:00
case AST_TO_SIGNED :
2013-11-02 13:00:17 +01:00
children . at ( 0 ) - > detectSignWidthWorker ( width_hint , sub_sign_hint ) ;
2013-07-09 14:31:57 +02:00
break ;
case AST_TO_UNSIGNED :
2013-11-02 13:00:17 +01:00
children . at ( 0 ) - > detectSignWidthWorker ( width_hint , sub_sign_hint ) ;
2013-07-09 14:31:57 +02:00
sign_hint = false ;
break ;
2020-04-29 14:28:04 +02:00
case AST_SELFSZ :
sub_width_hint = 0 ;
children . at ( 0 ) - > detectSignWidthWorker ( sub_width_hint , sign_hint ) ;
break ;
2020-06-15 00:15:59 +02:00
case AST_CAST_SIZE :
2023-04-04 22:59:44 +02:00
while ( children . at ( 0 ) - > simplify ( true , 1 , - 1 , false ) ) { }
2020-06-15 00:15:59 +02:00
if ( children . at ( 0 ) - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Static cast with non constant expression! \n " ) ;
2020-06-15 00:15:59 +02:00
children . at ( 1 ) - > detectSignWidthWorker ( width_hint , sign_hint ) ;
2021-12-30 08:01:30 +01:00
this_width = children . at ( 0 ) - > bitsAsConst ( ) . as_int ( ) ;
width_hint = max ( width_hint , this_width ) ;
2020-06-15 00:15:59 +02:00
if ( width_hint < = 0 )
2023-04-04 11:53:50 +02:00
input_error ( " Static cast with zero or negative size! \n " ) ;
2020-06-15 00:15:59 +02:00
break ;
2013-07-09 14:31:57 +02:00
case AST_CONCAT :
2025-06-16 22:55:24 +02:00
for ( auto & child : children ) {
2013-11-02 13:00:17 +01:00
sub_width_hint = 0 ;
sub_sign_hint = true ;
2013-11-03 18:56:45 +01:00
child - > detectSignWidthWorker ( sub_width_hint , sub_sign_hint ) ;
2013-11-02 13:00:17 +01:00
this_width + = sub_width_hint ;
}
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , this_width ) ;
2013-11-02 13:00:17 +01:00
sign_hint = false ;
break ;
2013-07-09 14:31:57 +02:00
case AST_REPLICATE :
2023-04-04 22:59:44 +02:00
while ( children [ 0 ] - > simplify ( true , 1 , - 1 , false ) = = true ) { }
2013-11-02 13:00:17 +01:00
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Left operand of replicate expression is not constant! \n " ) ;
2013-11-02 13:00:17 +01:00
children [ 1 ] - > detectSignWidthWorker ( sub_width_hint , sub_sign_hint ) ;
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , children [ 0 ] - > bitsAsConst ( ) . as_int ( ) * sub_width_hint ) ;
2013-07-09 14:31:57 +02:00
sign_hint = false ;
break ;
case AST_NEG :
case AST_BIT_NOT :
case AST_POS :
2014-06-24 15:08:48 +02:00
children [ 0 ] - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 14:31:57 +02:00
break ;
case AST_BIT_AND :
case AST_BIT_OR :
case AST_BIT_XOR :
case AST_BIT_XNOR :
2025-06-16 22:55:24 +02:00
for ( auto & child : children )
2014-06-24 15:08:48 +02:00
child - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 14:31:57 +02: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 19:30:49 +01:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 14:31:57 +02:00
sign_hint = false ;
break ;
case AST_SHIFT_LEFT :
case AST_SHIFT_RIGHT :
case AST_SHIFT_SLEFT :
case AST_SHIFT_SRIGHT :
2020-04-27 17:04:47 +02:00
case AST_SHIFTX :
case AST_SHIFT :
2013-08-19 20:58:01 +02:00
case AST_POW :
2014-06-24 15:08:48 +02:00
children [ 0 ] - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 14:31:57 +02:00
break ;
case AST_LT :
case AST_LE :
case AST_EQ :
case AST_NE :
2013-12-27 13:50:08 +01:00
case AST_EQX :
case AST_NEX :
2013-07-09 14:31:57 +02:00
case AST_GE :
case AST_GT :
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 14:31:57 +02:00
sign_hint = false ;
break ;
case AST_ADD :
case AST_SUB :
case AST_MUL :
case AST_DIV :
case AST_MOD :
2025-06-16 22:55:24 +02:00
for ( auto & child : children )
2014-06-24 15:08:48 +02:00
child - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 14:31:57 +02:00
break ;
case AST_LOGIC_AND :
case AST_LOGIC_OR :
case AST_LOGIC_NOT :
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , 1 ) ;
2013-07-09 23:41:28 +02:00
sign_hint = false ;
2013-07-09 14:31:57 +02:00
break ;
case AST_TERNARY :
2014-06-24 15:08:48 +02:00
children . at ( 1 ) - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
children . at ( 2 ) - > detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2013-07-09 14:31:57 +02:00
break ;
case AST_MEMRD :
2013-11-04 06:04:42 +01:00
if ( ! id2ast - > is_signed )
2013-07-09 14:31:57 +02:00
sign_hint = false ;
2013-11-04 06:04:42 +01:00
if ( ! id2ast - > children [ 0 ] - > range_valid )
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width of memory access `%s'! \n " , str ) ;
2013-11-04 06:04:42 +01:00
this_width = id2ast - > children [ 0 ] - > range_left - id2ast - > children [ 0 ] - > range_right + 1 ;
2015-10-25 19:30:49 +01:00
width_hint = max ( width_hint , this_width ) ;
2013-07-09 14:31:57 +02:00
break ;
2021-03-25 19:06:05 +01:00
case AST_CASE :
{
// This detects the _overall_ sign and width to be used for comparing
// the case expression with the case item expressions. The case
// expression and case item expressions are extended to the maximum
// width among them, and are only interpreted as signed if all of them
// are signed.
width_hint = - 1 ;
sign_hint = true ;
auto visit_case_expr = [ & width_hint , & sign_hint ] ( AstNode * node ) {
int sub_width_hint = - 1 ;
bool sub_sign_hint = true ;
node - > detectSignWidth ( sub_width_hint , sub_sign_hint ) ;
width_hint = max ( width_hint , sub_width_hint ) ;
sign_hint & = sub_sign_hint ;
} ;
2025-06-16 22:55:24 +02:00
visit_case_expr ( children [ 0 ] . get ( ) ) ;
2021-03-25 19:06:05 +01:00
for ( size_t i = 1 ; i < children . size ( ) ; i + + ) {
2025-06-16 22:55:24 +02:00
AstNode * child = children [ i ] . get ( ) ;
for ( auto & v : child - > children ) {
2021-03-25 19:06:05 +01:00
if ( v - > type ! = AST_DEFAULT & & v - > type ! = AST_BLOCK )
2025-06-16 22:55:24 +02:00
visit_case_expr ( v . get ( ) ) ;
}
2021-03-25 19:06:05 +01:00
}
break ;
}
2021-07-29 18:35:22 +02:00
case AST_PREFIX :
// Prefix nodes always resolve to identifiers in generate loops, so we
// can simply perform the resolution to determine the sign and width.
2023-04-04 22:59:44 +02:00
simplify ( true , 1 , - 1 , false ) ;
2021-07-29 18:35:22 +02:00
log_assert ( type = = AST_IDENTIFIER ) ;
detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
break ;
2016-07-27 15:41:22 +02:00
case AST_FCALL :
2018-02-23 13:14:47 +01:00
if ( str = = " \\ $anyconst " | | str = = " \\ $anyseq " | | str = = " \\ $allconst " | | str = = " \\ $allseq " ) {
2016-07-27 15:41:22 +02:00
if ( GetSize ( children ) = = 1 ) {
2023-04-04 22:59:44 +02:00
while ( children [ 0 ] - > simplify ( true , 1 , - 1 , false ) = = true ) { }
2016-07-27 15:41:22 +02:00
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " System function %s called with non-const argument! \n " ,
2025-09-17 01:12:14 +02:00
RTLIL : : unescape_id ( str ) ) ;
2016-07-27 15:41:22 +02:00
width_hint = max ( width_hint , int ( children [ 0 ] - > asInt ( true ) ) ) ;
}
break ;
}
2016-09-19 01:30:07 +02: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 ) ;
2022-05-24 17:18:53 +02:00
sign_hint & = sub_sign_hint ;
2016-09-19 01:30:07 +02:00
}
break ;
}
2021-12-16 02:15:09 +01:00
if ( str = = " \\ $size " | | str = = " \\ $bits " | | str = = " \\ $high " | | str = = " \\ $low " | | str = = " \\ $left " | | str = = " \\ $right " ) {
2022-05-20 21:46:39 +02:00
width_hint = max ( width_hint , 32 ) ;
2021-12-16 02:15:09 +01:00
break ;
}
2021-02-12 20:25:34 +01:00
if ( current_scope . count ( str ) )
{
// This width detection is needed for function calls which are
2022-05-30 22:45:39 +02:00
// unelaborated, which currently applies to calls to functions
// reached via unevaluated ternary branches or used in case or case
// item expressions.
2021-02-12 20:25:34 +01:00
const AstNode * func = current_scope . at ( str ) ;
if ( func - > type ! = AST_FUNCTION )
2025-09-12 08:03:05 +02:00
input_error ( " Function call to %s resolved to something that isn't a function! \n " , RTLIL : : unescape_id ( str ) ) ;
2021-02-12 20:25:34 +01:00
const AstNode * wire = nullptr ;
2025-06-16 22:55:24 +02:00
for ( const auto & child : func - > children )
2021-02-12 20:25:34 +01:00
if ( child - > str = = func - > str ) {
2025-06-16 22:55:24 +02:00
wire = child . get ( ) ;
2021-02-12 20:25:34 +01:00
break ;
}
log_assert ( wire & & wire - > type = = AST_WIRE ) ;
2022-05-30 22:45:39 +02:00
sign_hint & = wire - > is_signed ;
int result_width = 1 ;
2021-02-12 20:25:34 +01:00
if ( ! wire - > children . empty ( ) )
{
log_assert ( wire - > children . size ( ) = = 1 ) ;
2025-06-16 22:55:24 +02:00
const AstNode * range = wire - > children . at ( 0 ) . get ( ) ;
2021-02-12 20:25:34 +01:00
log_assert ( range - > type = = AST_RANGE & & range - > children . size ( ) = = 2 ) ;
2025-06-16 22:55:24 +02:00
auto left = range - > children . at ( 0 ) - > clone ( ) ;
auto right = range - > children . at ( 1 ) - > clone ( ) ;
2023-04-05 11:00:07 +02:00
left - > set_in_param_flag ( true ) ;
right - > set_in_param_flag ( true ) ;
2023-04-04 22:59:44 +02:00
while ( left - > simplify ( true , 1 , - 1 , false ) ) { }
while ( right - > simplify ( true , 1 , - 1 , false ) ) { }
2021-02-12 20:25:34 +01:00
if ( left - > type ! = AST_CONSTANT | | right - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Function %s has non-constant width! " ,
2025-09-17 01:12:14 +02:00
RTLIL : : unescape_id ( str ) ) ;
2022-05-30 22:45:39 +02:00
result_width = abs ( int ( left - > asInt ( true ) - right - > asInt ( true ) ) ) ;
2021-02-12 20:25:34 +01:00
}
2022-05-30 22:45:39 +02:00
width_hint = max ( width_hint , result_width ) ;
2021-02-12 20:25:34 +01:00
break ;
}
2020-05-04 21:12:30 +02:00
YS_FALLTHROUGH
2016-07-27 15:41:22 +02:00
2013-07-09 14:31:57 +02:00
// everything should have been handled above -> print error if not.
default :
2021-10-20 09:07:22 +02:00
AstNode * current_scope_ast = current_ast_mod = = nullptr ? current_ast : current_ast_mod ;
2013-07-09 14:31:57 +02:00
for ( auto f : log_files )
2021-10-20 09:07:22 +02:00
current_scope_ast - > dumpAst ( f , " verilog-ast> " ) ;
2025-09-12 08:03:05 +02:00
input_error ( " Don't know how to detect sign and width for %s node! \n " , type2str ( type ) ) ;
2025-06-16 22:55:24 +02:00
2013-07-09 14:31:57 +02:00
}
2014-06-21 21:41:13 +02:00
if ( * found_real )
sign_hint = true ;
2013-07-09 14:31:57 +02:00
}
// detect sign and width of an expression
2014-06-16 15:00:57 +02:00
void AstNode : : detectSignWidth ( int & width_hint , bool & sign_hint , bool * found_real )
2013-07-09 14:31:57 +02:00
{
2014-06-16 15:00:57 +02:00
width_hint = - 1 ;
sign_hint = true ;
if ( found_real )
* found_real = false ;
detectSignWidthWorker ( width_hint , sign_hint , found_real ) ;
2021-03-04 21:08:16 +01:00
constexpr int kWidthLimit = 1 < < 24 ;
if ( width_hint > = kWidthLimit )
2023-04-04 11:53:50 +02:00
input_error ( " Expression width %d exceeds implementation limit of %d! \n " ,
width_hint , kWidthLimit ) ;
2013-07-09 14:31:57 +02:00
}
2013-01-05 11:13:26 +01: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 14:31:57 +02:00
RTLIL : : SigSpec AstNode : : genRTLIL ( int width_hint , bool sign_hint )
2013-01-05 11:13:26 +01: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 10:56:05 +02:00
// be instantiated for this type of AST node.
2020-04-02 18:51:32 +02:00
IdString type_name ;
2013-01-05 11:13:26 +01:00
switch ( type )
{
// simply ignore this nodes.
2015-08-14 10:56:05 +02:00
// they are either leftovers from simplify() or are referenced by other nodes
2013-01-05 11:13:26 +01:00
// and are only accessed here thru this references
2016-08-21 13:23:58 +02:00
case AST_NONE :
2013-01-05 11:13:26 +01:00
case AST_TASK :
case AST_FUNCTION :
2014-08-21 12:43:51 +02:00
case AST_DPI_FUNCTION :
2013-01-05 11:13:26 +01:00
case AST_AUTOWIRE :
2013-07-04 14:12:33 +02:00
case AST_DEFPARAM :
2013-01-05 11:13:26 +01:00
case AST_GENVAR :
case AST_GENFOR :
2013-03-26 09:44:54 +01:00
case AST_GENBLOCK :
2013-01-05 11:13:26 +01:00
case AST_GENIF :
2013-12-04 21:06:54 +01:00
case AST_GENCASE :
2016-06-18 10:24:21 +02:00
case AST_PACKAGE :
2025-08-04 05:31:54 +02:00
case AST_IMPORT :
2018-03-09 13:47:11 +01:00
case AST_ENUM :
2018-10-12 20:58:37 +02:00
case AST_MODPORT :
case AST_MODPORTMEMBER :
2019-09-19 21:43:13 +02:00
case AST_TYPEDEF :
2020-05-08 15:40:49 +02:00
case AST_STRUCT :
2020-05-12 15:25:33 +02:00
case AST_UNION :
2013-01-05 11:13:26 +01:00
break ;
2018-10-11 23:33:31 +02:00
case AST_INTERFACEPORT : {
2018-10-13 20:34:44 +02:00
// If a port in a module with unknown type is found, mark it with the attribute 'is_interface'
2018-10-11 23:33:31 +02:00
// This is used by the hierarchy pass to know when it can replace interface connection with the individual
// signals.
2021-02-27 00:08:23 +01:00
RTLIL : : IdString id = str ;
check_unique_id ( current_module , id , this , " interface port " ) ;
RTLIL : : Wire * wire = current_module - > addWire ( id , 1 ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2018-10-11 23:33:31 +02:00
wire - > start_offset = 0 ;
wire - > port_id = port_id ;
wire - > port_input = true ;
wire - > port_output = true ;
2020-03-12 20:57:01 +01:00
wire - > set_bool_attribute ( ID : : is_interface ) ;
2018-10-12 20:58:37 +02:00
if ( children . size ( ) > 0 ) {
for ( size_t i = 0 ; i < children . size ( ) ; i + + ) {
if ( children [ i ] - > type = = AST_INTERFACEPORTTYPE ) {
2018-10-20 12:45:51 +02:00
std : : pair < std : : string , std : : string > res = AST : : split_modport_from_type ( children [ i ] - > str ) ;
2020-04-02 18:51:32 +02:00
wire - > attributes [ ID : : interface_type ] = res . first ;
2018-10-20 12:45:51 +02:00
if ( res . second ! = " " )
2020-04-02 18:51:32 +02:00
wire - > attributes [ ID : : interface_modport ] = res . second ;
2018-10-12 20:58:37 +02:00
break ;
}
}
}
2018-10-11 23:33:31 +02:00
wire - > upto = 0 ;
}
break ;
case AST_INTERFACEPORTTYPE :
break ;
2013-01-05 11:13:26 +01:00
2013-11-24 20:29:07 +01:00
// remember the parameter, needed for example in techmap
case AST_PARAMETER :
2020-04-16 15:51:03 +02: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 21:12:30 +02:00
YS_FALLTHROUGH
2019-06-19 14:38:50 +02:00
case AST_LOCALPARAM :
if ( flag_pwires )
{
if ( GetSize ( children ) < 1 | | children [ 0 ] - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Parameter `%s' with non-constant value! \n " , str ) ;
2019-06-19 14:38:50 +02:00
RTLIL : : Const val = children [ 0 ] - > bitsAsConst ( ) ;
2021-02-27 00:08:23 +01:00
RTLIL : : IdString id = str ;
check_unique_id ( current_module , id , this , " pwire " ) ;
RTLIL : : Wire * wire = current_module - > addWire ( id , GetSize ( val ) ) ;
2019-06-19 14:38:50 +02:00
current_module - > connect ( wire , val ) ;
2021-02-06 01:38:10 +01:00
wire - > is_signed = children [ 0 ] - > is_signed ;
2019-06-19 14:38:50 +02:00
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2020-04-02 18:51:32 +02:00
wire - > attributes [ type = = AST_PARAMETER ? ID : : parameter : ID : : localparam ] = 1 ;
2019-06-19 14:38:50 +02:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2019-06-19 14:38:50 +02:00
wire - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
}
}
2013-11-24 20:29:07 +01:00
break ;
2013-01-05 11:13:26 +01:00
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE : {
if ( ! range_valid )
2025-09-12 08:03:05 +02:00
input_error ( " Signal `%s' with non-constant width! \n " , str ) ;
2013-01-05 11:13:26 +01:00
2020-05-18 18:15:03 +02:00
if ( ! ( range_left + 1 > = range_right ) )
2025-09-12 08:03:05 +02:00
input_error ( " Signal `%s' with invalid width range %d! \n " , str , range_left - range_right + 1 ) ;
2013-01-05 11:13:26 +01:00
2021-02-27 00:08:23 +01:00
RTLIL : : IdString id = str ;
check_unique_id ( current_module , id , this , " signal " ) ;
RTLIL : : Wire * wire = current_module - > addWire ( id , range_left - range_right + 1 ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2013-01-05 11:13:26 +01:00
wire - > start_offset = range_right ;
wire - > port_id = port_id ;
wire - > port_input = is_input ;
wire - > port_output = is_output ;
2014-07-28 14:25:03 +02:00
wire - > upto = range_swapped ;
2025-05-06 12:02:00 +02:00
2020-04-27 18:44:24 +02:00
wire - > is_signed = is_signed ;
2013-01-05 11:13:26 +01:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
wire - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
2019-05-23 10:16:41 +02:00
2020-03-12 20:57:01 +01:00
if ( is_wand ) wire - > set_bool_attribute ( ID : : wand ) ;
if ( is_wor ) wire - > set_bool_attribute ( ID : : wor ) ;
2013-01-05 11:13:26 +01:00
}
break ;
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY : {
2014-07-28 11:08:55 +02:00
log_assert ( children . size ( ) > = 2 ) ;
log_assert ( children [ 0 ] - > type = = AST_RANGE ) ;
log_assert ( children [ 1 ] - > type = = AST_RANGE ) ;
2013-01-05 11:13:26 +01:00
if ( ! children [ 0 ] - > range_valid | | ! children [ 1 ] - > range_valid )
2025-09-12 08:03:05 +02:00
input_error ( " Memory `%s' with non-constant width or size! \n " , str ) ;
2013-01-05 11:13:26 +01:00
RTLIL : : Memory * memory = new RTLIL : : Memory ;
2021-02-23 19:22:53 +01:00
set_src_attr ( memory , this ) ;
2013-01-05 11:13:26 +01:00
memory - > name = str ;
memory - > width = children [ 0 ] - > range_left - children [ 0 ] - > range_right + 1 ;
2015-01-01 12:56:01 +01: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 ;
}
2021-02-27 00:08:23 +01:00
check_unique_id ( current_module , memory - > name , this , " memory " ) ;
2013-01-05 11:13:26 +01:00
current_module - > memories [ memory - > name ] = memory ;
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
memory - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
}
break ;
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
case AST_CONSTANT :
2019-02-13 12:36:47 +01:00
case AST_REALVALUE :
2013-01-05 11:13:26 +01:00
{
2013-07-09 14:31:57 +02:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
is_signed = sign_hint ;
2013-01-05 11:13:26 +01:00
2019-05-27 11:42:10 +02:00
if ( type = = AST_CONSTANT ) {
if ( is_unsized ) {
return RTLIL : : SigSpec ( bitsAsUnsizedConst ( width_hint ) ) ;
} else {
return RTLIL : : SigSpec ( bitsAsConst ( ) ) ;
}
}
2019-02-13 12:36:47 +01:00
2014-06-14 20:38:05 +02:00
RTLIL : : SigSpec sig = realAsConst ( width_hint ) ;
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " converting real value %e to binary %s. \n " , realvalue , log_signal ( sig ) ) ;
2014-06-14 20:38:05 +02:00
return sig ;
2014-06-14 07:44:19 +02:00
}
2013-01-05 11:13:26 +01: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 :
{
2025-06-16 22:55:24 +02:00
RTLIL : : Wire * wire = nullptr ;
2013-06-10 13:19:04 +02:00
RTLIL : : SigChunk chunk ;
2018-10-11 23:33:31 +02:00
bool is_interface = false ;
2013-06-10 13:19:04 +02:00
2025-06-16 22:55:24 +02:00
AST : : AstNode * member_node = nullptr ;
2014-07-28 16:09:50 +02:00
int add_undef_bits_msb = 0 ;
int add_undef_bits_lsb = 0 ;
2020-04-15 20:36:40 +02:00
log_assert ( id2ast ! = nullptr ) ;
if ( id2ast - > type = = AST_AUTOWIRE & & current_module - > wires_ . count ( str ) = = 0 ) {
2014-07-26 20:12:50 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( str ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2013-01-05 11:13:26 +01:00
wire - > name = str ;
2020-04-20 17:06:53 +02:00
// If we are currently processing a bind directive which wires up
// signals or parameters explicitly, rather than with .*, then
// current_module will start out empty and we don't want to warn the
// user about it: we'll spot broken wiring later, when we run the
// hierarchy pass.
if ( dynamic_cast < RTLIL : : Binding * > ( current_module ) ) {
/* nothing to do here */
} else if ( flag_autowire )
2025-09-17 01:03:45 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Identifier `%s' is implicitly declared. \n " , str ) ;
2014-02-17 14:28:52 +01:00
else
2025-09-12 08:03:05 +02:00
input_error ( " Identifier `%s' is implicitly declared and `default_nettype is set to none. \n " , str ) ;
2013-01-05 11:13:26 +01:00
}
2018-03-09 13:47:11 +01:00
else if ( id2ast - > type = = AST_PARAMETER | | id2ast - > type = = AST_LOCALPARAM | | id2ast - > type = = AST_ENUM_ITEM ) {
2013-11-07 14:08:53 +01:00
if ( id2ast - > children [ 0 ] - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Parameter %s does not evaluate to constant value! \n " , str ) ;
2013-06-10 13:56:03 +02:00
chunk = RTLIL : : Const ( id2ast - > children [ 0 ] - > bits ) ;
2013-06-10 13:19:04 +02:00
goto use_const_chunk ;
}
2020-04-15 20:36:40 +02:00
else if ( ( id2ast - > type = = AST_WIRE | | id2ast - > type = = AST_AUTOWIRE | | id2ast - > type = = AST_MEMORY ) & & current_module - > wires_ . count ( str ) ! = 0 ) {
2018-10-11 23:33:31 +02:00
RTLIL : : Wire * current_wire = current_module - > wire ( str ) ;
2020-03-12 20:57:01 +01:00
if ( current_wire - > get_bool_attribute ( ID : : is_interface ) )
2018-10-11 23:33:31 +02: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 {
2025-09-12 08:03:05 +02:00
input_error ( " Identifier `%s' doesn't map to any signal! \n " , str ) ;
2018-10-11 23:33:31 +02:00
}
2013-01-05 11:13:26 +01:00
if ( id2ast - > type = = AST_MEMORY )
2025-09-12 08:03:05 +02:00
input_error ( " Identifier `%s' does map to an unexpanded memory! \n " , str ) ;
2013-01-05 11:13:26 +01:00
2018-10-13 20:34:44 +02:00
// If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface'
2018-10-11 23:33:31 +02: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 ) {
2025-08-20 00:45:26 +02:00
IdString dummy_wire_name = stringf ( " $dummywireforinterface%s " , str ) ;
2020-04-02 18:51:32 +02:00
RTLIL : : Wire * dummy_wire = current_module - > wire ( dummy_wire_name ) ;
if ( ! dummy_wire ) {
2018-10-11 23:33:31 +02:00
dummy_wire = current_module - > addWire ( dummy_wire_name ) ;
2020-03-12 20:57:01 +01:00
dummy_wire - > set_bool_attribute ( ID : : is_interface ) ;
2018-10-11 23:33:31 +02:00
}
2020-04-02 18:51:32 +02:00
return dummy_wire ;
2018-10-11 23:33:31 +02:00
}
2014-07-27 01:49:51 +02:00
wire = current_module - > wires_ [ str ] ;
2013-01-05 11:13:26 +01:00
chunk . wire = wire ;
chunk . width = wire - > width ;
chunk . offset = 0 ;
2024-01-25 07:28:15 +01:00
if ( ( member_node = get_struct_member ( ) ) ) {
2023-02-28 18:45:55 +01:00
// Clamp wire chunk to range of member within struct/union.
chunk . width = member_node - > range_left - member_node - > range_right + 1 ;
chunk . offset = member_node - > range_right ;
}
2013-06-10 13:19:04 +02:00
use_const_chunk :
2013-01-05 11:13:26 +01:00
if ( children . size ( ) ! = 0 ) {
2018-10-02 09:44:23 +02:00
if ( children [ 0 ] - > type ! = AST_RANGE )
2023-04-04 11:53:50 +02:00
input_error ( " Single range expected. \n " ) ;
2014-07-28 16:45:26 +02:00
int source_width = id2ast - > range_left - id2ast - > range_right + 1 ;
int source_offset = id2ast - > range_right ;
2023-02-28 18:45:55 +01:00
int chunk_left = source_width - 1 ;
int chunk_right = 0 ;
if ( member_node ) {
// Clamp wire chunk to range of member within struct/union.
log_assert ( ! source_offset & & ! id2ast - > range_swapped ) ;
chunk_left = chunk . offset + chunk . width - 1 ;
chunk_right = chunk . offset ;
2023-02-19 23:25:08 +01:00
}
2013-01-05 11:13:26 +01:00
if ( ! children [ 0 ] - > range_valid ) {
2025-06-16 22:55:24 +02:00
auto left_at_zero_ast = children [ 0 ] - > children [ 0 ] - > clone_at_zero ( ) ;
auto right_at_zero_ast = children [ 0 ] - > children . size ( ) > = 2 ? children [ 0 ] - > children [ 1 ] - > clone_at_zero ( ) : left_at_zero_ast - > clone ( ) ;
2023-04-04 22:59:44 +02:00
while ( left_at_zero_ast - > simplify ( true , 1 , - 1 , false ) ) { }
while ( right_at_zero_ast - > simplify ( true , 1 , - 1 , false ) ) { }
2013-01-05 11:13:26 +01:00
if ( left_at_zero_ast - > type ! = AST_CONSTANT | | right_at_zero_ast - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Unsupported expression on dynamic range select on signal `%s'! \n " , str ) ;
2019-02-21 18:40:11 +01:00
int width = abs ( int ( left_at_zero_ast - > integer - right_at_zero_ast - > integer ) ) + 1 ;
2025-06-18 22:50:46 +02:00
auto fake_ast = std : : make_unique < AstNode > ( children [ 0 ] - > location , AST_NONE , clone ( ) , children [ 0 ] - > children . size ( ) > = 2 ?
2013-01-05 11:13:26 +01:00
children [ 0 ] - > children [ 1 ] - > clone ( ) : children [ 0 ] - > children [ 0 ] - > clone ( ) ) ;
fake_ast - > children [ 0 ] - > delete_children ( ) ;
2023-02-28 18:45:55 +01:00
if ( member_node )
2023-04-05 11:00:07 +02:00
fake_ast - > children [ 0 ] - > set_attribute ( ID : : wiretype , member_node - > clone ( ) ) ;
2020-05-01 17:25:33 +02: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 ) ;
2023-02-28 18:45:55 +01:00
if ( source_offset ! = 0 ) {
shift_val = current_module - > Sub ( NEW_ID , shift_val , source_offset , fake_ast_sign ) ;
2014-07-29 14:42:33 +02:00
fake_ast - > children [ 1 ] - > is_signed = true ;
}
if ( id2ast - > range_swapped ) {
2020-05-01 17:25:33 +02:00
shift_val = current_module - > Sub ( NEW_ID , RTLIL : : SigSpec ( source_width - width ) , shift_val , fake_ast_sign ) ;
2014-07-29 14:42:33 +02:00
fake_ast - > children [ 1 ] - > is_signed = true ;
}
2014-10-10 16:59:44 +02:00
if ( GetSize ( shift_val ) > = 32 )
2014-07-29 14:42:33 +02:00
fake_ast - > children [ 1 ] - > is_signed = true ;
2025-06-17 15:25:57 +02:00
RTLIL : : SigSpec sig = binop2rtlil ( fake_ast . get ( ) , ID ( $ shiftx ) , width , fake_ast - > children [ 0 ] - > genRTLIL ( ) , shift_val ) ;
2013-01-05 11:13:26 +01:00
return sig ;
} else {
2014-07-28 14:25:03 +02:00
chunk . width = children [ 0 ] - > range_left - children [ 0 ] - > range_right + 1 ;
2023-02-28 18:45:55 +01:00
chunk . offset + = children [ 0 ] - > range_right - source_offset ;
2014-07-28 15:31:19 +02:00
if ( id2ast - > range_swapped )
2023-02-28 18:45:55 +01:00
chunk . offset = source_width - ( chunk . offset + chunk . width ) ;
if ( chunk . offset > chunk_left | | chunk . offset + chunk . width < chunk_right ) {
2014-07-28 16:09:50 +02:00
if ( chunk . width = = 1 )
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Range select out of bounds on signal `%s': Setting result bit to undef. \n " ,
2018-11-04 10:19:32 +01:00
str . c_str ( ) ) ;
2014-07-28 16:09:50 +02:00
else
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef. \n " ,
2018-10-20 23:48:53 +02:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , chunk . width ) ;
2014-07-28 16:09:50 +02:00
chunk = RTLIL : : SigChunk ( RTLIL : : State : : Sx , chunk . width ) ;
} else {
2023-02-28 18:45:55 +01:00
if ( chunk . offset + chunk . width - 1 > chunk_left ) {
add_undef_bits_msb = ( chunk . offset + chunk . width - 1 ) - chunk_left ;
2014-07-28 16:09:50 +02:00
chunk . width - = add_undef_bits_msb ;
}
2023-02-28 18:45:55 +01:00
if ( chunk . offset < chunk_right ) {
add_undef_bits_lsb = chunk_right - chunk . offset ;
2014-07-28 16:09:50 +02:00
chunk . width - = add_undef_bits_lsb ;
chunk . offset + = add_undef_bits_lsb ;
}
if ( add_undef_bits_lsb )
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef. \n " ,
2018-11-04 10:19:32 +01:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , add_undef_bits_lsb ) ;
2014-07-28 16:09:50 +02:00
if ( add_undef_bits_msb )
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef. \n " ,
2018-11-04 10:19:32 +01:00
children [ 0 ] - > range_left , children [ 0 ] - > range_right , str . c_str ( ) , add_undef_bits_msb ) ;
2014-07-28 16:09:50 +02:00
}
2013-01-05 11:13:26 +01:00
}
}
2014-07-28 16:09:50 +02: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 11:13:26 +01:00
2014-08-14 23:02:07 +02:00
if ( genRTLIL_subst_ptr )
sig . replace ( * genRTLIL_subst_ptr ) ;
2013-01-05 11:13:26 +01:00
2013-07-09 14:31:57 +02:00
is_signed = children . size ( ) > 0 ? false : id2ast - > is_signed & & sign_hint ;
2013-01-05 11:13:26 +01:00
return sig ;
}
2013-11-07 19:19:53 +01:00
// just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly
2013-01-05 11:13:26 +01:00
case AST_TO_SIGNED :
2020-04-29 14:28:04 +02:00
case AST_TO_UNSIGNED :
case AST_SELFSZ : {
2013-11-07 03:01:28 +01:00
RTLIL : : SigSpec sig = children [ 0 ] - > genRTLIL ( ) ;
2014-07-22 20:15:14 +02:00
if ( sig . size ( ) < width_hint )
2013-11-07 18:17:10 +01:00
sig . extend_u0 ( width_hint , sign_hint ) ;
2013-07-11 19:24:59 +02:00
is_signed = sign_hint ;
2013-01-05 11:13:26 +01:00
return sig ;
}
2020-06-15 00:15:59 +02:00
// changing the size of signal can be done directly using RTLIL::SigSpec
case AST_CAST_SIZE : {
RTLIL : : SigSpec size = children [ 0 ] - > genRTLIL ( ) ;
if ( ! size . is_fully_const ( ) )
2023-04-04 11:53:50 +02:00
input_error ( " Static cast with non constant expression! \n " ) ;
2020-06-15 00:15:59 +02:00
int width = size . as_int ( ) ;
if ( width < = 0 )
2023-04-04 11:53:50 +02:00
input_error ( " Static cast with zero or negative size! \n " ) ;
2022-01-06 07:33:08 +01:00
// determine the *signedness* of the expression
int sub_width_hint = - 1 ;
bool sub_sign_hint = true ;
children [ 1 ] - > detectSignWidth ( sub_width_hint , sub_sign_hint ) ;
// generate the signal given the *cast's* size and the
// *expression's* signedness
RTLIL : : SigSpec sig = children [ 1 ] - > genWidthRTLIL ( width , sub_sign_hint ) ;
// context may effect this node's signedness, but not that of the
// casted expression
2020-06-15 00:15:59 +02:00
is_signed = sign_hint ;
return sig ;
}
2013-01-05 11:13:26 +01:00
// concatenation of signals can be done directly using RTLIL::SigSpec
case AST_CONCAT : {
RTLIL : : SigSpec sig ;
2014-07-22 20:39:13 +02:00
for ( auto it = children . begin ( ) ; it ! = children . end ( ) ; it + + )
sig . append ( ( * it ) - > genRTLIL ( ) ) ;
2014-07-22 20:15:14 +02:00
if ( sig . size ( ) < width_hint )
2013-11-07 18:17:10 +01:00
sig . extend_u0 ( width_hint , false ) ;
2013-01-05 11:13:26 +01: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 ( ) )
2023-04-04 11:53:50 +02:00
input_error ( " Left operand of replicate expression is not constant! \n " ) ;
2013-01-05 11:13:26 +01:00
int count = left . as_int ( ) ;
RTLIL : : SigSpec sig ;
for ( int i = 0 ; i < count ; i + + )
sig . append ( right ) ;
2014-07-22 20:15:14 +02:00
if ( sig . size ( ) < width_hint )
2013-11-07 18:17:10 +01:00
sig . extend_u0 ( width_hint , false ) ;
2013-01-05 11:13:26 +01:00
is_signed = false ;
return sig ;
}
// generate cells for unary operations: $not, $pos, $neg
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
{
2013-07-09 14:31:57 +02:00
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
is_signed = children [ 0 ] - > is_signed ;
2014-07-22 20:15:14 +02:00
int width = arg . size ( ) ;
2013-07-09 14:31:57 +02:00
if ( width_hint > 0 ) {
2013-01-05 11:13:26 +01:00
width = width_hint ;
2014-09-04 02:07:52 +02:00
widthExtend ( this , arg , width , is_signed ) ;
2013-07-09 14:31:57 +02:00
}
2013-01-05 11:13:26 +01:00
return uniop2rtlil ( this , type_name , width , arg ) ;
}
// generate cells for binary operations: $and, $or, $xor, $xnor
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
{
2013-07-09 23:41:28 +02:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
2013-07-09 14:31:57 +02:00
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2015-10-25 19:30:49 +01:00
int width = max ( left . size ( ) , right . size ( ) ) ;
2013-06-13 11:18:45 +02:00
if ( width_hint > 0 )
2013-06-10 17:10:06 +02:00
width = width_hint ;
2013-07-09 23:53:55 +02:00
is_signed = children [ 0 ] - > is_signed & & children [ 1 ] - > is_signed ;
2013-01-05 11:13:26 +01: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 18:51:32 +02: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 11:13:26 +01:00
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2015-10-25 19:30:49 +01:00
RTLIL : : SigSpec sig = uniop2rtlil ( this , type_name , max ( width_hint , 1 ) , arg ) ;
2013-01-05 11:13:26 +01:00
return sig ;
}
// generate cells for unary operations: $reduce_bool
2015-08-14 10:56:05 +02:00
// (this is actually just an $reduce_or, but for clarity a different cell type is used)
2020-04-02 18:51:32 +02:00
if ( 0 ) { case AST_REDUCE_BOOL : type_name = ID ( $ reduce_bool ) ; }
2013-01-05 11:13:26 +01:00
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2015-10-25 19:30:49 +01:00
RTLIL : : SigSpec sig = arg . size ( ) > 1 ? uniop2rtlil ( this , type_name , max ( width_hint , 1 ) , arg ) : arg ;
2013-01-05 11:13:26 +01:00
return sig ;
}
// generate cells for binary operations: $shl, $shr, $sshl, $sshr
2020-04-02 18:51:32 +02: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 17:04:47 +02:00
if ( 0 ) { case AST_SHIFTX : type_name = ID ( $ shiftx ) ; }
if ( 0 ) { case AST_SHIFT : type_name = ID ( $ shift ) ; }
2013-01-05 11:13:26 +01:00
{
2013-07-09 14:31:57 +02:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
2023-11-27 15:28:06 +01:00
// for $shift and $shiftx, the second operand can be negative
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( - 1 , type = = AST_SHIFT | | type = = AST_SHIFTX ) ;
2014-07-22 20:15:14 +02:00
int width = width_hint > 0 ? width_hint : left . size ( ) ;
2013-07-09 14:31:57 +02:00
is_signed = children [ 0 ] - > is_signed ;
2013-01-05 11:13:26 +01:00
return binop2rtlil ( this , type_name , width , left , right ) ;
}
2013-11-07 22:20:00 +01: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 20:15:14 +02:00
int width = width_hint > 0 ? width_hint : left . size ( ) ;
2013-11-07 22:20:00 +01:00
is_signed = children [ 0 ] - > is_signed ;
if ( ! flag_noopt & & left . is_fully_const ( ) & & left . as_int ( ) = = 2 & & ! right_signed )
2020-04-02 18:51:32 +02:00
return binop2rtlil ( this , ID ( $ shl ) , width , RTLIL : : SigSpec ( 1 , left . size ( ) ) , right ) ;
return binop2rtlil ( this , ID ( $ pow ) , width , left , right ) ;
2013-11-07 22:20:00 +01:00
}
2013-01-05 11:13:26 +01:00
// generate cells for binary operations: $lt, $le, $eq, $ne, $ge, $gt
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
{
2015-10-25 19:30:49 +01:00
int width = max ( width_hint , 1 ) ;
2013-07-09 14:31:57 +02: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 20:50:53 +01:00
RTLIL : : SigSpec sig = binop2rtlil ( this , type_name , width , left , right ) ;
2013-01-05 11:13:26 +01:00
return sig ;
}
2013-11-07 22:20:00 +01:00
// generate cells for binary operations: $add, $sub, $mul, $div, $mod
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
{
2013-07-09 14:31:57 +02:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-11-07 22:20:00 +01:00
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-11-08 11:40:36 +01:00
#if 0
2015-10-25 19:30:49 +01:00
int width = max ( left . size ( ) , right . size ( ) ) ;
2013-01-05 11:13:26 +01:00
if ( width > width_hint & & width_hint > 0 )
width = width_hint ;
if ( width < width_hint ) {
2013-08-09 17:09:24 +02:00
if ( type = = AST_ADD | | type = = AST_SUB | | type = = AST_DIV )
2013-01-05 11:13:26 +01:00
width + + ;
2013-07-09 23:41:28 +02:00
if ( type = = AST_SUB & & ( ! children [ 0 ] - > is_signed | | ! children [ 1 ] - > is_signed ) )
2013-01-05 11:13:26 +01:00
width = width_hint ;
if ( type = = AST_MUL )
2015-10-25 19:30:49 +01:00
width = min ( left . size ( ) + right . size ( ) , width_hint ) ;
2013-01-05 11:13:26 +01:00
}
2013-11-08 11:40:36 +01:00
# else
2015-10-25 19:30:49 +01:00
int width = max ( max ( left . size ( ) , right . size ( ) ) , width_hint ) ;
2013-11-08 11:40:36 +01:00
# endif
2013-07-09 14:31:57 +02:00
is_signed = children [ 0 ] - > is_signed & & children [ 1 ] - > is_signed ;
2013-01-05 11:13:26 +01:00
return binop2rtlil ( this , type_name , width , left , right ) ;
}
// generate cells for binary operations: $logic_and, $logic_or
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
{
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( ) ;
RTLIL : : SigSpec right = children [ 1 ] - > genRTLIL ( ) ;
2015-10-25 19:30:49 +01:00
return binop2rtlil ( this , type_name , max ( width_hint , 1 ) , left , right ) ;
2013-01-05 11:13:26 +01:00
}
// generate cells for unary operations: $logic_not
case AST_LOGIC_NOT :
{
RTLIL : : SigSpec arg = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 18:51:32 +02:00
return uniop2rtlil ( this , ID ( $ logic_not ) , max ( width_hint , 1 ) , arg ) ;
2013-01-05 11:13:26 +01:00
}
// generate multiplexer for ternary operator (aka ?:-operator)
case AST_TERNARY :
{
2013-07-12 13:13:04 +02:00
if ( width_hint < 0 )
detectSignWidth ( width_hint , sign_hint ) ;
2020-04-14 21:05:07 +02:00
is_signed = sign_hint ;
2013-07-12 13:13:04 +02:00
2013-01-05 11:13:26 +01:00
RTLIL : : SigSpec cond = children [ 0 ] - > genRTLIL ( ) ;
2020-02-28 01:55:55 +01:00
RTLIL : : SigSpec sig ;
2020-04-14 21:05:07 +02:00
if ( cond . is_fully_def ( ) )
{
2020-02-28 01:55:55 +01:00
if ( cond . as_bool ( ) ) {
sig = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
2020-04-14 21:05:07 +02:00
log_assert ( is_signed = = children [ 1 ] - > is_signed ) ;
} else {
2020-02-28 01:55:55 +01:00
sig = children [ 2 ] - > genRTLIL ( width_hint , sign_hint ) ;
2020-04-14 21:05:07 +02:00
log_assert ( is_signed = = children [ 2 ] - > is_signed ) ;
2020-02-28 01:55:55 +01:00
}
2020-04-14 21:05:07 +02:00
widthExtend ( this , sig , sig . size ( ) , is_signed ) ;
2020-02-28 01:55:55 +01:00
}
2020-04-14 21:05:07 +02:00
else
{
2020-02-28 01:55:55 +01:00
RTLIL : : SigSpec val1 = children [ 1 ] - > genRTLIL ( width_hint , sign_hint ) ;
RTLIL : : SigSpec val2 = children [ 2 ] - > genRTLIL ( width_hint , sign_hint ) ;
2013-01-05 11:13:26 +01:00
2020-02-28 01:55:55 +01:00
if ( cond . size ( ) > 1 )
2020-04-02 18:51:32 +02:00
cond = uniop2rtlil ( this , ID ( $ reduce_bool ) , 1 , cond , false ) ;
2013-01-05 11:13:26 +01:00
2020-02-28 01:55:55 +01:00
int width = max ( val1 . size ( ) , val2 . size ( ) ) ;
2020-04-14 21:05:07 +02:00
log_assert ( is_signed = = children [ 1 ] - > is_signed ) ;
log_assert ( is_signed = = children [ 2 ] - > is_signed ) ;
2020-02-28 01:55:55 +01:00
widthExtend ( this , val1 , width , is_signed ) ;
widthExtend ( this , val2 , width , is_signed ) ;
2013-01-05 11:13:26 +01:00
2020-02-28 01:55:55 +01:00
sig = mux2rtlil ( this , cond , val1 , val2 ) ;
}
2013-11-07 18:17:10 +01:00
2014-07-22 20:15:14 +02:00
if ( sig . size ( ) < width_hint )
2013-11-07 18:17:10 +01:00
sig . extend_u0 ( width_hint , sign_hint ) ;
return sig ;
2013-01-05 11:13:26 +01:00
}
// generate $memrd cells for memory read ports
case AST_MEMRD :
{
std : : stringstream sstr ;
2025-06-18 22:50:46 +02:00
sstr < < " $memrd$ " < < str < < " $ " < < RTLIL : : encode_filename ( * location . begin . filename ) < < " : " < < location . begin . line < < " $ " < < ( autoidx + + ) ;
2013-01-05 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ memrd ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , this ) ;
2013-01-05 11:13:26 +01:00
2014-08-02 13:11:01 +02:00
RTLIL : : Wire * wire = current_module - > addWire ( cell - > name . str ( ) + " _DATA " , current_module - > memories [ str ] - > width ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2013-01-05 11:13:26 +01:00
2015-02-14 14:21:15 +01:00
int mem_width , mem_size , addr_bits ;
2016-11-01 23:17:43 +01:00
is_signed = id2ast - > is_signed ;
2021-02-06 01:38:10 +01:00
wire - > is_signed = is_signed ;
2015-02-14 14:21:15 +01:00
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
2013-01-05 11:13:26 +01:00
2016-08-19 18:38:25 +02:00
RTLIL : : SigSpec addr_sig = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
2018-06-28 16:57:03 +02:00
if ( ! sign_hint )
is_signed = false ;
2013-01-05 11:13:26 +01:00
return RTLIL : : SigSpec ( wire ) ;
}
2021-02-23 16:48:29 +01:00
// generate $meminit cells
2015-02-14 10:49:30 +01:00
case AST_MEMINIT :
2013-01-05 11:13:26 +01:00
{
std : : stringstream sstr ;
2025-06-18 22:50:46 +02:00
sstr < < " $meminit$ " < < str < < " $ " < < RTLIL : : encode_filename ( * location . begin . filename ) < < " : " < < location . begin . line < < " $ " < < ( autoidx + + ) ;
2013-01-05 11:13:26 +01:00
2021-05-21 02:27:06 +02:00
SigSpec en_sig = children [ 2 ] - > genRTLIL ( ) ;
RTLIL : : Cell * cell = current_module - > addCell ( sstr . str ( ) , ID ( $ meminit_v2 ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , this ) ;
2013-01-05 11:13:26 +01:00
2015-02-14 14:21:15 +01:00
int mem_width , mem_size , addr_bits ;
id2ast - > meminfo ( mem_width , mem_size , addr_bits ) ;
2013-01-05 11:13:26 +01:00
2021-05-21 02:27:06 +02:00
if ( children [ 3 ] - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Memory init with non-constant word count! \n " ) ;
2021-05-21 02:27:06 +02:00
int num_words = int ( children [ 3 ] - > asInt ( false ) ) ;
2021-02-23 16:48:29 +01:00
cell - > parameters [ ID : : WORDS ] = RTLIL : : Const ( num_words ) ;
2015-07-31 10:40:09 +02:00
2016-08-19 18:38:25 +02:00
SigSpec addr_sig = children [ 0 ] - > genRTLIL ( ) ;
2020-04-02 18:51:32 +02:00
cell - > setPort ( ID : : ADDR , addr_sig ) ;
2021-03-25 19:06:05 +01:00
cell - > setPort ( ID : : DATA , children [ 1 ] - > genWidthRTLIL ( current_module - > memories [ str ] - > width * num_words , true ) ) ;
2021-05-21 02:27:06 +02:00
cell - > setPort ( ID : : EN , en_sig ) ;
2013-01-05 11:13:26 +01:00
2020-04-02 18:51:32 +02: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 11:13:26 +01:00
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : PRIORITY ] = RTLIL : : Const ( autoidx - 1 ) ;
2013-01-05 11:13:26 +01:00
}
break ;
2024-01-11 10:39:28 +01:00
// generate $check cells
2014-01-19 14:03:40 +01:00
case AST_ASSERT :
2015-02-26 18:47:39 +01:00
case AST_ASSUME :
2017-02-25 10:36:39 +01:00
case AST_LIVE :
case AST_FAIR :
2017-02-04 14:14:26 +01:00
case AST_COVER :
2014-01-19 14:03:40 +01:00
{
2024-01-11 10:39:28 +01:00
std : : string flavor , desc ;
if ( type = = AST_ASSERT ) { flavor = " assert " ; desc = " assert property () " ; }
if ( type = = AST_ASSUME ) { flavor = " assume " ; desc = " assume property () " ; }
if ( type = = AST_LIVE ) { flavor = " live " ; desc = " assert property (eventually) " ; }
if ( type = = AST_FAIR ) { flavor = " fair " ; desc = " assume property (eventually) " ; }
if ( type = = AST_COVER ) { flavor = " cover " ; desc = " cover property () " ; }
2014-01-19 14:03:40 +01:00
2019-03-07 20:17:32 +01:00
IdString cellname ;
2020-04-02 18:51:32 +02:00
if ( str . empty ( ) )
2025-08-20 00:45:26 +02:00
cellname = stringf ( " $%s$%s:%d$%d " , flavor , RTLIL : : encode_filename ( * location . begin . filename ) , location . begin . line , autoidx + + ) ;
2020-04-02 18:51:32 +02:00
else
2019-03-07 20:17:32 +01:00
cellname = str ;
2021-02-27 00:08:23 +01:00
check_unique_id ( current_module , cellname , this , " procedural assertion " ) ;
2014-01-19 14:03:40 +01:00
2024-01-11 10:39:28 +01:00
RTLIL : : SigSpec check = children [ 0 ] - > genRTLIL ( ) ;
if ( GetSize ( check ) ! = 1 )
check = current_module - > ReduceBool ( NEW_ID , check ) ;
RTLIL : : Cell * cell = current_module - > addCell ( cellname , ID ( $ check ) ) ;
set_src_attr ( cell , this ) ;
2014-01-19 14:03:40 +01:00
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Attribute `%s' with non-constant value! \n " , attr . first ) ;
2014-01-19 14:03:40 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
}
2024-01-11 10:39:28 +01:00
cell - > setParam ( ID ( FLAVOR ) , flavor ) ;
cell - > parameters [ ID : : TRG_WIDTH ] = 0 ;
cell - > parameters [ ID : : TRG_ENABLE ] = 0 ;
cell - > parameters [ ID : : TRG_POLARITY ] = 0 ;
cell - > parameters [ ID : : PRIORITY ] = 0 ;
cell - > setPort ( ID : : TRG , RTLIL : : SigSpec ( ) ) ;
cell - > setPort ( ID : : EN , RTLIL : : S1 ) ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : A , check ) ;
2024-01-11 10:39:28 +01:00
// No message is emitted to ensure Verilog code roundtrips correctly.
Fmt fmt ;
fmt . emit_rtlil ( cell ) ;
2014-01-19 14:03:40 +01:00
}
break ;
2013-01-05 11:13:26 +01:00
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN :
{
2015-02-08 00:48:23 +01:00
RTLIL : : SigSpec left = children [ 0 ] - > genRTLIL ( ) ;
2021-03-25 19:06:05 +01:00
RTLIL : : SigSpec right = children [ 1 ] - > genWidthRTLIL ( left . size ( ) , true ) ;
2019-05-27 18:00:22 +02: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 13:42:30 +02:00
new_left . append ( left [ i ] ) ;
2019-05-27 18:00:22 +02:00
new_right . append ( right [ i ] ) ;
2019-05-23 13:42:30 +02:00
}
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Ignoring assignment to constant bits: \n "
2019-05-23 13:42:30 +02: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 18:00:22 +02:00
left = new_left ;
right = new_right ;
}
current_module - > connect ( RTLIL : : SigSig ( left , right ) ) ;
2013-01-05 11:13:26 +01:00
}
break ;
// create an RTLIL::Cell for an AST_CELL
case AST_CELL :
{
int port_counter = 0 , para_counter = 0 ;
2014-07-25 15:05:18 +02:00
2021-02-27 00:08:23 +01:00
RTLIL : : IdString id = str ;
check_unique_id ( current_module , id , this , " cell " ) ;
RTLIL : : Cell * cell = current_module - > addCell ( id , " " ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , this ) ;
2018-10-13 20:34:44 +02:00
// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass
2020-04-02 18:51:32 +02:00
cell - > set_bool_attribute ( ID : : module_not_derived ) ;
2014-07-25 15:05:18 +02:00
2013-01-05 11:13:26 +01:00
for ( auto it = children . begin ( ) ; it ! = children . end ( ) ; it + + ) {
2025-08-08 07:10:16 +02:00
auto * child = it - > get ( ) ;
2013-01-05 11:13:26 +01:00
if ( child - > type = = AST_CELLTYPE ) {
cell - > type = child - > str ;
2019-08-07 21:20:08 +02:00
if ( flag_icells & & cell - > type . begins_with ( " \\ $ " ) )
2014-01-29 00:59:28 +01:00
cell - > type = cell - > type . substr ( 1 ) ;
2013-01-05 11:13:26 +01:00
continue ;
}
if ( child - > type = = AST_PARASET ) {
2015-02-18 23:35:23 +01:00
IdString paraname = child - > str . empty ( ) ? stringf ( " $%d " , + + para_counter ) : child - > str ;
2025-08-08 07:10:16 +02:00
const auto * value = child - > children [ 0 ] . get ( ) ;
2021-10-20 02:46:26 +02:00
if ( value - > type = = AST_REALVALUE )
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " Replacing floating point parameter %s.%s = %f with string. \n " ,
2021-10-20 02:46:26 +02:00
log_id ( cell ) , log_id ( paraname ) , value - > realvalue ) ;
else if ( value - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Parameter %s.%s with non-constant value! \n " ,
2018-11-04 10:19:32 +01:00
log_id ( cell ) , log_id ( paraname ) ) ;
2021-10-20 02:46:26 +02:00
cell - > parameters [ paraname ] = value - > asParaConst ( ) ;
2013-01-05 11:13:26 +01:00
continue ;
}
if ( child - > type = = AST_ARGUMENT ) {
RTLIL : : SigSpec sig ;
2020-12-18 20:59:08 +01:00
if ( child - > children . size ( ) > 0 ) {
2025-08-08 07:10:16 +02:00
auto * arg = child - > children [ 0 ] . get ( ) ;
2020-12-18 20:59:08 +01:00
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
2021-10-20 02:46:26 +02:00
if ( arg - > type = = AST_IDENTIFIER & & arg - > id2ast & & arg - > id2ast - > is_signed & & ! arg - > is_signed )
// fully-sliced signed wire will be resolved
// once the module becomes available
log_assert ( attributes . count ( ID : : reprocess_after ) ) ;
else
log_assert ( arg - > is_signed = = sig . as_wire ( ) - > is_signed ) ;
2020-12-18 20:59:08 +01:00
} 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-06 01:38:10 +01:00
RTLIL : : Wire * wire = current_module - > addWire ( wire_name , GetSize ( sig ) ) ;
2020-12-18 20:59:08 +01:00
wire - > is_signed = true ;
current_module - > connect ( wire , sig ) ;
sig = wire ;
}
}
2013-01-05 11:13:26 +01:00
if ( child - > str . size ( ) = = 0 ) {
char buf [ 100 ] ;
snprintf ( buf , 100 , " $%d " , + + port_counter ) ;
2019-05-27 18:00:22 +02:00
cell - > setPort ( buf , sig ) ;
2013-01-05 11:13:26 +01:00
} else {
2019-05-27 18:00:22 +02:00
cell - > setPort ( child - > str , sig ) ;
2013-01-05 11:13:26 +01:00
}
continue ;
}
2014-07-28 11:08:55 +02:00
log_abort ( ) ;
2013-01-05 11:13:26 +01:00
}
for ( auto & attr : attributes ) {
if ( attr . second - > type ! = AST_CONSTANT )
2025-09-12 08:03:05 +02:00
input_error ( " Attribute `%s' with non-constant value. \n " , attr . first ) ;
2013-12-04 14:14:05 +01:00
cell - > attributes [ attr . first ] = attr . second - > asAttrConst ( ) ;
2013-01-05 11:13:26 +01:00
}
2020-04-02 18:51:32 +02: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-22 02:33:12 +02:00
if ( ! full & & src_width ! = dst_width )
2023-04-04 11:53:50 +02:00
input_error ( " Parallel specify SRC width does not match DST width. \n " ) ;
2020-04-02 18:51:32 +02:00
cell - > setParam ( ID : : SRC_WIDTH , Const ( src_width ) ) ;
cell - > setParam ( ID : : DST_WIDTH , Const ( dst_width ) ) ;
2019-04-23 15:46:40 +02:00
}
2020-04-02 18:51:32 +02: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 21:16:01 +01:00
if ( dat_width ! = dst_width )
2023-04-04 11:53:50 +02:00
input_error ( " Specify DAT width does not match DST width. \n " ) ;
2020-04-02 18:51:32 +02: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 21:16:01 +01:00
}
2020-04-02 18:51:32 +02: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-22 02:33:12 +02:00
}
2013-01-05 11:13:26 +01:00
}
break ;
// use ProcessGenerator for always blocks
2013-03-31 11:51:12 +02:00
case AST_ALWAYS : {
2025-08-08 12:31:40 +02:00
ProcessGenerator generator ( this - > clone ( ) ) ;
2013-03-31 11:51:12 +02:00
ignoreThisSignalsInInitial . append ( generator . outputSignals ) ;
} break ;
case AST_INITIAL : {
2025-06-16 22:55:24 +02:00
auto always = this - > clone ( ) ;
2025-08-08 12:31:40 +02:00
ProcessGenerator generator ( this - > clone ( ) , ignoreThisSignalsInInitial ) ;
2013-01-05 11:13:26 +01:00
} break ;
2019-06-07 12:41:09 +02:00
case AST_TECALL : {
int sz = children . size ( ) ;
if ( str = = " $info " ) {
if ( sz > 0 )
2025-09-17 01:06:28 +02:00
log_file_info ( * location . begin . filename , location . begin . line , " %s. \n " , children [ 0 ] - > str ) ;
2019-06-07 12:41:09 +02:00
else
2025-06-18 22:50:46 +02:00
log_file_info ( * location . begin . filename , location . begin . line , " \n " ) ;
2019-06-07 12:41:09 +02:00
} else if ( str = = " $warning " ) {
if ( sz > 0 )
2025-09-17 01:03:45 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " %s. \n " , children [ 0 ] - > str ) ;
2019-06-07 12:41:09 +02:00
else
2025-06-18 22:50:46 +02:00
log_file_warning ( * location . begin . filename , location . begin . line , " \n " ) ;
2019-06-07 12:41:09 +02:00
} else if ( str = = " $error " ) {
if ( sz > 0 )
2025-09-12 08:03:05 +02:00
input_error ( " %s. \n " , children [ 0 ] - > str ) ;
2019-06-07 12:41:09 +02:00
else
2023-04-04 11:53:50 +02:00
input_error ( " \n " ) ;
2019-06-07 12:41:09 +02: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 )
2025-09-12 08:03:05 +02:00
input_error ( " FATAL: %s. \n " , children [ 0 ] - > str ) ;
2019-06-07 12:41:09 +02:00
else
2023-04-04 11:53:50 +02:00
input_error ( " FATAL. \n " ) ;
2019-06-07 12:41:09 +02:00
} else {
2025-09-12 08:03:05 +02:00
input_error ( " Unknown elaboration system task '%s'. \n " , str ) ;
2019-06-07 12:41:09 +02:00
}
} break ;
2020-05-21 18:36:29 +02:00
case AST_BIND : {
2020-04-20 17:06:53 +02:00
// Read a bind construct. This should have one or more cells as children.
for ( RTLIL : : Binding * binding : genBindings ( ) )
current_module - > add ( binding ) ;
2020-05-21 18:36:29 +02:00
break ;
}
2016-07-27 15:41:22 +02:00
case AST_FCALL : {
2018-02-23 13:14:47 +01:00
if ( str = = " \\ $anyconst " | | str = = " \\ $anyseq " | | str = = " \\ $allconst " | | str = = " \\ $allseq " )
2016-07-27 15:41:22 +02:00
{
2016-08-30 19:09:56 +02:00
string myid = stringf ( " %s$%d " , str . c_str ( ) + 1 , autoidx + + ) ;
2016-07-27 15:41:22 +02:00
int width = width_hint ;
if ( GetSize ( children ) > 1 )
2023-04-04 11:53:50 +02:00
input_error ( " System function %s got %d arguments, expected 1 or 0. \n " ,
2025-09-17 01:12:14 +02:00
RTLIL : : unescape_id ( str ) , GetSize ( children ) ) ;
2016-07-27 15:41:22 +02:00
if ( GetSize ( children ) = = 1 ) {
if ( children [ 0 ] - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " System function %s called with non-const argument! \n " ,
2025-09-17 01:12:14 +02:00
RTLIL : : unescape_id ( str ) ) ;
2016-07-27 15:41:22 +02:00
width = children [ 0 ] - > asInt ( true ) ;
}
if ( width < = 0 )
2025-09-12 08:03:05 +02:00
input_error ( " Failed to detect width of %s! \n " , RTLIL : : unescape_id ( str ) ) ;
2016-07-27 15:41:22 +02:00
Cell * cell = current_module - > addCell ( myid , str . substr ( 1 ) ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( cell , this ) ;
2020-04-02 18:51:32 +02:00
cell - > parameters [ ID : : WIDTH ] = width ;
2016-07-27 15:41:22 +02:00
2020-04-02 18:51:32 +02:00
if ( attributes . count ( ID : : reg ) ) {
auto & attr = attributes . at ( ID : : reg ) ;
2017-06-07 12:30:24 +02:00
if ( attr - > type ! = AST_CONSTANT )
2023-04-04 11:53:50 +02:00
input_error ( " Attribute `reg' with non-constant value! \n " ) ;
2020-04-02 18:51:32 +02:00
cell - > attributes [ ID : : reg ] = attr - > asAttrConst ( ) ;
2017-06-07 12:30:24 +02:00
}
2016-07-27 15:41:22 +02:00
Wire * wire = current_module - > addWire ( myid + " _wire " , width ) ;
2021-02-23 19:22:53 +01:00
set_src_attr ( wire , this ) ;
2020-03-12 20:57:01 +01:00
cell - > setPort ( ID : : Y , wire ) ;
2016-07-27 15:41:22 +02:00
is_signed = sign_hint ;
return SigSpec ( wire ) ;
}
2020-05-04 21:12:30 +02:00
}
YS_FALLTHROUGH
2016-07-27 15:41:22 +02:00
2013-01-05 11:13:26 +01:00
// everything should have been handled above -> print error if not.
default :
for ( auto f : log_files )
2019-02-21 17:36:51 +01:00
current_ast_mod - > dumpAst ( f , " verilog-ast> " ) ;
2025-09-12 08:03:05 +02:00
input_error ( " Don't know how to generate RTLIL code for %s node! \n " , type2str ( type ) ) ;
2013-01-05 11:13:26 +01:00
}
return RTLIL : : SigSpec ( ) ;
}
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
2015-08-14 10:56:05 +02:00
// signals must be substituted before being used as input values (used by ProcessGenerator)
2013-01-05 11:13:26 +01:00
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
2021-03-25 19:06:05 +01:00
RTLIL : : SigSpec AstNode : : genWidthRTLIL ( int width , bool sgn , const dict < RTLIL : : SigBit , RTLIL : : SigBit > * new_subst_ptr )
2013-01-05 11:13:26 +01:00
{
2014-12-28 19:24:24 +01:00
const dict < RTLIL : : SigBit , RTLIL : : SigBit > * backup_subst_ptr = genRTLIL_subst_ptr ;
2013-01-05 11:13:26 +01:00
2014-08-14 23:02:07 +02:00
if ( new_subst_ptr )
genRTLIL_subst_ptr = new_subst_ptr ;
2013-01-05 11:13:26 +01:00
2021-03-25 19:06:05 +01:00
bool sign_hint = sgn ;
2013-07-09 14:31:57 +02:00
int width_hint = width ;
detectSignWidthWorker ( width_hint , sign_hint ) ;
RTLIL : : SigSpec sig = genRTLIL ( width_hint , sign_hint ) ;
2013-01-05 11:13:26 +01:00
2014-08-14 23:02:07 +02:00
genRTLIL_subst_ptr = backup_subst_ptr ;
2013-01-05 11:13:26 +01:00
if ( width > = 0 )
2013-11-07 19:19:53 +01:00
sig . extend_u0 ( width , is_signed ) ;
2013-01-05 11:13:26 +01:00
return sig ;
}
2014-07-31 13:19:47 +02:00
YOSYS_NAMESPACE_END