2013-01-05 04:13:26 -06:00
/*
* yosys -- Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
2015-07-02 04:14:30 -05:00
*
2013-01-05 04:13:26 -06:00
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* The Verilog frontend.
*
* This frontend is using the AST frontend library (see frontends/ast/).
* Thus this frontend does not generate RTLIL code directly but creates an
* AST directly from the Verilog parse tree and then passes this AST to
* the AST frontend library.
*
* ---
*
* This is the actual bison parser for Verilog code. The AST ist created directly
* from the bison reduce functions here. Note that this code uses a few global
* variables to hold the state of the AST generator and therefore this parser is
* not reentrant.
*
*/
2021-10-01 15:41:11 -05:00
%require "3.0"
2013-01-05 04:13:26 -06:00
%{
#include <list>
2018-12-13 11:47:05 -06:00
#include <stack>
2014-06-13 04:29:23 -05:00
#include <string.h>
2015-08-12 08:04:44 -05:00
#include "frontends/verilog/verilog_frontend.h"
2020-02-23 01:19:52 -06:00
#include "frontends/verilog/verilog_parser.tab.hh"
2013-01-05 04:13:26 -06:00
#include "kernel/log.h"
2020-02-23 01:19:52 -06:00
#define YYLEX_PARAM &yylval, &yylloc
2014-07-31 06:19:47 -05:00
USING_YOSYS_NAMESPACE
2013-01-05 04:13:26 -06:00
using namespace AST;
using namespace VERILOG_FRONTEND;
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_BEGIN
2013-01-05 04:13:26 -06:00
namespace VERILOG_FRONTEND {
int port_counter;
2020-05-04 12:48:37 -05:00
dict<std::string, int> port_stubs;
dict<IdString, AstNode*> *attr_list, default_attr_list;
std::stack<dict<IdString, AstNode*> *> attr_list_stack;
dict<IdString, AstNode*> *albuf;
2021-06-14 09:28:10 -05:00
std::vector<UserTypeMap> user_type_stack;
2020-05-04 12:48:37 -05:00
dict<std::string, AstNode*> pkg_user_types;
2013-01-05 04:13:26 -06:00
std::vector<AstNode*> ast_stack;
struct AstNode *astbuf1, *astbuf2, *astbuf3;
struct AstNode *current_function_or_task;
struct AstNode *current_ast, *current_ast_mod;
int current_function_or_task_port_id;
std::vector<char> case_type_stack;
2014-08-04 08:19:24 -05:00
bool do_not_require_port_stubs;
2014-02-17 07:28:52 -06:00
bool default_nettype_wire;
2019-04-21 14:58:57 -05:00
bool sv_mode, formal_mode, lib_mode, specify_mode;
2018-09-24 13:51:16 -05:00
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
2017-02-08 07:38:15 -06:00
bool current_wire_rand, current_wire_const;
2018-10-12 13:58:37 -05:00
bool current_modport_input, current_modport_output;
2014-08-23 08:03:55 -05:00
std::istream *lexin;
2013-01-05 04:13:26 -06:00
}
2014-07-31 06:19:47 -05:00
YOSYS_NAMESPACE_END
2013-01-05 04:13:26 -06:00
2020-02-23 01:19:52 -06:00
#define SET_AST_NODE_LOC(WHICH, BEGIN, END) \
do { (WHICH)->location.first_line = (BEGIN).first_line; \
(WHICH)->location.first_column = (BEGIN).first_column; \
(WHICH)->location.last_line = (END).last_line; \
(WHICH)->location.last_column = (END).last_column; } while(0)
#define SET_RULE_LOC(LHS, BEGIN, END) \
do { (LHS).first_line = (BEGIN).first_line; \
(LHS).first_column = (BEGIN).first_column; \
(LHS).last_line = (END).last_line; \
(LHS).last_column = (END).last_column; } while(0)
int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
2020-05-04 12:48:37 -05:00
static void append_attr(AstNode *ast, dict<IdString, AstNode*> *al)
2013-01-05 04:13:26 -06:00
{
for (auto &it : *al) {
if (ast->attributes.count(it.first) > 0)
delete ast->attributes[it.first];
ast->attributes[it.first] = it.second;
}
delete al;
}
2020-05-04 12:48:37 -05:00
static void append_attr_clone(AstNode *ast, dict<IdString, AstNode*> *al)
2013-01-05 04:13:26 -06:00
{
for (auto &it : *al) {
if (ast->attributes.count(it.first) > 0)
delete ast->attributes[it.first];
ast->attributes[it.first] = it.second->clone();
}
}
2020-05-04 12:48:37 -05:00
static void free_attr(dict<IdString, AstNode*> *al)
2013-01-05 04:13:26 -06:00
{
for (auto &it : *al)
delete it.second;
delete al;
}
2019-04-21 14:58:57 -05:00
struct specify_target {
char polarity_op;
AstNode *dst, *dat;
};
struct specify_triple {
AstNode *t_min, *t_avg, *t_max;
};
struct specify_rise_fall {
specify_triple rise;
specify_triple fall;
};
2021-06-22 09:51:41 -05:00
static void addWiretypeNode(std::string *name, AstNode *node)
{
log_assert(node);
node->is_custom_type = true;
node->children.push_back(new AstNode(AST_WIRETYPE));
node->children.back()->str = *name;
delete name;
}
2020-02-27 10:57:35 -06:00
static void addTypedefNode(std::string *name, AstNode *node)
{
log_assert(node);
auto *tnode = new AstNode(AST_TYPEDEF, node);
tnode->str = *name;
2021-06-14 09:28:10 -05:00
auto &user_types = user_type_stack.back();
user_types[*name] = tnode;
2020-02-27 10:57:35 -06:00
if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) {
// typedef inside a package so we need the qualified name
auto qname = current_ast_mod->str + "::" + (*name).substr(1);
pkg_user_types[qname] = tnode;
}
delete name;
ast_stack.back()->children.push_back(tnode);
}
2020-03-23 15:07:22 -05:00
static void enterTypeScope()
{
2021-06-14 09:28:10 -05:00
user_type_stack.push_back(UserTypeMap());
2020-03-23 15:07:22 -05:00
}
static void exitTypeScope()
{
user_type_stack.pop_back();
}
2020-03-24 09:35:21 -05:00
static bool isInLocalScope(const std::string *name)
{
// tests if a name was declared in the current block scope
2021-06-14 09:28:10 -05:00
auto &user_types = user_type_stack.back();
return (user_types.count(*name) > 0);
2020-03-24 09:35:21 -05:00
}
2018-03-09 06:47:11 -06:00
static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
{
auto range = new AstNode(AST_RANGE);
range->children.push_back(AstNode::mkconst_int(msb, true));
range->children.push_back(AstNode::mkconst_int(lsb, true));
range->is_signed = isSigned;
return range;
}
static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true)
{
auto range = makeRange(msb, lsb, isSigned);
parent->children.push_back(range);
}
2020-05-08 08:40:49 -05:00
static AstNode *checkRange(AstNode *type_node, AstNode *range_node)
{
if (type_node->range_left >= 0 && type_node->range_right >= 0) {
// type already restricts the range
if (range_node) {
frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
}
else {
range_node = makeRange(type_node->range_left, type_node->range_right, false);
}
}
2024-01-25 00:28:15 -06:00
if (range_node) {
bool valid = true;
if (range_node->type == AST_RANGE) {
valid = range_node->children.size() == 2;
} else { // AST_MULTIRANGE
for (auto child : range_node->children) {
valid = valid && child->children.size() == 2;
}
}
if (!valid)
frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form [<expr>:<expr>]");
2020-05-08 08:40:49 -05:00
}
2024-01-25 00:28:15 -06:00
2020-05-08 08:40:49 -05:00
return range_node;
}
2020-07-17 06:41:09 -05:00
static void rewriteRange(AstNode *rangeNode)
2020-05-08 08:40:49 -05:00
{
if (rangeNode->type == AST_RANGE && rangeNode->children.size() == 1) {
2022-11-13 00:41:25 -06:00
// SV array size [n], rewrite as [0:n-1]
rangeNode->children.push_back(new AstNode(AST_SUB, rangeNode->children[0], AstNode::mkconst_int(1, true)));
rangeNode->children[0] = AstNode::mkconst_int(0, false);
2020-05-08 08:40:49 -05:00
}
2020-07-17 06:41:09 -05:00
}
static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
{
node->type = AST_MEMORY;
if (rangeNode->type == AST_MULTIRANGE) {
for (auto *itr : rangeNode->children)
rewriteRange(itr);
} else
rewriteRange(rangeNode);
2020-05-08 08:40:49 -05:00
node->children.push_back(rangeNode);
}
2021-06-14 14:32:01 -05:00
static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after)
{
if (!before && after)
frontend_verilog_yyerror("%s missing where end label (%s) was given.",
element, after->c_str() + 1);
if (before && after && *before != *after)
frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.",
element, before->c_str() + 1, after->c_str() + 1);
}
2021-08-31 12:45:02 -05:00
// This transforms a loop like
// for (genvar i = 0; i < 10; i++) begin : blk
// to
// genvar _i;
// for (_i = 0; _i < 10; _i++) begin : blk
// localparam i = _i;
// where `_i` is actually some auto-generated name.
static void rewriteGenForDeclInit(AstNode *loop)
{
// check if this generate for loop contains an inline declaration
log_assert(loop->type == AST_GENFOR);
AstNode *decl = loop->children[0];
if (decl->type == AST_ASSIGN_EQ)
return;
log_assert(decl->type == AST_GENVAR);
log_assert(loop->children.size() == 5);
// identify each component of the loop
AstNode *init = loop->children[1];
AstNode *cond = loop->children[2];
AstNode *incr = loop->children[3];
AstNode *body = loop->children[4];
log_assert(init->type == AST_ASSIGN_EQ);
log_assert(incr->type == AST_ASSIGN_EQ);
log_assert(body->type == AST_GENBLOCK);
// create a unique name for the genvar
std::string old_str = decl->str;
std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str());
// rename and move the genvar declaration to the containing description
decl->str = new_str;
loop->children.erase(loop->children.begin());
log_assert(current_ast_mod != nullptr);
current_ast_mod->children.push_back(decl);
// create a new localparam with old name so that the items in the loop
// can simply use the old name and shadow it as necessary
AstNode *indirect = new AstNode(AST_LOCALPARAM);
indirect->str = old_str;
AstNode *ident = new AstNode(AST_IDENTIFIER);
ident->str = new_str;
indirect->children.push_back(ident);
body->children.insert(body->children.begin(), indirect);
// only perform the renaming for the initialization, guard, and
// incrementation to enable proper shadowing of the synthetic localparam
std::function<void(AstNode*)> substitute = [&](AstNode *node) {
if (node->type == AST_IDENTIFIER && node->str == old_str)
node->str = new_str;
for (AstNode *child : node->children)
substitute(child);
};
substitute(init);
substitute(cond);
substitute(incr);
}
2023-09-05 21:19:28 -05:00
static void ensureAsgnExprAllowed()
{
if (!sv_mode)
frontend_verilog_yyerror("Assignments within expressions are only supported in SystemVerilog mode.");
if (ast_stack.back()->type != AST_BLOCK)
frontend_verilog_yyerror("Assignments within expressions are only permitted within procedures.");
}
// add a pre/post-increment/decrement statement
2023-09-18 22:26:35 -05:00
static const AstNode *addIncOrDecStmt(dict<IdString, AstNode*> *stmt_attr, AstNode *lhs,
dict<IdString, AstNode*> *op_attr, AST::AstNodeType op,
YYLTYPE begin, YYLTYPE end)
2023-09-05 21:19:28 -05:00
{
AstNode *one = AstNode::mkconst_int(1, true);
AstNode *rhs = new AstNode(op, lhs->clone(), one);
2023-09-18 22:26:35 -05:00
if (op_attr != nullptr)
append_attr(rhs, op_attr);
2023-09-05 21:19:28 -05:00
AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs);
SET_AST_NODE_LOC(stmt, begin, end);
2023-09-18 22:26:35 -05:00
if (stmt_attr != nullptr)
append_attr(stmt, stmt_attr);
2023-09-05 21:19:28 -05:00
ast_stack.back()->children.push_back(stmt);
return stmt;
}
// create a pre/post-increment/decrement expression, and add the corresponding statement
static AstNode *addIncOrDecExpr(AstNode *lhs, dict<IdString, AstNode*> *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo)
{
ensureAsgnExprAllowed();
2023-09-18 22:26:35 -05:00
const AstNode *stmt = addIncOrDecStmt(nullptr, lhs, attr, op, begin, end);
2023-09-05 21:19:28 -05:00
log_assert(stmt->type == AST_ASSIGN_EQ);
AstNode *expr = stmt->children[0]->clone();
if (undo) {
2023-09-18 22:35:18 -05:00
AstNode *minus_one = AstNode::mkconst_int(-1, true, 1);
2023-09-05 21:19:28 -05:00
expr = new AstNode(op, expr, minus_one);
}
SET_AST_NODE_LOC(expr, begin, end);
return expr;
}
// add a binary operator assignment statement, e.g., a += b
static const AstNode *addAsgnBinopStmt(dict<IdString, AstNode*> *attr, AstNode *lhs, AST::AstNodeType op, AstNode *rhs, YYLTYPE begin, YYLTYPE end)
{
SET_AST_NODE_LOC(rhs, end, end);
if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT ||
op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) {
rhs = new AstNode(AST_TO_UNSIGNED, rhs);
SET_AST_NODE_LOC(rhs, end, end);
}
rhs = new AstNode(op, lhs->clone(), rhs);
AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs);
SET_AST_NODE_LOC(rhs, begin, end);
SET_AST_NODE_LOC(stmt, begin, end);
ast_stack.back()->children.push_back(stmt);
if (attr != nullptr)
append_attr(stmt, attr);
return lhs;
}
2013-01-05 04:13:26 -06:00
%}
2019-05-05 21:29:11 -05:00
%define api.prefix {frontend_verilog_yy}
2020-03-03 10:41:55 -06:00
%define api.pure
2013-01-05 04:13:26 -06:00
2019-05-14 23:07:26 -05:00
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <map>
#include <string>
#include "frontends/verilog/verilog_frontend.h"
}
2013-01-05 04:13:26 -06:00
%union {
std::string *string;
2014-07-31 06:19:47 -05:00
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
2020-05-04 12:48:37 -05:00
YOSYS_NAMESPACE_PREFIX dict<YOSYS_NAMESPACE_PREFIX RTLIL::IdString, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
2019-04-21 14:58:57 -05:00
struct specify_target *specify_target_ptr;
struct specify_triple *specify_triple_ptr;
struct specify_rise_fall *specify_rise_fall_ptr;
2013-01-05 04:13:26 -06:00
bool boolean;
2019-04-21 14:58:57 -05:00
char ch;
2021-02-28 14:49:16 -06:00
int integer;
sv: support remaining assignment operators
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=
2021-03-27 14:59:48 -05:00
YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type;
2013-01-05 04:13:26 -06:00
}
2019-04-21 14:58:57 -05:00
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
2019-06-10 18:52:06 -05:00
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER TOK_MSG_TASKS
2020-03-11 12:21:44 -05:00
%token <string> TOK_BASE TOK_BASED_CONSTVAL TOK_UNBASED_UNSIZED_CONSTVAL
2020-03-24 09:35:21 -05:00
%token <string> TOK_USER_TYPE TOK_PKG_USER_TYPE
2019-05-04 02:25:32 -05:00
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
2013-01-05 04:13:26 -06:00
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
2013-07-04 07:12:33 -05:00
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
2016-06-18 03:24:21 -05:00
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
2019-11-22 09:07:55 -06:00
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT
2019-05-22 07:22:42 -05:00
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
sv: support remaining assignment operators
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=
2021-03-27 14:59:48 -05:00
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
2019-11-21 14:27:19 -06:00
%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
2014-06-06 10:40:04 -05:00
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
2017-11-23 01:48:17 -06:00
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
2013-01-05 04:13:26 -06:00
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
2019-04-21 14:58:57 -05:00
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
2020-02-13 15:06:13 -06:00
%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND
2014-06-14 05:00:47 -05:00
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
2013-01-05 04:13:26 -06:00
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
2019-03-09 00:53:58 -06:00
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
2017-02-25 03:36:39 -06:00
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
2021-02-22 12:19:42 -06:00
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_UNIQUE0 TOK_PRIORITY
2023-03-20 06:50:14 -05:00
%token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_VOID TOK_UNION
sv: support remaining assignment operators
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=
2021-03-27 14:59:48 -05:00
%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN
%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN
%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN
2022-02-11 15:57:31 -06:00
%token TOK_BIND TOK_TIME_SCALE
2013-01-05 04:13:26 -06:00
2021-02-28 14:49:16 -06:00
%type <ast> range range_or_multirange non_opt_range non_opt_multirange
2020-05-19 10:13:04 -05:00
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
2020-03-11 12:21:44 -05:00
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number
2020-02-27 10:57:35 -06:00
%type <string> type_name
2021-06-22 09:51:41 -05:00
%type <ast> opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type
2021-02-28 14:49:16 -06:00
%type <boolean> opt_property always_comb_or_latch always_or_always_ff
%type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned
2021-06-22 09:51:41 -05:00
%type <integer> integer_atom_type integer_vector_type
2017-02-23 09:33:19 -06:00
%type <al> attr case_attr
2020-05-12 11:20:34 -05:00
%type <ast> struct_union
2023-09-05 21:19:28 -05:00
%type <ast_node_type> asgn_binop inc_or_dec_op
2021-08-31 12:45:02 -05:00
%type <ast> genvar_identifier
2013-01-05 04:13:26 -06:00
2019-04-21 14:58:57 -05:00
%type <specify_target_ptr> specify_target
2020-02-13 10:59:08 -06:00
%type <specify_triple_ptr> specify_triple specify_opt_triple
2019-04-21 14:58:57 -05:00
%type <specify_rise_fall_ptr> specify_rise_fall
2020-02-13 10:59:08 -06:00
%type <ast> specify_if specify_condition
2019-04-21 14:58:57 -05:00
%type <ch> specify_edge
2013-01-05 04:13:26 -06:00
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
2013-06-13 04:18:45 -05:00
%left '|' OP_NOR
2013-01-05 04:13:26 -06:00
%left '^' OP_XNOR
2013-06-13 04:18:45 -05:00
%left '&' OP_NAND
2013-12-27 06:50:08 -06:00
%left OP_EQ OP_NE OP_EQX OP_NEX
2013-01-05 04:13:26 -06:00
%left '<' OP_LE OP_GE '>'
%left OP_SHL OP_SHR OP_SSHL OP_SSHR
%left '+' '-'
%left '*' '/' '%'
%left OP_POW
2020-07-15 04:54:28 -05:00
%precedence OP_CAST
%precedence UNARY_OPS
2013-01-05 04:13:26 -06:00
2016-08-25 04:44:25 -05:00
%define parse.error verbose
%define parse.lac full
2020-07-15 04:54:28 -05:00
%precedence FAKE_THEN
%precedence TOK_ELSE
2017-09-29 22:39:07 -05:00
2013-01-05 04:13:26 -06:00
%debug
2020-02-23 01:19:52 -06:00
%locations
2013-01-05 04:13:26 -06:00
%%
2014-08-21 05:42:28 -05:00
input: {
2015-02-19 06:36:54 -06:00
ast_stack.clear();
2014-08-21 05:42:28 -05:00
ast_stack.push_back(current_ast);
} design {
ast_stack.pop_back();
2014-10-10 09:59:44 -05:00
log_assert(GetSize(ast_stack) == 0);
2014-08-21 05:42:28 -05:00
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
};
design:
module design |
defattr design |
task_func_decl design |
2015-10-07 07:59:08 -05:00
param_decl design |
localparam_decl design |
2019-09-19 14:43:13 -05:00
typedef_decl design |
2016-06-18 03:24:21 -05:00
package design |
2018-10-11 16:33:31 -05:00
interface design |
2020-05-21 11:36:29 -05:00
bind_directive design |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
attr:
{
2018-12-13 11:47:05 -06:00
if (attr_list != nullptr)
attr_list_stack.push(attr_list);
2020-05-04 12:48:37 -05:00
attr_list = new dict<IdString, AstNode*>;
2013-01-05 04:13:26 -06:00
for (auto &it : default_attr_list)
2018-12-13 11:47:05 -06:00
(*attr_list)[it.first] = it.second->clone();
2013-01-05 04:13:26 -06:00
} attr_opt {
2018-12-13 11:47:05 -06:00
$$ = attr_list;
if (!attr_list_stack.empty()) {
attr_list = attr_list_stack.top();
attr_list_stack.pop();
} else
attr_list = nullptr;
2013-01-05 04:13:26 -06:00
};
attr_opt:
2020-02-23 01:19:52 -06:00
attr_opt ATTR_BEGIN opt_attr_list ATTR_END {
SET_RULE_LOC(@$, @2, @$);
}|
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
defattr:
DEFATTR_BEGIN {
2018-12-13 11:47:05 -06:00
if (attr_list != nullptr)
attr_list_stack.push(attr_list);
2020-05-04 12:48:37 -05:00
attr_list = new dict<IdString, AstNode*>;
2013-01-05 04:13:26 -06:00
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
} opt_attr_list {
2018-12-13 11:47:05 -06:00
attr_list->swap(default_attr_list);
delete attr_list;
if (!attr_list_stack.empty()) {
attr_list = attr_list_stack.top();
attr_list_stack.pop();
} else
attr_list = nullptr;
2013-01-05 04:13:26 -06:00
} DEFATTR_END;
opt_attr_list:
2020-07-14 17:04:23 -05:00
attr_list | %empty;
2013-01-05 04:13:26 -06:00
attr_list:
attr_assign |
attr_list ',' attr_assign;
attr_assign:
2013-07-04 07:12:33 -05:00
hierarchical_id {
2018-12-13 11:47:05 -06:00
if (attr_list->count(*$1) != 0)
delete (*attr_list)[*$1];
(*attr_list)[*$1] = AstNode::mkconst_int(1, false);
2013-01-05 04:13:26 -06:00
delete $1;
} |
2013-07-04 07:12:33 -05:00
hierarchical_id '=' expr {
2018-12-13 11:47:05 -06:00
if (attr_list->count(*$1) != 0)
delete (*attr_list)[*$1];
(*attr_list)[*$1] = $3;
2013-01-05 04:13:26 -06:00
delete $1;
};
2013-07-04 07:12:33 -05:00
hierarchical_id:
TOK_ID {
$$ = $1;
} |
2016-06-18 03:24:21 -05:00
hierarchical_id TOK_PACKAGESEP TOK_ID {
2019-08-07 14:20:08 -05:00
if ($3->compare(0, 1, "\\") == 0)
2016-06-18 03:24:21 -05:00
*$1 += "::" + $3->substr(1);
else
*$1 += "::" + *$3;
delete $3;
$$ = $1;
} |
2013-07-04 07:12:33 -05:00
hierarchical_id '.' TOK_ID {
2019-08-07 14:20:08 -05:00
if ($3->compare(0, 1, "\\") == 0)
2013-07-04 07:12:33 -05:00
*$1 += "." + $3->substr(1);
else
*$1 += "." + *$3;
delete $3;
$$ = $1;
};
2019-10-13 22:24:31 -05:00
hierarchical_type_id:
2020-02-27 10:57:35 -06:00
TOK_USER_TYPE
2020-03-24 09:35:21 -05:00
| TOK_PKG_USER_TYPE // package qualified type name
2020-02-27 10:57:35 -06:00
| '(' TOK_USER_TYPE ')' { $$ = $2; } // non-standard grammar
;
2019-10-13 22:24:31 -05:00
2013-01-05 04:13:26 -06:00
module:
2020-03-27 11:21:45 -05:00
attr TOK_MODULE {
enterTypeScope();
} TOK_ID {
2014-08-04 08:19:24 -05:00
do_not_require_port_stubs = false;
2013-01-05 04:13:26 -06:00
AstNode *mod = new AstNode(AST_MODULE);
2014-08-21 05:42:28 -05:00
ast_stack.back()->children.push_back(mod);
2013-01-05 04:13:26 -06:00
ast_stack.push_back(mod);
2014-08-21 05:42:28 -05:00
current_ast_mod = mod;
2013-01-05 04:13:26 -06:00
port_stubs.clear();
port_counter = 0;
2020-03-27 11:21:45 -05:00
mod->str = *$4;
2013-01-05 04:13:26 -06:00
append_attr(mod, $1);
2020-05-19 09:58:48 -05:00
} module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label {
2013-01-05 04:13:26 -06:00
if (port_stubs.size() != 0)
frontend_verilog_yyerror("Missing details for module port `%s'.",
port_stubs.begin()->first.c_str());
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @$);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
2014-08-21 05:42:28 -05:00
log_assert(ast_stack.size() == 1);
2021-06-14 14:32:01 -05:00
checkLabelsMatch("Module name", $4, $11);
2014-08-21 05:42:28 -05:00
current_ast_mod = NULL;
2021-06-14 14:32:01 -05:00
delete $4;
delete $11;
2020-03-23 15:07:22 -05:00
exitTypeScope();
2013-01-05 04:13:26 -06:00
};
module_para_opt:
2020-07-14 17:04:23 -05:00
'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | %empty;
2013-03-23 12:54:31 -05:00
module_para_list:
2016-03-15 06:22:31 -05:00
single_module_para | module_para_list ',' single_module_para;
2013-01-05 04:13:26 -06:00
2013-11-07 02:58:15 -06:00
single_module_para:
2020-07-14 17:04:23 -05:00
%empty |
2019-06-19 07:38:50 -05:00
attr TOK_PARAMETER {
2014-10-30 08:01:02 -05:00
if (astbuf1) delete astbuf1;
2013-11-07 02:58:15 -06:00
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
2019-06-19 07:38:50 -05:00
append_attr(astbuf1, $1);
2019-10-13 22:24:31 -05:00
} param_type single_param_decl |
2019-06-19 07:38:50 -05:00
attr TOK_LOCALPARAM {
2017-04-30 10:20:30 -05:00
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
2019-06-19 07:38:50 -05:00
append_attr(astbuf1, $1);
2019-10-13 22:24:31 -05:00
} param_type single_param_decl |
2017-04-30 10:20:30 -05:00
single_param_decl;
2013-11-07 02:58:15 -06:00
2013-01-05 04:13:26 -06:00
module_args_opt:
2020-07-14 17:04:23 -05:00
'(' ')' | %empty | '(' module_args optional_comma ')';
2013-01-05 04:13:26 -06:00
module_args:
module_arg | module_args ',' module_arg;
optional_comma:
2020-07-14 17:04:23 -05:00
',' | %empty;
2013-01-05 04:13:26 -06:00
2013-11-19 18:49:37 -06:00
module_arg_opt_assignment:
'=' expr {
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
2019-06-19 04:37:11 -05:00
if (ast_stack.back()->children.back()->is_input) {
AstNode *n = ast_stack.back()->children.back();
2020-03-12 14:57:01 -05:00
if (n->attributes.count(ID::defaultvalue))
delete n->attributes.at(ID::defaultvalue);
n->attributes[ID::defaultvalue] = $2;
2021-03-16 10:43:03 -05:00
} else {
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic)
ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2))));
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
}
2013-11-19 18:49:37 -06:00
} else
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value.");
2013-11-19 18:49:37 -06:00
} |
2020-07-14 17:04:23 -05:00
%empty;
2013-11-19 18:49:37 -06:00
2013-01-05 04:13:26 -06:00
module_arg:
2013-11-19 18:49:37 -06:00
TOK_ID {
2013-11-19 13:35:31 -06:00
if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) {
AstNode *node = ast_stack.back()->children.back()->clone();
node->str = *$1;
node->port_id = ++port_counter;
ast_stack.back()->children.push_back(node);
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(node, @1, @1);
2013-11-19 13:35:31 -06:00
} else {
if (port_stubs.count(*$1) != 0)
frontend_verilog_yyerror("Duplicate module port `%s'.", $1->c_str());
port_stubs[*$1] = ++port_counter;
}
2013-01-05 04:13:26 -06:00
delete $1;
2013-11-19 18:49:37 -06:00
} module_arg_opt_assignment |
2018-10-11 16:33:31 -05:00
TOK_ID {
astbuf1 = new AstNode(AST_INTERFACEPORT);
astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
astbuf1->children[0]->str = *$1;
delete $1;
} TOK_ID { /* SV interfaces */
if (!sv_mode)
frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
astbuf2->str = *$3;
delete $3;
astbuf2->port_id = ++port_counter;
ast_stack.back()->children.push_back(astbuf2);
delete astbuf1; // really only needed if multiple instances of same type.
} module_arg_opt_assignment |
2024-01-25 00:28:15 -06:00
attr wire_type range_or_multirange TOK_ID {
2013-01-05 04:13:26 -06:00
AstNode *node = $2;
node->str = *$4;
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(node, @4, @4);
2013-01-05 04:13:26 -06:00
node->port_id = ++port_counter;
2021-03-01 12:31:25 -06:00
AstNode *range = checkRange(node, $3);
if (range != NULL)
node->children.push_back(range);
2013-01-05 04:13:26 -06:00
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str());
2016-06-20 13:16:37 -05:00
if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
2013-01-05 04:13:26 -06:00
frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str());
ast_stack.back()->children.push_back(node);
append_attr(node, $1);
delete $4;
2014-08-07 09:41:27 -05:00
} module_arg_opt_assignment |
'.' '.' '.' {
do_not_require_port_stubs = true;
};
2013-01-05 04:13:26 -06:00
2016-06-18 03:24:21 -05:00
package:
2020-03-27 11:21:45 -05:00
attr TOK_PACKAGE {
enterTypeScope();
} TOK_ID {
2016-06-18 03:24:21 -05:00
AstNode *mod = new AstNode(AST_PACKAGE);
ast_stack.back()->children.push_back(mod);
ast_stack.push_back(mod);
current_ast_mod = mod;
2020-03-27 11:21:45 -05:00
mod->str = *$4;
2016-06-18 03:24:21 -05:00
append_attr(mod, $1);
2020-06-19 13:46:38 -05:00
} ';' package_body TOK_ENDPACKAGE opt_label {
2016-06-18 03:24:21 -05:00
ast_stack.pop_back();
2021-06-14 14:32:01 -05:00
checkLabelsMatch("Package name", $4, $9);
2016-06-18 03:24:21 -05:00
current_ast_mod = NULL;
2021-06-14 14:32:01 -05:00
delete $4;
delete $9;
2020-03-23 15:07:22 -05:00
exitTypeScope();
2016-06-18 03:24:21 -05:00
};
package_body:
2020-07-14 17:04:23 -05:00
package_body package_body_stmt | %empty;
2016-06-18 03:24:21 -05:00
package_body_stmt:
2021-05-27 15:47:02 -05:00
typedef_decl | localparam_decl | param_decl | task_func_decl;
2016-06-18 03:24:21 -05:00
2018-10-11 16:33:31 -05:00
interface:
2020-03-27 11:21:45 -05:00
TOK_INTERFACE {
enterTypeScope();
} TOK_ID {
2018-10-11 16:33:31 -05:00
do_not_require_port_stubs = false;
AstNode *intf = new AstNode(AST_INTERFACE);
ast_stack.back()->children.push_back(intf);
ast_stack.push_back(intf);
current_ast_mod = intf;
port_stubs.clear();
port_counter = 0;
2020-03-27 11:21:45 -05:00
intf->str = *$3;
delete $3;
2018-10-11 16:33:31 -05:00
} module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
if (port_stubs.size() != 0)
frontend_verilog_yyerror("Missing details for module port `%s'.",
port_stubs.begin()->first.c_str());
ast_stack.pop_back();
log_assert(ast_stack.size() == 1);
current_ast_mod = NULL;
2020-03-23 15:07:22 -05:00
exitTypeScope();
2018-10-11 16:33:31 -05:00
};
interface_body:
2020-07-14 17:04:23 -05:00
interface_body interface_body_stmt | %empty;
2018-10-11 16:33:31 -05:00
interface_body_stmt:
2020-05-12 08:25:33 -05:00
param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
2020-05-21 11:36:29 -05:00
modport_stmt | bind_directive;
bind_directive:
TOK_BIND {
AstNode *bnode = new AstNode(AST_BIND);
ast_stack.back()->children.push_back(bnode);
ast_stack.push_back(bnode);
}
bind_target {
// bind_target should have added at least one child
log_assert(ast_stack.back()->children.size() >= 1);
}
TOK_ID {
// The single_cell parser in cell_list_no_array uses astbuf1 as
// a sort of template for constructing cells.
astbuf1 = new AstNode(AST_CELL);
astbuf1->children.push_back(new AstNode(AST_CELLTYPE));
astbuf1->children[0]->str = *$5;
delete $5;
}
cell_parameter_list_opt cell_list_no_array ';' {
// cell_list should have added at least one more child
log_assert(ast_stack.back()->children.size() >= 2);
delete astbuf1;
ast_stack.pop_back();
};
// bind_target matches the target of the bind (everything before
// bind_instantiation in the IEEE 1800 spec).
//
// We can't use the BNF from the spec directly because it's ambiguous:
// something like "bind foo bar_i (.*)" can either be interpreted with "foo" as
// a module or interface identifier (matching bind_target_scope in the spec) or
// by considering foo as a degenerate hierarchical identifier with no '.'
// characters, followed by no bit select (which matches bind_target_instance in
// the spec).
//
// Instead, we resolve everything as an instance name and then deal with the
// ambiguity when converting to RTLIL / in the hierarchy pass.
bind_target:
bind_target_instance opt_bind_target_instance_list;
// An optional list of target instances for a bind statement, introduced by a
// colon.
opt_bind_target_instance_list:
':' bind_target_instance_list |
%empty;
bind_target_instance_list:
bind_target_instance |
bind_target_instance_list ',' bind_target_instance;
// A single target instance for a bind statement. The top of ast_stack will be
// the bind node where we should add it.
bind_target_instance:
hierarchical_id {
auto *node = new AstNode(AST_IDENTIFIER);
node->str = *$1;
delete $1;
ast_stack.back()->children.push_back(node);
};
2018-10-11 16:33:31 -05:00
2021-02-24 14:48:15 -06:00
mintypmax_expr:
expr { delete $1; } |
expr ':' expr ':' expr { delete $1; delete $3; delete $5; };
2015-02-20 03:21:36 -06:00
non_opt_delay:
2017-09-25 18:52:59 -05:00
'#' TOK_ID { delete $2; } |
'#' TOK_CONSTVAL { delete $2; } |
2017-11-18 03:01:30 -06:00
'#' TOK_REALVAL { delete $2; } |
2022-02-11 15:57:31 -06:00
// our `expr` doesn't have time_scale, so we need the parenthesized variant
'#' TOK_TIME_SCALE |
'#' '(' TOK_TIME_SCALE ')' |
2021-02-24 14:48:15 -06:00
'#' '(' mintypmax_expr ')' |
'#' '(' mintypmax_expr ',' mintypmax_expr ')' |
'#' '(' mintypmax_expr ',' mintypmax_expr ',' mintypmax_expr ')';
2015-02-20 03:21:36 -06:00
delay:
2020-07-14 17:04:23 -05:00
non_opt_delay | %empty;
2015-02-20 03:21:36 -06:00
2020-05-19 10:13:04 -05:00
io_wire_type:
{ astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; }
wire_type_token_io wire_type_const_rand opt_wire_type_token wire_type_signedness
{ $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); };
2013-01-05 04:13:26 -06:00
2020-05-19 10:13:04 -05:00
non_io_wire_type:
{ astbuf3 = new AstNode(AST_WIRE); current_wire_rand = false; current_wire_const = false; }
wire_type_const_rand wire_type_token wire_type_signedness
{ $$ = astbuf3; SET_RULE_LOC(@$, @2, @$); };
wire_type:
io_wire_type |
non_io_wire_type;
2013-01-05 04:13:26 -06:00
2018-06-06 14:27:25 -05:00
wire_type_token_io:
2013-01-05 04:13:26 -06:00
TOK_INPUT {
astbuf3->is_input = true;
} |
TOK_OUTPUT {
astbuf3->is_output = true;
} |
TOK_INOUT {
astbuf3->is_input = true;
astbuf3->is_output = true;
2018-06-06 14:27:25 -05:00
};
2020-05-19 10:13:04 -05:00
wire_type_signedness:
TOK_SIGNED { astbuf3->is_signed = true; } |
TOK_UNSIGNED { astbuf3->is_signed = false; } |
%empty;
wire_type_const_rand:
2021-01-21 09:30:55 -06:00
TOK_RAND TOK_CONST {
current_wire_rand = true;
current_wire_const = true;
} |
TOK_CONST {
current_wire_const = true;
} |
TOK_RAND {
current_wire_rand = true;
} |
2020-05-19 10:13:04 -05:00
%empty;
opt_wire_type_token:
wire_type_token | %empty;
2018-06-06 14:27:25 -05:00
wire_type_token:
2021-08-13 22:51:28 -05:00
// nets
net_type {
2019-05-22 07:22:42 -05:00
} |
2021-08-13 22:51:28 -05:00
net_type logic_type {
2021-01-20 10:15:48 -06:00
} |
// regs
2013-01-05 04:13:26 -06:00
TOK_REG {
astbuf3->is_reg = true;
} |
2021-01-20 10:15:48 -06:00
TOK_VAR TOK_REG {
astbuf3->is_reg = true;
2018-03-09 02:35:33 -06:00
} |
2021-01-20 10:15:48 -06:00
// logics
2019-05-04 00:52:51 -05:00
TOK_VAR {
astbuf3->is_logic = true;
} |
2021-01-20 10:15:48 -06:00
TOK_VAR logic_type {
astbuf3->is_logic = true;
} |
logic_type {
astbuf3->is_logic = true;
2013-01-05 04:13:26 -06:00
} |
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
astbuf3->is_reg = true;
2019-06-20 18:04:12 -05:00
astbuf3->is_signed = true;
2013-01-05 04:13:26 -06:00
astbuf3->range_left = 31;
astbuf3->range_right = 0;
};
2021-08-13 22:51:28 -05:00
net_type:
TOK_WOR {
astbuf3->is_wor = true;
} |
TOK_WAND {
astbuf3->is_wand = true;
} |
TOK_WIRE;
2021-01-20 10:15:48 -06:00
logic_type:
TOK_LOGIC {
} |
2021-02-28 14:49:16 -06:00
integer_atom_type {
astbuf3->range_left = $1 - 1;
2021-01-20 10:15:48 -06:00
astbuf3->range_right = 0;
astbuf3->is_signed = true;
2021-06-22 09:51:41 -05:00
} |
hierarchical_type_id {
addWiretypeNode($1, astbuf3);
2021-01-20 10:15:48 -06:00
};
2021-02-28 14:49:16 -06:00
integer_atom_type:
TOK_INTEGER { $$ = 32; } |
TOK_INT { $$ = 32; } |
TOK_SHORTINT { $$ = 16; } |
TOK_LONGINT { $$ = 64; } |
TOK_BYTE { $$ = 8; } ;
2021-06-22 09:51:41 -05:00
integer_vector_type:
TOK_LOGIC { $$ = TOK_LOGIC; } |
TOK_REG { $$ = TOK_REG; } ;
2013-11-20 03:51:32 -06:00
non_opt_range:
2013-01-05 04:13:26 -06:00
'[' expr ':' expr ']' {
$$ = new AstNode(AST_RANGE);
$$->children.push_back($2);
$$->children.push_back($4);
} |
2013-11-20 06:05:27 -06:00
'[' expr TOK_POS_INDEXED expr ']' {
$$ = new AstNode(AST_RANGE);
2020-04-29 07:28:04 -05:00
AstNode *expr = new AstNode(AST_SELFSZ, $2);
2020-03-08 10:12:12 -05:00
$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true)));
$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true)));
2013-11-20 06:05:27 -06:00
} |
'[' expr TOK_NEG_INDEXED expr ']' {
$$ = new AstNode(AST_RANGE);
2020-04-29 07:28:04 -05:00
AstNode *expr = new AstNode(AST_SELFSZ, $2);
2020-03-08 10:12:12 -05:00
$$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true)));
$$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4));
2013-11-20 06:05:27 -06:00
} |
2013-01-05 04:13:26 -06:00
'[' expr ']' {
$$ = new AstNode(AST_RANGE);
$$->children.push_back($2);
2013-11-20 03:51:32 -06:00
};
2014-08-06 08:43:46 -05:00
non_opt_multirange:
non_opt_range non_opt_range {
$$ = new AstNode(AST_MULTIRANGE, $1, $2);
} |
non_opt_multirange non_opt_range {
$$ = $1;
$$->children.push_back($2);
};
2013-11-20 03:51:32 -06:00
range:
non_opt_range {
$$ = $1;
2013-01-05 04:13:26 -06:00
} |
2020-07-14 17:04:23 -05:00
%empty {
2013-01-05 04:13:26 -06:00
$$ = NULL;
};
2014-08-06 08:43:46 -05:00
range_or_multirange:
range { $$ = $1; } |
non_opt_multirange { $$ = $1; };
2013-01-05 04:13:26 -06:00
module_body:
module_body module_body_stmt |
2014-06-06 16:05:01 -05:00
/* the following line makes the generate..endgenrate keywords optional */
module_body gen_stmt |
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
module_body gen_block |
2020-07-10 07:56:14 -05:00
module_body ';' |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
module_body_stmt:
2019-10-13 22:24:31 -05:00
task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
2020-05-21 11:36:29 -05:00
enum_decl | struct_decl | bind_directive |
2020-07-10 07:56:14 -05:00
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
2017-02-09 06:51:44 -06:00
checker_decl:
TOK_CHECKER TOK_ID ';' {
AstNode *node = new AstNode(AST_GENBLOCK);
node->str = *$2;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} module_body TOK_ENDCHECKER {
delete $2;
ast_stack.pop_back();
};
2013-01-05 04:13:26 -06:00
task_func_decl:
2014-08-21 05:43:51 -05:00
attr TOK_DPI_FUNCTION TOK_ID TOK_ID {
2014-08-21 10:22:04 -05:00
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4));
2014-08-21 05:43:51 -05:00
current_function_or_task->str = *$4;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $4;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
2014-08-21 10:22:04 -05:00
attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID {
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3));
current_function_or_task->str = *$6;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $5;
delete $6;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
2014-08-22 07:30:29 -05:00
attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID {
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)));
current_function_or_task->str = *$8;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $5;
delete $7;
delete $8;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
2017-11-23 01:48:17 -06:00
attr TOK_TASK opt_automatic TOK_ID {
2013-01-05 04:13:26 -06:00
current_function_or_task = new AstNode(AST_TASK);
2017-11-23 01:48:17 -06:00
current_function_or_task->str = *$4;
2014-08-18 07:29:30 -05:00
append_attr(current_function_or_task, $1);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
2017-11-23 01:48:17 -06:00
delete $4;
2014-10-27 07:21:57 -05:00
} task_func_args_opt ';' task_func_body TOK_ENDTASK {
2013-01-05 04:13:26 -06:00
current_function_or_task = NULL;
ast_stack.pop_back();
} |
2023-03-20 06:50:14 -05:00
attr TOK_FUNCTION opt_automatic TOK_VOID TOK_ID {
// The difference between void functions and tasks is that
// always_comb's implicit sensitivity list behaves as if functions were
// inlined, but ignores signals read only in tasks. This only matters
// for event based simulation, and for synthesis we can treat a void
// function like a task.
current_function_or_task = new AstNode(AST_TASK);
current_function_or_task->str = *$5;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
delete $5;
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
2021-02-28 14:49:16 -06:00
attr TOK_FUNCTION opt_automatic func_return_type TOK_ID {
2013-01-05 04:13:26 -06:00
current_function_or_task = new AstNode(AST_FUNCTION);
2021-02-28 14:49:16 -06:00
current_function_or_task->str = *$5;
2014-08-18 07:29:30 -05:00
append_attr(current_function_or_task, $1);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
AstNode *outreg = new AstNode(AST_WIRE);
2021-02-28 14:49:16 -06:00
outreg->str = *$5;
outreg->is_signed = false;
2018-06-05 09:44:24 -05:00
outreg->is_reg = true;
2021-02-28 14:49:16 -06:00
if ($4 != NULL) {
outreg->children.push_back($4);
outreg->is_signed = $4->is_signed;
$4->is_signed = false;
2021-03-18 12:38:25 -05:00
outreg->is_custom_type = $4->type == AST_WIRETYPE;
2014-06-16 08:02:40 -05:00
}
2013-01-05 04:13:26 -06:00
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
2021-02-28 14:49:16 -06:00
delete $5;
2014-10-27 07:21:57 -05:00
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
2013-01-05 04:13:26 -06:00
current_function_or_task = NULL;
ast_stack.pop_back();
};
2021-02-28 14:49:16 -06:00
func_return_type:
2021-03-18 12:38:25 -05:00
hierarchical_type_id {
$$ = new AstNode(AST_WIRETYPE);
$$->str = *$1;
delete $1;
} |
2021-02-28 14:49:16 -06:00
opt_type_vec opt_signedness_default_unsigned {
$$ = makeRange(0, 0, $2);
} |
opt_type_vec opt_signedness_default_unsigned non_opt_range {
$$ = $3;
$$->is_signed = $2;
} |
integer_atom_type opt_signedness_default_signed {
$$ = makeRange($1 - 1, 0, $2);
};
opt_type_vec:
%empty
| TOK_REG
| TOK_LOGIC
;
opt_signedness_default_signed:
%empty { $$ = true; }
| TOK_SIGNED { $$ = true; }
| TOK_UNSIGNED { $$ = false; }
;
opt_signedness_default_unsigned:
%empty { $$ = false; }
| TOK_SIGNED { $$ = true; }
| TOK_UNSIGNED { $$ = false; }
;
2014-08-21 05:43:51 -05:00
dpi_function_arg:
TOK_ID TOK_ID {
current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
delete $1;
delete $2;
} |
TOK_ID {
current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
delete $1;
};
opt_dpi_function_args:
'(' dpi_function_args ')' |
2020-07-14 17:04:23 -05:00
%empty;
2014-08-21 05:43:51 -05:00
dpi_function_args:
dpi_function_args ',' dpi_function_arg |
dpi_function_args ',' |
dpi_function_arg |
2020-07-14 17:04:23 -05:00
%empty;
2014-08-21 05:43:51 -05:00
2017-11-23 01:48:17 -06:00
opt_automatic:
TOK_AUTOMATIC |
2020-07-14 17:04:23 -05:00
%empty;
2017-11-23 01:48:17 -06:00
2014-10-27 07:21:57 -05:00
task_func_args_opt:
2020-07-14 17:04:23 -05:00
'(' ')' | %empty | '(' {
2014-10-27 07:21:57 -05:00
albuf = nullptr;
astbuf1 = nullptr;
astbuf2 = nullptr;
} task_func_args optional_comma {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
} ')';
task_func_args:
task_func_port | task_func_args ',' task_func_port;
task_func_port:
2024-01-25 00:28:15 -06:00
attr wire_type range_or_multirange {
2020-12-31 17:14:35 -06:00
bool prev_was_input = true;
bool prev_was_output = false;
2014-10-27 07:21:57 -05:00
if (albuf) {
2020-12-31 17:14:35 -06:00
prev_was_input = astbuf1->is_input;
prev_was_output = astbuf1->is_output;
2014-10-27 07:21:57 -05:00
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
}
albuf = $1;
astbuf1 = $2;
2020-05-08 08:40:49 -05:00
astbuf2 = checkRange(astbuf1, $3);
2020-12-31 17:14:35 -06:00
if (!astbuf1->is_input && !astbuf1->is_output) {
if (!sv_mode)
frontend_verilog_yyerror("task/function argument direction missing");
astbuf1->is_input = prev_was_input;
astbuf1->is_output = prev_was_output;
}
2020-05-11 15:00:36 -05:00
} wire_name |
{
2020-05-13 15:33:37 -05:00
if (!astbuf1) {
if (!sv_mode)
frontend_verilog_yyerror("task/function argument direction missing");
albuf = new dict<IdString, AstNode*>;
astbuf1 = new AstNode(AST_WIRE);
current_wire_rand = false;
current_wire_const = false;
astbuf1->is_input = true;
astbuf2 = NULL;
}
2020-05-11 15:00:36 -05:00
} wire_name;
2014-10-27 07:21:57 -05:00
2013-01-05 04:13:26 -06:00
task_func_body:
task_func_body behavioral_stmt |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
2019-04-21 14:58:57 -05:00
/*************************** specify parser ***************************/
2018-03-04 15:35:08 -06:00
specify_block:
2019-04-21 14:58:57 -05:00
TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
2018-03-04 15:35:08 -06:00
2019-04-21 14:58:57 -05:00
specify_item_list:
specify_item specify_item_list |
2020-07-14 17:04:23 -05:00
%empty;
2018-03-04 15:35:08 -06:00
specify_item:
2019-04-21 14:58:57 -05:00
specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
AstNode *en_expr = $1;
char specify_edge = $3;
AstNode *src_expr = $4;
string *oper = $5;
specify_target *target = $6;
specify_rise_fall *timing = $9;
if (specify_edge != 0 && target->dat == nullptr)
frontend_verilog_yyerror("Found specify edge but no data spec.\n");
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
2020-05-04 12:53:06 -05:00
SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10);
2019-04-21 14:58:57 -05:00
char oper_polarity = 0;
char oper_type = oper->at(0);
if (oper->size() == 3) {
oper_polarity = oper->at(0);
oper_type = oper->at(1);
}
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
cell->children.back()->str = "\\FULL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
cell->children.back()->str = "\\SRC_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
cell->children.back()->str = "\\SRC_DST_POL";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
cell->children.back()->str = "\\T_RISE_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
2019-04-22 02:52:47 -05:00
cell->children.back()->str = "\\T_RISE_TYP";
2019-04-21 14:58:57 -05:00
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
cell->children.back()->str = "\\T_RISE_MAX";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
cell->children.back()->str = "\\T_FALL_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
2019-04-22 02:52:47 -05:00
cell->children.back()->str = "\\T_FALL_TYP";
2019-04-21 14:58:57 -05:00
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
cell->children.back()->str = "\\T_FALL_MAX";
cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
cell->children.back()->str = "\\EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
cell->children.back()->str = "\\DST";
if (target->dat)
{
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
cell->children.back()->str = "\\EDGE_EN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
cell->children.back()->str = "\\EDGE_POL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
cell->children.back()->str = "\\DAT_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
cell->children.back()->str = "\\DAT_DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
cell->children.back()->str = "\\DAT";
}
delete oper;
delete target;
delete timing;
2019-04-23 08:46:40 -05:00
} |
2020-02-13 10:59:08 -06:00
TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' {
2019-04-23 15:57:10 -05:00
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
2019-04-23 08:46:40 -05:00
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
2020-02-13 10:59:08 -06:00
specify_triple *limit = $11;
specify_triple *limit2 = $12;
2019-04-23 08:46:40 -05:00
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = "$specrule";
2020-05-04 12:53:06 -05:00
SET_AST_NODE_LOC(cell, @1, @14);
2019-04-23 08:46:40 -05:00
2019-04-23 15:57:10 -05:00
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
2019-04-23 15:18:04 -05:00
2020-02-13 10:59:08 -06:00
cell->children.push_back(new AstNode(AST_PARASET, limit->t_min));
cell->children.back()->str = "\\T_LIMIT_MIN";
2019-04-23 08:46:40 -05:00
2020-02-13 10:59:08 -06:00
cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg));
cell->children.back()->str = "\\T_LIMIT_TYP";
cell->children.push_back(new AstNode(AST_PARASET, limit->t_max));
cell->children.back()->str = "\\T_LIMIT_MAX";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2_MIN";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2_TYP";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2_MAX";
2019-04-23 15:57:10 -05:00
2019-04-23 08:46:40 -05:00
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
cell->children.push_back(new AstNode(AST_PARASET, src_pol));
cell->children.back()->str = "\\SRC_POL";
cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
cell->children.back()->str = "\\DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
cell->children.back()->str = "\\DST_POL";
2019-04-23 15:18:04 -05:00
cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
cell->children.back()->str = "\\SRC_EN";
2019-04-23 08:46:40 -05:00
2019-04-23 15:18:04 -05:00
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
cell->children.back()->str = "\\DST_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
cell->children.back()->str = "\\DST";
2019-04-23 08:46:40 -05:00
delete $1;
2021-03-16 10:43:03 -05:00
delete limit;
delete limit2;
2019-04-21 14:58:57 -05:00
};
2020-02-13 10:59:08 -06:00
specify_opt_triple:
',' specify_triple {
2019-04-23 15:57:10 -05:00
$$ = $2;
} |
2020-07-14 17:04:23 -05:00
%empty {
2019-04-23 15:57:10 -05:00
$$ = nullptr;
};
2019-04-21 14:58:57 -05:00
specify_if:
TOK_IF '(' expr ')' {
$$ = $3;
} |
2020-07-14 17:04:23 -05:00
%empty {
2019-04-21 14:58:57 -05:00
$$ = nullptr;
};
2019-04-23 08:46:40 -05:00
specify_condition:
TOK_SPECIFY_AND expr {
$$ = $2;
} |
2020-07-14 17:04:23 -05:00
%empty {
2019-04-23 08:46:40 -05:00
$$ = nullptr;
};
2019-04-21 14:58:57 -05:00
specify_target:
expr {
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $1;
$$->dat = nullptr;
} |
'(' expr ':' expr ')'{
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_NEG_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '-';
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_POS_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '+';
$$->dst = $2;
$$->dat = $4;
};
specify_edge:
TOK_POSEDGE { $$ = 'p'; } |
TOK_NEGEDGE { $$ = 'n'; } |
2020-07-14 17:04:23 -05:00
%empty { $$ = 0; };
2019-04-21 14:58:57 -05:00
specify_rise_fall:
specify_triple {
$$ = new specify_rise_fall;
$$->rise = *$1;
$$->fall.t_min = $1->t_min->clone();
$$->fall.t_avg = $1->t_avg->clone();
$$->fall.t_max = $1->t_max->clone();
delete $1;
} |
'(' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
2020-02-19 13:09:37 -06:00
} |
'(' specify_triple ',' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
2020-05-04 12:53:06 -05:00
delete $6;
log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
2020-02-19 13:09:37 -06:00
} |
'(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
2020-05-04 12:53:06 -05:00
delete $6;
delete $8;
delete $10;
delete $12;
log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
2020-02-19 13:09:37 -06:00
} |
'(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
2020-05-04 12:53:06 -05:00
delete $6;
delete $8;
delete $10;
delete $12;
delete $14;
delete $16;
delete $18;
delete $20;
delete $22;
delete $24;
log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
2020-02-19 13:09:37 -06:00
}
2019-04-21 14:58:57 -05:00
specify_triple:
expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $1->clone();
$$->t_max = $1->clone();
} |
expr ':' expr ':' expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $3;
$$->t_max = $5;
};
/******************** ignored specify parser **************************/
ignored_specify_block:
TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
ignored_specify_item_opt:
ignored_specify_item_opt ignored_specify_item |
ignored_specify_item ;
ignored_specify_item:
2018-03-04 15:35:08 -06:00
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
| path_declaration
2018-08-19 16:08:08 -05:00
| system_timing_declaration
2018-03-04 15:35:08 -06:00
;
specparam_declaration:
TOK_SPECPARAM list_of_specparam_assignments ';' |
TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ;
// IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow
specparam_range:
2019-04-21 14:58:57 -05:00
'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
2018-03-04 15:35:08 -06:00
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
2020-02-13 15:27:15 -06:00
ignspec_id '=' ignspec_expr ;
2018-03-04 15:35:08 -06:00
2019-07-03 04:22:10 -05:00
ignspec_opt_cond:
2020-07-14 17:04:23 -05:00
TOK_IF '(' ignspec_expr ')' | %empty;
2018-03-04 15:35:08 -06:00
path_declaration :
2018-08-20 09:27:45 -05:00
simple_path_declaration ';'
2018-03-04 15:35:08 -06:00
// | edge_sensitive_path_declaration
// | state_dependent_path_declaration
;
simple_path_declaration :
2019-07-03 04:22:10 -05:00
ignspec_opt_cond parallel_path_description '=' path_delay_value |
ignspec_opt_cond full_path_description '=' path_delay_value
2018-03-04 15:35:08 -06:00
;
path_delay_value :
2020-02-13 15:27:15 -06:00
'(' ignspec_expr list_of_path_delay_extra_expressions ')'
| ignspec_expr
| ignspec_expr list_of_path_delay_extra_expressions
2018-03-04 15:35:08 -06:00
;
2018-08-20 09:27:45 -05:00
list_of_path_delay_extra_expressions :
2020-02-13 15:27:15 -06:00
',' ignspec_expr
| ',' ignspec_expr list_of_path_delay_extra_expressions
;
2018-03-04 15:35:08 -06:00
2019-06-28 03:21:16 -05:00
specify_edge_identifier :
TOK_POSEDGE | TOK_NEGEDGE ;
2018-03-04 15:35:08 -06:00
parallel_path_description :
2019-06-28 03:21:16 -05:00
'(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' |
'(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor opt_polarity_operator ':' ignspec_expr ')' ')' |
'(' specify_edge_identifier specify_input_terminal_descriptor '=' '>' '(' specify_output_terminal_descriptor TOK_POS_INDEXED ignspec_expr ')' ')' ;
2018-03-04 15:35:08 -06:00
2018-08-15 11:56:30 -05:00
full_path_description :
2019-06-28 03:21:16 -05:00
'(' list_of_path_inputs '*' '>' list_of_path_outputs ')' |
'(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs opt_polarity_operator ':' ignspec_expr ')' ')' |
'(' specify_edge_identifier list_of_path_inputs '*' '>' '(' list_of_path_outputs TOK_POS_INDEXED ignspec_expr ')' ')' ;
2018-08-15 11:56:30 -05:00
2018-08-19 16:08:08 -05:00
// This was broken into 2 rules to solve shift/reduce conflicts
2018-08-15 11:56:30 -05:00
list_of_path_inputs :
2018-08-19 16:08:08 -05:00
specify_input_terminal_descriptor opt_polarity_operator |
specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ;
more_path_inputs :
',' specify_input_terminal_descriptor |
more_path_inputs ',' specify_input_terminal_descriptor ;
2018-08-15 11:56:30 -05:00
list_of_path_outputs :
specify_output_terminal_descriptor |
list_of_path_outputs ',' specify_output_terminal_descriptor ;
2018-12-07 13:14:07 -06:00
2018-03-04 15:35:08 -06:00
opt_polarity_operator :
2020-07-14 17:04:23 -05:00
'+' | '-' | %empty;
2018-03-04 15:35:08 -06:00
// Good enough for the time being
specify_input_terminal_descriptor :
2019-04-21 14:58:57 -05:00
ignspec_id ;
2018-03-04 15:35:08 -06:00
// Good enough for the time being
specify_output_terminal_descriptor :
2019-04-21 14:58:57 -05:00
ignspec_id ;
2018-03-04 15:35:08 -06:00
system_timing_declaration :
2019-04-21 14:58:57 -05:00
ignspec_id '(' system_timing_args ')' ';' ;
2018-08-19 16:08:08 -05:00
system_timing_arg :
2019-04-21 14:58:57 -05:00
TOK_POSEDGE ignspec_id |
TOK_NEGEDGE ignspec_id |
ignspec_expr ;
2018-03-04 15:35:08 -06:00
2018-08-19 16:08:08 -05:00
system_timing_args :
system_timing_arg |
2020-02-13 15:06:13 -06:00
system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg |
2018-08-19 16:08:08 -05:00
system_timing_args ',' system_timing_arg ;
2018-12-07 13:14:07 -06:00
2018-03-04 15:35:08 -06:00
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
2018-12-07 13:14:07 -06:00
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
2019-04-21 14:58:57 -05:00
ignspec_constant_expression:
expr { delete $1; };
ignspec_expr:
2020-02-13 10:59:08 -06:00
expr { delete $1; } |
expr ':' expr ':' expr {
2020-02-13 15:06:13 -06:00
delete $1;
delete $3;
delete $5;
2020-02-13 10:59:08 -06:00
};
2019-04-21 14:58:57 -05:00
ignspec_id:
2020-02-13 19:58:43 -06:00
TOK_ID { delete $1; }
range_or_multirange { delete $3; };
2019-04-21 14:58:57 -05:00
/**********************************************************************/
2018-03-04 15:35:08 -06:00
2013-11-07 02:58:15 -06:00
param_signed:
TOK_SIGNED {
astbuf1->is_signed = true;
2020-07-10 02:59:48 -05:00
} | TOK_UNSIGNED {
astbuf1->is_signed = false;
2020-07-14 17:04:23 -05:00
} | %empty;
2013-01-05 04:13:26 -06:00
2013-11-07 02:58:15 -06:00
param_integer:
2021-02-28 14:49:16 -06:00
type_atom {
astbuf1->is_reg = false;
2020-07-15 03:15:13 -05:00
};
2013-11-07 02:58:15 -06:00
2014-06-14 05:00:47 -05:00
param_real:
TOK_REAL {
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
2020-07-15 03:15:13 -05:00
};
2020-07-10 02:59:48 -05:00
2013-11-07 02:58:15 -06:00
param_range:
range {
if ($1 != NULL) {
astbuf1->children.push_back($1);
}
};
2013-01-05 04:13:26 -06:00
2020-07-15 03:15:13 -05:00
param_integer_type: param_integer param_signed;
2021-02-28 14:49:16 -06:00
param_range_type:
type_vec param_signed {
addRange(astbuf1, 0, 0);
} |
type_vec param_signed non_opt_range {
astbuf1->children.push_back($3);
};
2020-07-15 03:15:13 -05:00
param_implicit_type: param_signed param_range;
2020-07-10 02:59:48 -05:00
2019-10-13 22:24:31 -05:00
param_type:
2020-07-10 03:14:31 -05:00
param_integer_type | param_real | param_range_type | param_implicit_type |
2019-10-13 22:24:31 -05:00
hierarchical_type_id {
2023-01-29 13:22:00 -06:00
addWiretypeNode($1, astbuf1);
2019-09-19 15:07:20 -05:00
};
2013-11-07 02:58:15 -06:00
param_decl:
2019-05-16 05:44:16 -05:00
attr TOK_PARAMETER {
2013-11-07 02:58:15 -06:00
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
2019-06-19 07:38:50 -05:00
append_attr(astbuf1, $1);
2019-09-19 15:07:20 -05:00
} param_type param_decl_list ';' {
2013-11-07 02:58:15 -06:00
delete astbuf1;
2013-01-05 04:13:26 -06:00
};
localparam_decl:
2019-05-16 05:44:16 -05:00
attr TOK_LOCALPARAM {
2013-11-07 02:58:15 -06:00
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
2019-06-19 07:38:50 -05:00
append_attr(astbuf1, $1);
2019-10-13 22:24:31 -05:00
} param_type param_decl_list ';' {
2013-11-07 02:58:15 -06:00
delete astbuf1;
};
2013-01-05 04:13:26 -06:00
2013-11-07 02:58:15 -06:00
param_decl_list:
single_param_decl | param_decl_list ',' single_param_decl;
2013-01-05 04:13:26 -06:00
2013-11-07 02:58:15 -06:00
single_param_decl:
2021-03-02 09:43:53 -06:00
single_param_decl_ident '=' expr {
AstNode *decl = ast_stack.back()->children.back();
log_assert(decl->type == AST_PARAMETER || decl->type == AST_LOCALPARAM);
delete decl->children[0];
decl->children[0] = $3;
} |
single_param_decl_ident {
AstNode *decl = ast_stack.back()->children.back();
if (decl->type != AST_PARAMETER) {
log_assert(decl->type == AST_LOCALPARAM);
frontend_verilog_yyerror("localparam initialization is missing!");
}
if (!sv_mode)
frontend_verilog_yyerror("Parameter defaults can only be omitted in SystemVerilog mode!");
delete decl->children[0];
decl->children.erase(decl->children.begin());
};
single_param_decl_ident:
TOK_ID {
2018-09-23 03:32:54 -05:00
AstNode *node;
if (astbuf1 == nullptr) {
if (!sv_mode)
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
2018-09-23 03:32:54 -05:00
node = new AstNode(AST_PARAMETER);
node->children.push_back(AstNode::mkconst_int(0, true));
} else {
node = astbuf1->clone();
}
2013-11-07 02:58:15 -06:00
node->str = *$1;
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
2013-11-07 02:58:15 -06:00
delete $1;
2021-03-02 09:43:53 -06:00
SET_AST_NODE_LOC(node, @1, @1);
2013-01-05 04:13:26 -06:00
};
2013-07-04 07:12:33 -05:00
defparam_decl:
TOK_DEFPARAM defparam_decl_list ';';
defparam_decl_list:
single_defparam_decl | defparam_decl_list ',' single_defparam_decl;
single_defparam_decl:
2016-11-15 06:35:19 -06:00
range rvalue '=' expr {
2013-07-04 07:12:33 -05:00
AstNode *node = new AstNode(AST_DEFPARAM);
2016-11-15 06:35:19 -06:00
node->children.push_back($2);
2013-07-04 07:12:33 -05:00
node->children.push_back($4);
if ($1 != NULL)
node->children.push_back($1);
ast_stack.back()->children.push_back(node);
};
2020-05-08 08:40:49 -05:00
/////////
// enum
/////////
2018-03-09 06:47:11 -06:00
enum_type: TOK_ENUM {
2020-02-03 00:12:24 -06:00
static int enum_count;
2018-03-09 06:47:11 -06:00
// create parent node for the enum
astbuf2 = new AstNode(AST_ENUM);
ast_stack.back()->children.push_back(astbuf2);
2020-02-03 00:12:24 -06:00
astbuf2->str = std::string("$enum");
astbuf2->str += std::to_string(enum_count++);
2018-03-09 06:47:11 -06:00
// create the template for the names
astbuf1 = new AstNode(AST_ENUM_ITEM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
2021-08-05 14:02:35 -05:00
} enum_base_type '{' enum_name_list optional_comma '}' {
// create template for the enum vars
auto tnode = astbuf1->clone();
delete astbuf1;
astbuf1 = tnode;
tnode->type = AST_WIRE;
tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str);
// drop constant but keep any range
delete tnode->children[0];
tnode->children.erase(tnode->children.begin());
$$ = astbuf1;
};
2018-03-09 06:47:11 -06:00
2020-05-08 08:40:49 -05:00
enum_base_type: type_atom type_signing
| type_vec type_signing range { if ($3) astbuf1->children.push_back($3); }
2020-07-14 17:04:23 -05:00
| %empty { astbuf1->is_reg = true; addRange(astbuf1); }
2018-03-09 06:47:11 -06:00
;
2021-02-28 14:49:16 -06:00
type_atom:
integer_atom_type {
astbuf1->is_reg = true;
astbuf1->is_signed = true;
addRange(astbuf1, $1 - 1, 0);
};
2018-03-09 06:47:11 -06:00
2020-05-08 08:40:49 -05:00
type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned
| TOK_LOGIC { astbuf1->is_logic = true; } // unsigned
2018-03-09 06:47:11 -06:00
;
2020-05-08 08:40:49 -05:00
type_signing:
TOK_SIGNED { astbuf1->is_signed = true; }
| TOK_UNSIGNED { astbuf1->is_signed = false; }
2020-07-14 17:04:23 -05:00
| %empty
2020-05-08 08:40:49 -05:00
;
enum_name_list: enum_name_decl
2018-03-09 06:47:11 -06:00
| enum_name_list ',' enum_name_decl
;
enum_name_decl:
TOK_ID opt_enum_init {
// put in fn
log_assert(astbuf1);
log_assert(astbuf2);
auto node = astbuf1->clone();
node->str = *$1;
delete $1;
2020-05-12 08:25:33 -05:00
SET_AST_NODE_LOC(node, @1, @1);
2018-03-09 06:47:11 -06:00
delete node->children[0];
2020-06-17 06:51:02 -05:00
node->children[0] = $2 ? $2 : new AstNode(AST_NONE);
2018-03-09 06:47:11 -06:00
astbuf2->children.push_back(node);
}
;
opt_enum_init:
'=' basic_expr { $$ = $2; } // TODO: restrict this
2020-07-14 17:04:23 -05:00
| %empty { $$ = NULL; }
2018-03-09 06:47:11 -06:00
;
enum_var_list:
enum_var
| enum_var_list ',' enum_var
;
enum_var: TOK_ID {
log_assert(astbuf1);
log_assert(astbuf2);
auto node = astbuf1->clone();
ast_stack.back()->children.push_back(node);
node->str = *$1;
delete $1;
2020-05-12 08:25:33 -05:00
SET_AST_NODE_LOC(node, @1, @1);
2018-03-09 06:47:11 -06:00
node->is_enum = true;
}
;
2020-05-08 08:40:49 -05:00
enum_decl: enum_type enum_var_list ';' { delete $1; }
2018-03-09 06:47:11 -06:00
;
2020-05-12 08:25:33 -05:00
//////////////////
// struct or union
//////////////////
2020-05-08 08:40:49 -05:00
Handling of attributes for struct / union variables
(* nowrshmsk *) on a struct / union variable now affects dynamic
bit slice assignments to members of the struct / union.
(* nowrshmsk *) can in some cases yield significant resource savings; the
combination of pipeline shifting and indexed writes is an example of this.
Constructs similar to the one below can benefit from (* nowrshmsk *), and
in addition it is no longer necessary to split out the shift assignments
on separate lines in order to avoid the error message "ERROR: incompatible
mix of lookahead and non-lookahead IDs in LHS expression."
always_ff @(posedge clk) begin
if (rotate) begin
{ v5, v4, v3, v2, v1, v0 } <= { v4, v3, v2, v1, v0, v5 };
if (res) begin
v0.bytes <= '0;
end else if (w) begin
v0.bytes[addr] <= data;
end
end
end
2023-03-02 12:02:30 -06:00
struct_decl:
attr struct_type {
append_attr($2, $1);
} struct_var_list ';' {
delete astbuf2;
}
2020-05-08 08:40:49 -05:00
;
2020-05-12 11:20:34 -05:00
struct_type: struct_union { astbuf2 = $1; } struct_body { $$ = astbuf2; }
2020-05-12 08:25:33 -05:00
;
struct_union:
2020-05-12 11:20:34 -05:00
TOK_STRUCT { $$ = new AstNode(AST_STRUCT); }
| TOK_UNION { $$ = new AstNode(AST_UNION); }
2020-05-08 08:40:49 -05:00
;
2020-05-12 11:20:34 -05:00
struct_body: opt_packed '{' struct_member_list '}'
;
2020-05-12 08:25:33 -05:00
2020-07-14 17:04:23 -05:00
opt_packed:
TOK_PACKED opt_signed_struct |
%empty { frontend_verilog_yyerror("Only PACKED supported at this time"); };
2020-05-08 08:40:49 -05:00
opt_signed_struct:
TOK_SIGNED { astbuf2->is_signed = true; }
2020-05-12 08:25:33 -05:00
| TOK_UNSIGNED { astbuf2->is_signed = false; }
2020-07-14 17:04:23 -05:00
| %empty // default is unsigned
2020-05-08 08:40:49 -05:00
;
struct_member_list: struct_member
| struct_member_list struct_member
;
struct_member: struct_member_type member_name_list ';' { delete astbuf1; }
;
member_name_list:
member_name
| member_name_list ',' member_name
;
member_name: TOK_ID {
astbuf1->str = $1->substr(1);
delete $1;
2020-06-07 12:28:45 -05:00
astbuf3 = astbuf1->clone();
SET_AST_NODE_LOC(astbuf3, @1, @1);
astbuf2->children.push_back(astbuf3);
} range { if ($3) astbuf3->children.push_back($3); }
2020-05-08 08:40:49 -05:00
;
2020-05-12 11:20:34 -05:00
struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_token
2020-05-08 08:40:49 -05:00
;
2020-05-12 11:20:34 -05:00
member_type_token:
2024-01-05 12:29:06 -06:00
member_type range_or_multirange {
AstNode *range = checkRange(astbuf1, $2);
if (range)
astbuf1->children.push_back(range);
}
2021-06-17 14:59:59 -05:00
| {
delete astbuf1;
} struct_union {
2020-05-12 11:20:34 -05:00
// stash state on ast_stack
ast_stack.push_back(astbuf2);
2021-06-17 14:59:59 -05:00
astbuf2 = $2;
2020-05-12 11:20:34 -05:00
} struct_body {
astbuf1 = astbuf2;
// recover state
astbuf2 = ast_stack.back();
ast_stack.pop_back();
}
2020-05-08 08:40:49 -05:00
;
member_type: type_atom type_signing
2024-01-05 12:29:06 -06:00
| type_vec type_signing
| hierarchical_type_id { addWiretypeNode($1, astbuf1); }
2020-05-08 08:40:49 -05:00
;
struct_var_list: struct_var
| struct_var_list ',' struct_var
;
struct_var: TOK_ID { auto *var_node = astbuf2->clone();
var_node->str = *$1;
delete $1;
2020-05-12 08:25:33 -05:00
SET_AST_NODE_LOC(var_node, @1, @1);
2020-05-08 08:40:49 -05:00
ast_stack.back()->children.push_back(var_node);
}
;
/////////
// wire
/////////
2013-01-05 04:13:26 -06:00
wire_decl:
2024-01-25 00:28:15 -06:00
attr wire_type range_or_multirange {
2013-01-05 04:13:26 -06:00
albuf = $1;
astbuf1 = $2;
2020-05-08 08:40:49 -05:00
astbuf2 = checkRange(astbuf1, $3);
2020-02-03 14:29:40 -06:00
} delay wire_name_list {
2013-01-05 04:13:26 -06:00
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
2014-10-27 07:21:57 -05:00
} ';' |
2014-12-11 06:56:20 -06:00
attr TOK_SUPPLY0 TOK_ID {
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
2014-12-11 06:56:20 -06:00
} opt_supply_wires ';' |
attr TOK_SUPPLY1 TOK_ID {
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
2014-12-11 06:56:20 -06:00
} opt_supply_wires ';';
opt_supply_wires:
2020-07-14 17:04:23 -05:00
%empty |
2014-12-11 06:56:20 -06:00
opt_supply_wires ',' TOK_ID {
AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone();
AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone();
wire_node->str = *$3;
assign_node->children[0]->str = *$3;
ast_stack.back()->children.push_back(wire_node);
ast_stack.back()->children.push_back(assign_node);
delete $3;
2013-01-05 04:13:26 -06:00
};
wire_name_list:
wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign;
wire_name_and_opt_assign:
2017-02-08 07:38:15 -06:00
wire_name {
2018-04-06 07:35:11 -05:00
bool attr_anyconst = false;
bool attr_anyseq = false;
bool attr_allconst = false;
bool attr_allseq = false;
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyconst)) {
delete ast_stack.back()->children.back()->attributes.at(ID::anyconst);
ast_stack.back()->children.back()->attributes.erase(ID::anyconst);
2018-04-06 07:35:11 -05:00
attr_anyconst = true;
}
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->children.back()->get_bool_attribute(ID::anyseq)) {
delete ast_stack.back()->children.back()->attributes.at(ID::anyseq);
ast_stack.back()->children.back()->attributes.erase(ID::anyseq);
2018-04-06 07:35:11 -05:00
attr_anyseq = true;
}
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->children.back()->get_bool_attribute(ID::allconst)) {
delete ast_stack.back()->children.back()->attributes.at(ID::allconst);
ast_stack.back()->children.back()->attributes.erase(ID::allconst);
2018-04-06 07:35:11 -05:00
attr_allconst = true;
}
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->children.back()->get_bool_attribute(ID::allseq)) {
delete ast_stack.back()->children.back()->attributes.at(ID::allseq);
ast_stack.back()->children.back()->attributes.erase(ID::allseq);
2018-04-06 07:35:11 -05:00
attr_allseq = true;
}
if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) {
2017-02-08 07:38:15 -06:00
AstNode *wire = new AstNode(AST_IDENTIFIER);
AstNode *fcall = new AstNode(AST_FCALL);
wire->str = ast_stack.back()->children.back()->str;
fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq";
2018-04-06 07:35:11 -05:00
if (attr_anyconst)
fcall->str = "\\$anyconst";
if (attr_anyseq)
fcall->str = "\\$anyseq";
if (attr_allconst)
fcall->str = "\\$allconst";
if (attr_allseq)
fcall->str = "\\$allseq";
2020-04-02 11:51:32 -05:00
fcall->attributes[ID::reg] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str));
2017-02-08 07:38:15 -06:00
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall));
}
} |
2013-01-05 04:13:26 -06:00
wire_name '=' expr {
2013-11-23 09:26:59 -06:00
AstNode *wire = new AstNode(AST_IDENTIFIER);
wire->str = ast_stack.back()->children.back()->str;
2019-06-19 04:37:11 -05:00
if (astbuf1->is_input) {
2020-03-12 14:57:01 -05:00
if (astbuf1->attributes.count(ID::defaultvalue))
delete astbuf1->attributes.at(ID::defaultvalue);
astbuf1->attributes[ID::defaultvalue] = $3;
2020-02-23 01:19:52 -06:00
}
else if (astbuf1->is_reg || astbuf1->is_logic){
AstNode *assign = new AstNode(AST_ASSIGN_LE, wire, $3);
AstNode *block = new AstNode(AST_BLOCK, assign);
AstNode *init = new AstNode(AST_INITIAL, block);
SET_AST_NODE_LOC(assign, @1, @3);
SET_AST_NODE_LOC(block, @1, @3);
SET_AST_NODE_LOC(init, @1, @3);
ast_stack.back()->children.push_back(init);
}
else {
AstNode *assign = new AstNode(AST_ASSIGN, wire, $3);
SET_AST_NODE_LOC(assign, @1, @3);
ast_stack.back()->children.push_back(assign);
}
2013-01-05 04:13:26 -06:00
};
wire_name:
2014-08-06 08:43:46 -05:00
TOK_ID range_or_multirange {
2015-09-22 14:34:21 -05:00
if (astbuf1 == nullptr)
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node.");
2013-01-05 04:13:26 -06:00
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
if (astbuf2 != NULL)
node->children.push_back(astbuf2->clone());
if ($2 != NULL) {
if (node->is_input || node->is_output)
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
2019-09-20 06:11:17 -05:00
if (!astbuf2 && !node->is_custom_type) {
2020-05-08 08:40:49 -05:00
addRange(node, 0, 0, false);
2019-06-19 05:47:48 -05:00
}
2020-05-08 08:40:49 -05:00
rewriteAsMemoryNode(node, $2);
2013-01-05 04:13:26 -06:00
}
2021-02-06 22:54:17 -06:00
if (current_function_or_task) {
if (node->is_input || node->is_output)
node->port_id = current_function_or_task_port_id++;
} else if (ast_stack.back()->type == AST_GENBLOCK) {
if (node->is_input || node->is_output)
frontend_verilog_yyerror("Cannot declare module port `%s' within a generate block.", $1->c_str());
} else {
2014-08-04 08:19:24 -05:00
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
port_stubs[*$1] = ++port_counter;
}
2013-01-05 04:13:26 -06:00
if (port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str());
2016-06-20 13:16:37 -05:00
if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
2013-01-05 04:13:26 -06:00
frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str());
node->port_id = port_stubs[*$1];
port_stubs.erase(*$1);
} else {
if (node->is_input || node->is_output)
frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str());
}
}
2020-02-23 01:19:52 -06:00
//FIXME: for some reason, TOK_ID has a location which always points to one column *after* the real last column...
SET_AST_NODE_LOC(node, @1, @1);
2014-08-05 05:15:53 -05:00
ast_stack.back()->children.push_back(node);
2018-03-09 02:35:33 -06:00
2013-01-05 04:13:26 -06:00
delete $1;
};
assign_stmt:
2015-02-20 03:21:36 -06:00
TOK_ASSIGN delay assign_expr_list ';';
2013-01-05 04:13:26 -06:00
assign_expr_list:
assign_expr | assign_expr_list ',' assign_expr;
assign_expr:
2015-10-15 08:19:23 -05:00
lvalue '=' expr {
2020-02-23 01:19:52 -06:00
AstNode *node = new AstNode(AST_ASSIGN, $1, $3);
SET_AST_NODE_LOC(node, @$, @$);
ast_stack.back()->children.push_back(node);
2013-01-05 04:13:26 -06:00
};
2020-02-27 10:57:35 -06:00
type_name: TOK_ID // first time seen
2020-03-24 09:35:21 -05:00
| TOK_USER_TYPE { if (isInLocalScope($1)) frontend_verilog_yyerror("Duplicate declaration of TYPEDEF '%s'", $1->c_str()+1); }
2020-02-27 10:57:35 -06:00
;
2019-09-19 14:43:13 -05:00
typedef_decl:
2024-01-25 00:28:15 -06:00
TOK_TYPEDEF typedef_base_type range_or_multirange type_name range_or_multirange ';' {
2019-09-19 14:43:13 -05:00
astbuf1 = $2;
2020-05-08 08:40:49 -05:00
astbuf2 = checkRange(astbuf1, $3);
2019-09-19 14:43:13 -05:00
if (astbuf2)
astbuf1->children.push_back(astbuf2);
2019-09-20 05:39:15 -05:00
if ($5 != NULL) {
2023-12-31 18:18:00 -06:00
if (!astbuf2 && !astbuf1->is_custom_type) {
2020-05-08 08:40:49 -05:00
addRange(astbuf1, 0, 0, false);
2019-09-20 05:39:15 -05:00
}
2020-05-08 08:40:49 -05:00
rewriteAsMemoryNode(astbuf1, $5);
2019-09-20 05:39:15 -05:00
}
2020-05-08 08:40:49 -05:00
addTypedefNode($4, astbuf1); }
2021-06-22 09:51:41 -05:00
| TOK_TYPEDEF enum_struct_type type_name ';' { addTypedefNode($3, $2); }
2020-05-08 08:40:49 -05:00
;
2021-06-22 09:51:41 -05:00
typedef_base_type:
hierarchical_type_id {
$$ = new AstNode(AST_WIRE);
$$->is_logic = true;
addWiretypeNode($1, $$);
} |
integer_vector_type opt_signedness_default_unsigned {
$$ = new AstNode(AST_WIRE);
if ($1 == TOK_REG) {
$$->is_reg = true;
} else {
$$->is_logic = true;
}
$$->is_signed = $2;
} |
integer_atom_type opt_signedness_default_signed {
$$ = new AstNode(AST_WIRE);
$$->is_logic = true;
$$->is_signed = $2;
$$->range_left = $1 - 1;
$$->range_right = 0;
};
enum_struct_type:
2020-05-08 08:40:49 -05:00
enum_type
| struct_type
2020-01-16 16:17:42 -06:00
;
2019-09-19 14:43:13 -05:00
2013-01-05 04:13:26 -06:00
cell_stmt:
attr TOK_ID {
astbuf1 = new AstNode(AST_CELL);
append_attr(astbuf1, $1);
astbuf1->children.push_back(new AstNode(AST_CELLTYPE));
astbuf1->children[0]->str = *$2;
delete $2;
} cell_parameter_list_opt cell_list ';' {
delete astbuf1;
} |
2015-02-20 03:21:36 -06:00
attr tok_prim_wrapper delay {
2013-01-05 04:13:26 -06:00
astbuf1 = new AstNode(AST_PRIMITIVE);
astbuf1->str = *$2;
append_attr(astbuf1, $1);
delete $2;
} prim_list ';' {
delete astbuf1;
};
tok_prim_wrapper:
TOK_PRIMITIVE {
$$ = $1;
} |
TOK_OR {
$$ = new std::string("or");
};
cell_list:
single_cell |
cell_list ',' single_cell;
single_cell:
2020-05-21 11:36:29 -05:00
single_cell_no_array | single_cell_arraylist;
single_cell_no_array:
2013-01-05 04:13:26 -06:00
TOK_ID {
astbuf2 = astbuf1->clone();
if (astbuf2->type != AST_PRIMITIVE)
astbuf2->str = *$1;
delete $1;
ast_stack.back()->children.push_back(astbuf2);
2020-02-23 01:19:52 -06:00
} '(' cell_port_list ')' {
SET_AST_NODE_LOC(astbuf2, @1, @$);
2020-05-21 11:36:29 -05:00
}
single_cell_arraylist:
2014-06-07 04:48:50 -05:00
TOK_ID non_opt_range {
astbuf2 = astbuf1->clone();
if (astbuf2->type != AST_PRIMITIVE)
astbuf2->str = *$1;
delete $1;
ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2));
2020-02-23 01:19:52 -06:00
} '(' cell_port_list ')'{
SET_AST_NODE_LOC(astbuf2, @1, @$);
};
2013-01-05 04:13:26 -06:00
2020-05-21 11:36:29 -05:00
cell_list_no_array:
single_cell_no_array |
cell_list_no_array ',' single_cell_no_array;
2013-01-05 04:13:26 -06:00
prim_list:
single_prim |
prim_list ',' single_prim;
single_prim:
single_cell |
/* no name */ {
astbuf2 = astbuf1->clone();
ast_stack.back()->children.push_back(astbuf2);
2020-05-04 12:22:05 -05:00
} '(' cell_port_list ')' {
SET_AST_NODE_LOC(astbuf2, @1, @$);
}
2013-01-05 04:13:26 -06:00
cell_parameter_list_opt:
2020-07-14 17:04:23 -05:00
'#' '(' cell_parameter_list ')' | %empty;
2013-01-05 04:13:26 -06:00
cell_parameter_list:
2016-03-15 06:22:31 -05:00
cell_parameter | cell_parameter_list ',' cell_parameter;
2013-01-05 04:13:26 -06:00
cell_parameter:
2020-07-14 17:04:23 -05:00
%empty |
2013-01-05 04:13:26 -06:00
expr {
AstNode *node = new AstNode(AST_PARASET);
astbuf1->children.push_back(node);
node->children.push_back($1);
} |
2020-10-01 11:26:53 -05:00
'.' TOK_ID '(' ')' {
// just ignore empty parameters
} |
2013-01-05 04:13:26 -06:00
'.' TOK_ID '(' expr ')' {
AstNode *node = new AstNode(AST_PARASET);
node->str = *$2;
astbuf1->children.push_back(node);
node->children.push_back($4);
delete $2;
};
2016-03-14 13:28:34 -05:00
cell_port_list:
2016-07-25 05:48:03 -05:00
cell_port_list_rules {
// remove empty args from end of list
while (!astbuf2->children.empty()) {
AstNode *node = astbuf2->children.back();
if (node->type != AST_ARGUMENT) break;
if (!node->children.empty()) break;
if (!node->str.empty()) break;
astbuf2->children.pop_back();
2016-07-25 09:37:58 -05:00
delete node;
2016-07-25 05:48:03 -05:00
}
// check port types
bool has_positional_args = false;
bool has_named_args = false;
for (auto node : astbuf2->children) {
if (node->type != AST_ARGUMENT) continue;
if (node->str.empty())
has_positional_args = true;
else
has_named_args = true;
}
if (has_positional_args && has_named_args)
frontend_verilog_yyerror("Mix of positional and named cell ports.");
};
cell_port_list_rules:
cell_port | cell_port_list_rules ',' cell_port;
2016-03-14 13:28:34 -05:00
2013-01-05 04:13:26 -06:00
cell_port:
2019-05-31 05:24:12 -05:00
attr {
2016-07-25 05:48:03 -05:00
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
2019-06-05 03:42:43 -05:00
free_attr($1);
2016-07-25 05:48:03 -05:00
} |
2019-05-31 05:24:12 -05:00
attr expr {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
2019-05-31 05:24:12 -05:00
node->children.push_back($2);
2019-06-05 03:42:43 -05:00
free_attr($1);
2013-01-05 04:13:26 -06:00
} |
2019-05-31 05:24:12 -05:00
attr '.' TOK_ID '(' expr ')' {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_ARGUMENT);
2019-05-31 05:24:12 -05:00
node->str = *$3;
2013-01-05 04:13:26 -06:00
astbuf2->children.push_back(node);
2019-05-31 05:24:12 -05:00
node->children.push_back($5);
delete $3;
2019-06-05 03:42:43 -05:00
free_attr($1);
2013-01-05 04:13:26 -06:00
} |
2019-05-31 05:24:12 -05:00
attr '.' TOK_ID '(' ')' {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_ARGUMENT);
2019-05-31 05:24:12 -05:00
node->str = *$3;
2013-01-05 04:13:26 -06:00
astbuf2->children.push_back(node);
2019-05-31 05:24:12 -05:00
delete $3;
2019-06-05 03:42:43 -05:00
free_attr($1);
2019-06-07 04:41:54 -05:00
} |
attr '.' TOK_ID {
AstNode *node = new AstNode(AST_ARGUMENT);
node->str = *$3;
2019-06-04 17:47:54 -05:00
astbuf2->children.push_back(node);
2019-06-07 04:41:54 -05:00
node->children.push_back(new AstNode(AST_IDENTIFIER));
node->children.back()->str = *$3;
delete $3;
free_attr($1);
2019-11-22 02:24:01 -06:00
} |
2019-11-22 09:07:55 -06:00
attr TOK_WILDCARD_CONNECT {
if (!sv_mode)
frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode.");
2020-04-02 11:51:32 -05:00
astbuf2->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false);
2021-03-18 04:38:36 -05:00
free_attr($1);
2013-01-05 04:13:26 -06:00
};
2019-11-21 14:27:19 -06:00
always_comb_or_latch:
TOK_ALWAYS_COMB {
$$ = false;
} |
TOK_ALWAYS_LATCH {
$$ = true;
};
always_or_always_ff:
TOK_ALWAYS {
$$ = false;
} |
TOK_ALWAYS_FF {
$$ = true;
};
2013-01-05 04:13:26 -06:00
always_stmt:
2019-11-21 14:27:19 -06:00
attr always_or_always_ff {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_ALWAYS);
append_attr(node, $1);
2019-11-21 14:27:19 -06:00
if ($2)
2020-04-02 11:51:32 -05:00
node->attributes[ID::always_ff] = AstNode::mkconst_int(1, false);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} always_cond {
AstNode *block = new AstNode(AST_BLOCK);
2019-11-21 14:27:19 -06:00
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @6, @6);
2019-11-21 14:27:19 -06:00
ast_stack.pop_back();
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @$);
2019-11-21 14:27:19 -06:00
ast_stack.pop_back();
2020-02-23 01:19:52 -06:00
SET_RULE_LOC(@$, @2, @$);
2019-11-21 14:27:19 -06:00
} |
attr always_comb_or_latch {
AstNode *node = new AstNode(AST_ALWAYS);
append_attr(node, $1);
if ($2)
2020-04-02 11:51:32 -05:00
node->attributes[ID::always_latch] = AstNode::mkconst_int(1, false);
2019-11-21 14:27:19 -06:00
else
2020-04-02 11:51:32 -05:00
node->attributes[ID::always_comb] = AstNode::mkconst_int(1, false);
2019-11-21 14:27:19 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
AstNode *block = new AstNode(AST_BLOCK);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
ast_stack.pop_back();
ast_stack.pop_back();
} |
attr TOK_INITIAL {
2013-03-31 04:19:11 -05:00
AstNode *node = new AstNode(AST_INITIAL);
2013-01-05 04:13:26 -06:00
append_attr(node, $1);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
ast_stack.pop_back();
ast_stack.pop_back();
};
always_cond:
'@' '(' always_events ')' |
2013-01-16 10:32:11 -06:00
'@' '(' '*' ')' |
'@' ATTR_BEGIN ')' |
'@' '(' ATTR_END |
2013-01-05 04:13:26 -06:00
'@' '*' |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
always_events:
always_event |
always_events TOK_OR always_event |
always_events ',' always_event;
always_event:
TOK_POSEDGE expr {
AstNode *node = new AstNode(AST_POSEDGE);
2020-04-17 01:16:59 -05:00
SET_AST_NODE_LOC(node, @1, @1);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
node->children.push_back($2);
} |
TOK_NEGEDGE expr {
AstNode *node = new AstNode(AST_NEGEDGE);
2020-04-17 01:16:59 -05:00
SET_AST_NODE_LOC(node, @1, @1);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
node->children.push_back($2);
} |
expr {
AstNode *node = new AstNode(AST_EDGE);
ast_stack.back()->children.push_back(node);
node->children.push_back($1);
};
opt_label:
':' TOK_ID {
$$ = $2;
} |
2020-07-14 17:04:23 -05:00
%empty {
2013-01-05 04:13:26 -06:00
$$ = NULL;
};
2019-03-10 18:27:18 -05:00
opt_sva_label:
TOK_SVA_LABEL ':' {
$$ = $1;
} |
2020-07-14 17:04:23 -05:00
%empty {
2019-03-10 18:27:18 -05:00
$$ = NULL;
};
2018-04-12 07:28:28 -05:00
opt_property:
2018-11-04 08:57:17 -06:00
TOK_PROPERTY {
$$ = true;
} |
2019-05-04 02:25:32 -05:00
TOK_FINAL {
$$ = false;
} |
2020-07-14 17:04:23 -05:00
%empty {
2018-11-04 08:57:17 -06:00
$$ = false;
};
2018-04-12 07:28:28 -05:00
2018-10-11 16:33:31 -05:00
modport_stmt:
2018-10-12 13:58:37 -05:00
TOK_MODPORT TOK_ID {
AstNode *modport = new AstNode(AST_MODPORT);
ast_stack.back()->children.push_back(modport);
ast_stack.push_back(modport);
modport->str = *$2;
delete $2;
} modport_args_opt {
ast_stack.pop_back();
log_assert(ast_stack.size() == 2);
} ';'
2018-10-11 16:33:31 -05:00
modport_args_opt:
'(' ')' | '(' modport_args optional_comma ')';
modport_args:
modport_arg | modport_args ',' modport_arg;
modport_arg:
2018-10-13 13:48:55 -05:00
modport_type_token modport_member |
modport_member
modport_member:
TOK_ID {
2018-10-12 13:58:37 -05:00
AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
ast_stack.back()->children.push_back(modport_member);
2018-10-13 13:48:55 -05:00
modport_member->str = *$1;
2018-10-12 13:58:37 -05:00
modport_member->is_input = current_modport_input;
modport_member->is_output = current_modport_output;
2018-10-13 13:48:55 -05:00
delete $1;
}
2018-10-11 16:33:31 -05:00
modport_type_token:
2018-10-12 13:58:37 -05:00
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
2018-10-11 16:33:31 -05:00
2014-01-18 21:18:22 -06:00
assert:
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (noassert_mode) {
2019-03-10 18:27:18 -05:00
delete $5;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
2015-02-26 11:47:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (noassume_mode) {
2019-03-10 18:27:18 -05:00
delete $5;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
2016-07-13 09:56:17 -05:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (noassert_mode) {
2019-03-10 18:27:18 -05:00
delete $6;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (noassume_mode) {
2019-03-10 18:27:18 -05:00
delete $6;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
AstNode *node = new AstNode(AST_COVER, $5);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
2017-02-04 07:14:26 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_COVER opt_property '(' ')' ';' {
2019-03-07 13:17:32 -06:00
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @5);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
2017-02-04 10:02:13 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_COVER ';' {
2019-03-07 13:17:32 -06:00
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @2);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
2017-02-04 10:02:13 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (norestrict_mode) {
2019-03-10 18:27:18 -05:00
delete $5;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(AST_ASSUME, $5);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @6);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
2019-03-10 18:27:18 -05:00
if (!$3)
2018-11-04 08:57:17 -06:00
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
delete $1;
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
2019-03-07 13:17:32 -06:00
if (norestrict_mode) {
2019-03-10 18:27:18 -05:00
delete $6;
2019-03-07 13:17:32 -06:00
} else {
2019-03-10 18:27:18 -05:00
AstNode *node = new AstNode(AST_FAIR, $6);
2024-02-08 05:32:15 -06:00
SET_AST_NODE_LOC(node, ($1 != nullptr ? @1 : @2), @7);
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
2019-03-10 18:27:18 -05:00
if (!$3)
2018-11-04 08:57:17 -06:00
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
2019-03-07 13:17:32 -06:00
if ($1 != nullptr)
delete $1;
2014-01-18 21:18:22 -06:00
};
2014-06-12 04:54:20 -05:00
assert_property:
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
SET_AST_NODE_LOC(node, @1, @6);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
2015-02-26 11:47:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(AST_ASSUME, $5);
SET_AST_NODE_LOC(node, @1, @6);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
2016-07-13 09:56:17 -05:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
SET_AST_NODE_LOC(node, @1, @7);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(AST_FAIR, $6);
SET_AST_NODE_LOC(node, @1, @7);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(AST_COVER, $5);
SET_AST_NODE_LOC(node, @1, @6);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
2017-02-04 07:14:26 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
2019-03-09 00:53:58 -06:00
if (norestrict_mode) {
2019-03-10 18:27:18 -05:00
delete $5;
2019-03-09 00:53:58 -06:00
} else {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(AST_ASSUME, $5);
SET_AST_NODE_LOC(node, @1, @6);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
2017-02-25 03:36:39 -06:00
} |
2019-03-10 18:27:18 -05:00
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
2019-03-09 00:53:58 -06:00
if (norestrict_mode) {
2019-03-10 18:27:18 -05:00
delete $6;
2019-03-09 00:53:58 -06:00
} else {
2020-03-17 00:00:12 -05:00
AstNode *node = new AstNode(AST_FAIR, $6);
SET_AST_NODE_LOC(node, @1, @7);
ast_stack.back()->children.push_back(node);
2019-03-09 00:53:58 -06:00
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
2014-06-12 04:54:20 -05:00
};
2013-01-05 04:13:26 -06:00
simple_behavioral_stmt:
2020-05-21 11:46:26 -05:00
attr lvalue '=' delay expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
2020-05-21 11:46:26 -05:00
SET_AST_NODE_LOC(node, @2, @5);
append_attr(node, $1);
2013-01-05 04:13:26 -06:00
} |
2023-09-05 21:19:28 -05:00
attr lvalue attr inc_or_dec_op {
2023-09-18 22:26:35 -05:00
addIncOrDecStmt($1, $2, $3, $4, @1, @4);
} |
attr inc_or_dec_op attr lvalue {
addIncOrDecStmt($1, $4, $3, $2, @1, @4);
2017-02-23 04:21:33 -06:00
} |
2020-05-21 11:46:26 -05:00
attr lvalue OP_LE delay expr {
AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
2020-05-21 11:46:26 -05:00
SET_AST_NODE_LOC(node, @2, @5);
append_attr(node, $1);
2020-06-03 06:51:57 -05:00
} |
sv: support remaining assignment operators
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=
2021-03-27 14:59:48 -05:00
attr lvalue asgn_binop delay expr {
2023-09-05 21:19:28 -05:00
addAsgnBinopStmt($1, $2, $3, $5, @2, @5);
2013-01-05 04:13:26 -06:00
};
sv: support remaining assignment operators
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=
2021-03-27 14:59:48 -05:00
asgn_binop:
TOK_BIT_OR_ASSIGN { $$ = AST_BIT_OR; } |
TOK_BIT_AND_ASSIGN { $$ = AST_BIT_AND; } |
TOK_BIT_XOR_ASSIGN { $$ = AST_BIT_XOR; } |
TOK_ADD_ASSIGN { $$ = AST_ADD; } |
TOK_SUB_ASSIGN { $$ = AST_SUB; } |
TOK_DIV_ASSIGN { $$ = AST_DIV; } |
TOK_MOD_ASSIGN { $$ = AST_MOD; } |
TOK_MUL_ASSIGN { $$ = AST_MUL; } |
TOK_SHL_ASSIGN { $$ = AST_SHIFT_LEFT; } |
TOK_SHR_ASSIGN { $$ = AST_SHIFT_RIGHT; } |
TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } |
TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ;
2023-09-05 21:19:28 -05:00
inc_or_dec_op:
// NOTE: These should only be permitted in SV mode, but Yosys has
// allowed them in all modes since support for them was added in 2017.
TOK_INCREMENT { $$ = AST_ADD; } |
TOK_DECREMENT { $$ = AST_SUB; } ;
2021-08-30 12:35:36 -05:00
for_initialization:
TOK_ID '=' expr {
AstNode *ident = new AstNode(AST_IDENTIFIER);
ident->str = *$1;
AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3);
ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @3);
2021-09-23 12:33:55 -05:00
delete $1;
2021-08-30 12:35:36 -05:00
} |
non_io_wire_type range TOK_ID {
frontend_verilog_yyerror("For loop variable declaration is missing initialization!");
} |
non_io_wire_type range TOK_ID '=' expr {
if (!sv_mode)
frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!");
// loop variable declaration
AstNode *wire = $1;
AstNode *range = checkRange(wire, $2);
if (range != nullptr)
wire->children.push_back(range);
SET_AST_NODE_LOC(wire, @1, @3);
SET_AST_NODE_LOC(range, @2, @2);
AstNode *ident = new AstNode(AST_IDENTIFIER);
ident->str = *$3;
wire->str = *$3;
delete $3;
AstNode *loop = ast_stack.back();
AstNode *parent = ast_stack.at(ast_stack.size() - 2);
log_assert(parent->children.back() == loop);
// loop variable initialization
AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5);
loop->children.push_back(asgn);
SET_AST_NODE_LOC(asgn, @3, @5);
SET_AST_NODE_LOC(ident, @3, @3);
// inject a wrapping block to declare the loop variable and
// contain the current loop
AstNode *wrapper = new AstNode(AST_BLOCK);
wrapper->str = "$fordecl_block$" + std::to_string(autoidx++);
wrapper->children.push_back(wire);
wrapper->children.push_back(loop);
parent->children.back() = wrapper; // replaces `loop`
};
2013-01-05 04:13:26 -06:00
// this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt:
2019-09-19 14:43:13 -05:00
defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
2015-02-20 03:21:36 -06:00
non_opt_delay behavioral_stmt |
2020-05-21 11:46:26 -05:00
simple_behavioral_stmt ';' |
2020-05-11 11:33:19 -05:00
attr ';' {
free_attr($1);
} |
2020-05-14 18:10:11 -05:00
attr hierarchical_id {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_TCALL);
2020-05-14 18:10:11 -05:00
node->str = *$2;
delete $2;
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
2020-05-14 18:10:11 -05:00
append_attr(node, $1);
2013-01-05 04:13:26 -06:00
} opt_arg_list ';'{
2020-11-28 20:40:36 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @5);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
2020-05-14 18:10:11 -05:00
attr TOK_MSG_TASKS {
2019-06-10 18:52:06 -05:00
AstNode *node = new AstNode(AST_TCALL);
2020-05-14 18:10:11 -05:00
node->str = *$2;
delete $2;
2019-06-10 18:52:06 -05:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
2020-05-14 18:10:11 -05:00
append_attr(node, $1);
2019-06-10 18:52:06 -05:00
} opt_arg_list ';'{
2020-11-28 20:40:36 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @5);
2019-06-10 18:52:06 -05:00
ast_stack.pop_back();
} |
2020-03-27 11:21:45 -05:00
attr TOK_BEGIN {
enterTypeScope();
} opt_label {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
2020-03-27 11:21:45 -05:00
if ($4 != NULL)
node->str = *$4;
2013-01-05 04:13:26 -06:00
} behavioral_stmt_list TOK_END opt_label {
2020-03-23 15:07:22 -05:00
exitTypeScope();
2021-06-14 14:32:01 -05:00
checkLabelsMatch("Begin label", $4, $8);
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
AstNode *node = ast_stack.back();
// In SystemVerilog, unnamed blocks with block item declarations
// create an implicit hierarchy scope
if (sv_mode && node->str.empty())
for (const AstNode* child : node->children)
if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER
|| child->type == AST_LOCALPARAM || child->type == AST_TYPEDEF) {
node->str = "$unnamed_block$" + std::to_string(autoidx++);
break;
}
2020-04-17 01:23:03 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @8);
2020-03-27 11:21:45 -05:00
delete $4;
delete $8;
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
attr TOK_FOR '(' {
AstNode *node = new AstNode(AST_FOR);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
2021-08-30 12:35:36 -05:00
} for_initialization ';' expr {
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back($7);
} ';' simple_behavioral_stmt ')' {
AstNode *block = new AstNode(AST_BLOCK);
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
block->str = "$for_loop$" + std::to_string(autoidx++);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @13, @13);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @13);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
2014-06-06 10:40:04 -05:00
attr TOK_WHILE '(' expr ')' {
AstNode *node = new AstNode(AST_WHILE);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back($4);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @7, @7);
2014-06-06 10:40:04 -05:00
ast_stack.pop_back();
ast_stack.pop_back();
} |
attr TOK_REPEAT '(' expr ')' {
AstNode *node = new AstNode(AST_REPEAT);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back($4);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @7, @7);
2014-06-06 10:40:04 -05:00
ast_stack.pop_back();
ast_stack.pop_back();
} |
2013-01-05 04:13:26 -06:00
attr TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_CASE);
AstNode *block = new AstNode(AST_BLOCK);
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block);
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(cond, @4, @4);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4));
node->children.push_back(cond);
ast_stack.push_back(node);
ast_stack.push_back(block);
append_attr(node, $1);
2020-02-23 01:19:52 -06:00
} behavioral_stmt {
SET_AST_NODE_LOC(ast_stack.back(), @7, @7);
} optional_else {
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @9);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
2017-02-23 09:33:19 -06:00
case_attr case_type '(' expr ')' {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_CASE, $4);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @4, @4);
2013-01-05 04:13:26 -06:00
} opt_synopsys_attr case_body TOK_ENDCASE {
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @9);
2013-01-05 04:13:26 -06:00
case_type_stack.pop_back();
ast_stack.pop_back();
};
2021-02-22 12:19:42 -06:00
case_attr:
attr {
$$ = $1;
2017-02-23 09:33:19 -06:00
} |
2021-02-22 12:19:42 -06:00
attr TOK_UNIQUE0 {
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
$$ = $1;
2017-02-23 09:33:19 -06:00
} |
2021-02-22 12:19:42 -06:00
attr TOK_PRIORITY {
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
$$ = $1;
} |
attr TOK_UNIQUE {
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
2017-02-23 09:33:19 -06:00
$$ = $1;
};
2013-01-05 04:13:26 -06:00
case_type:
2015-07-02 04:14:30 -05:00
TOK_CASE {
2013-01-05 04:13:26 -06:00
case_type_stack.push_back(0);
} |
2015-07-02 04:14:30 -05:00
TOK_CASEX {
2013-01-05 04:13:26 -06:00
case_type_stack.push_back('x');
} |
2015-07-02 04:14:30 -05:00
TOK_CASEZ {
2013-01-05 04:13:26 -06:00
case_type_stack.push_back('z');
};
opt_synopsys_attr:
opt_synopsys_attr TOK_SYNOPSYS_FULL_CASE {
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->attributes.count(ID::full_case) == 0)
ast_stack.back()->attributes[ID::full_case] = AstNode::mkconst_int(1, false);
2013-01-05 04:13:26 -06:00
} |
opt_synopsys_attr TOK_SYNOPSYS_PARALLEL_CASE {
2020-03-12 14:57:01 -05:00
if (ast_stack.back()->attributes.count(ID::parallel_case) == 0)
ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false);
2013-01-05 04:13:26 -06:00
} |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
behavioral_stmt_list:
behavioral_stmt_list behavioral_stmt |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
optional_else:
TOK_ELSE {
AstNode *block = new AstNode(AST_BLOCK);
AstNode *cond = new AstNode(AST_COND, new AstNode(AST_DEFAULT), block);
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(cond, @1, @1);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
ast_stack.back()->children.push_back(cond);
ast_stack.push_back(block);
2020-02-23 01:19:52 -06:00
} behavioral_stmt {
SET_AST_NODE_LOC(ast_stack.back(), @3, @3);
} |
2020-07-14 17:04:23 -05:00
%empty %prec FAKE_THEN;
2013-01-05 04:13:26 -06:00
case_body:
case_body case_item |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
case_item:
{
2016-04-21 08:31:54 -05:00
AstNode *node = new AstNode(
case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
case_type_stack.push_back(0);
2015-02-10 05:17:29 -06:00
} behavioral_stmt {
2013-01-05 04:13:26 -06:00
case_type_stack.pop_back();
2020-02-23 01:19:52 -06:00
SET_AST_NODE_LOC(ast_stack.back(), @4, @4);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
ast_stack.pop_back();
};
2013-12-04 14:06:54 -06:00
gen_case_body:
gen_case_body gen_case_item |
2020-07-14 17:04:23 -05:00
%empty;
2013-12-04 14:06:54 -06:00
gen_case_item:
{
2016-04-21 08:31:54 -05:00
AstNode *node = new AstNode(
case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
2013-12-04 14:06:54 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
case_type_stack.push_back(0);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @2);
2020-05-11 12:20:33 -05:00
} gen_stmt_block {
2013-12-04 14:06:54 -06:00
case_type_stack.pop_back();
ast_stack.pop_back();
};
2013-01-05 04:13:26 -06:00
case_select:
case_expr_list ':' |
TOK_DEFAULT;
case_expr_list:
TOK_DEFAULT {
2020-03-09 19:43:03 -05:00
AstNode *node = new AstNode(AST_DEFAULT);
SET_AST_NODE_LOC(node, @1, @1);
ast_stack.back()->children.push_back(node);
2013-01-05 04:13:26 -06:00
} |
2019-03-10 18:27:18 -05:00
TOK_SVA_LABEL {
2020-03-09 19:43:03 -05:00
AstNode *node = new AstNode(AST_IDENTIFIER);
SET_AST_NODE_LOC(node, @1, @1);
ast_stack.back()->children.push_back(node);
2019-03-10 18:27:18 -05:00
ast_stack.back()->children.back()->str = *$1;
delete $1;
} |
2013-01-05 04:13:26 -06:00
expr {
ast_stack.back()->children.push_back($1);
} |
case_expr_list ',' expr {
ast_stack.back()->children.push_back($3);
};
2013-02-26 06:18:22 -06:00
rvalue:
2013-07-04 07:12:33 -05:00
hierarchical_id '[' expr ']' '.' rvalue {
2013-02-26 06:18:22 -06:00
$$ = new AstNode(AST_PREFIX, $3, $6);
$$->str = *$1;
2021-08-02 19:42:34 -05:00
SET_AST_NODE_LOC($$, @1, @6);
2013-02-26 06:18:22 -06:00
delete $1;
} |
2013-07-04 07:12:33 -05:00
hierarchical_id range {
2013-02-26 06:18:22 -06:00
$$ = new AstNode(AST_IDENTIFIER, $2);
2013-01-05 04:13:26 -06:00
$$->str = *$1;
2020-03-17 01:21:10 -05:00
SET_AST_NODE_LOC($$, @1, @1);
2013-01-05 04:13:26 -06:00
delete $1;
2018-02-23 06:14:47 -06:00
if ($2 == nullptr && ($$->str == "\\$initstate" ||
$$->str == "\\$anyconst" || $$->str == "\\$anyseq" ||
$$->str == "\\$allconst" || $$->str == "\\$allseq"))
2016-07-21 07:23:22 -05:00
$$->type = AST_FCALL;
2013-11-20 03:51:32 -06:00
} |
2014-08-06 08:43:46 -05:00
hierarchical_id non_opt_multirange {
$$ = new AstNode(AST_IDENTIFIER, $2);
2013-11-20 03:51:32 -06:00
$$->str = *$1;
2020-03-17 01:21:10 -05:00
SET_AST_NODE_LOC($$, @1, @1);
2013-11-20 03:51:32 -06:00
delete $1;
2013-02-26 06:18:22 -06:00
};
lvalue:
rvalue {
$$ = $1;
2013-01-05 04:13:26 -06:00
} |
'{' lvalue_concat_list '}' {
$$ = $2;
};
lvalue_concat_list:
expr {
$$ = new AstNode(AST_CONCAT);
$$->children.push_back($1);
} |
expr ',' lvalue_concat_list {
$$ = $3;
$$->children.push_back($1);
};
opt_arg_list:
'(' arg_list optional_comma ')' |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
arg_list:
arg_list2 |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
arg_list2:
single_arg |
arg_list ',' single_arg;
single_arg:
expr {
ast_stack.back()->children.push_back($1);
};
module_gen_body:
2014-06-06 16:05:01 -05:00
module_gen_body gen_stmt_or_module_body_stmt |
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
module_gen_body gen_block |
2020-07-14 17:04:23 -05:00
%empty;
2013-01-05 04:13:26 -06:00
2014-06-06 16:05:01 -05:00
gen_stmt_or_module_body_stmt:
2020-05-11 12:20:33 -05:00
gen_stmt | module_body_stmt |
attr ';' {
free_attr($1);
};
2014-06-06 16:05:01 -05:00
2021-08-31 12:45:02 -05:00
genvar_identifier:
TOK_ID {
$$ = new AstNode(AST_IDENTIFIER);
$$->str = *$1;
delete $1;
};
genvar_initialization:
TOK_GENVAR genvar_identifier {
frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!");
} |
TOK_GENVAR genvar_identifier '=' expr {
if (!sv_mode)
frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!");
AstNode *node = new AstNode(AST_GENVAR);
node->is_reg = true;
node->is_signed = true;
node->range_left = 31;
node->range_right = 0;
node->str = $2->str;
node->children.push_back(checkRange(node, nullptr));
ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @4);
node = new AstNode(AST_ASSIGN_EQ, $2, $4);
ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @4);
} |
genvar_identifier '=' expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @1, @3);
};
2013-01-05 04:13:26 -06:00
// this production creates the obligatory if-else shift/reduce conflict
gen_stmt:
TOK_FOR '(' {
AstNode *node = new AstNode(AST_GENFOR);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
2021-08-31 12:45:02 -05:00
} genvar_initialization ';' expr {
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back($6);
2013-12-04 14:06:54 -06:00
} ';' simple_behavioral_stmt ')' gen_stmt_block {
2020-03-30 15:14:51 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @1, @11);
2021-08-31 12:45:02 -05:00
rewriteGenForDeclInit(ast_stack.back());
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_GENIF);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
ast_stack.back()->children.push_back($3);
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
} gen_stmt_block opt_gen_else {
2020-03-30 15:14:51 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
2013-12-04 14:06:54 -06:00
ast_stack.pop_back();
} |
case_type '(' expr ')' {
AstNode *node = new AstNode(AST_GENCASE, $3);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} gen_case_body TOK_ENDCASE {
case_type_stack.pop_back();
2020-03-30 15:14:51 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
} |
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
TOK_MSG_TASKS {
AstNode *node = new AstNode(AST_TECALL);
node->str = *$1;
delete $1;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} opt_arg_list ';'{
SET_AST_NODE_LOC(ast_stack.back(), @1, @3);
ast_stack.pop_back();
};
gen_block:
2020-03-27 11:21:45 -05:00
TOK_BEGIN {
enterTypeScope();
} opt_label {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_GENBLOCK);
2020-03-27 11:21:45 -05:00
node->str = $3 ? *$3 : std::string();
2013-01-05 04:13:26 -06:00
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} module_gen_body TOK_END opt_label {
2020-03-23 15:07:22 -05:00
exitTypeScope();
2021-06-14 14:32:01 -05:00
checkLabelsMatch("Begin label", $3, $7);
2020-03-27 11:21:45 -05:00
delete $3;
delete $7;
2020-03-30 15:14:51 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @1, @7);
2013-01-05 04:13:26 -06:00
ast_stack.pop_back();
2014-06-06 16:05:01 -05:00
};
2013-12-04 14:06:54 -06:00
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
// result is wrapped in a genblock only if necessary
2013-12-04 14:06:54 -06:00
gen_stmt_block:
{
AstNode *node = new AstNode(AST_GENBLOCK);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
2014-06-06 16:05:01 -05:00
} gen_stmt_or_module_body_stmt {
2020-03-30 15:14:51 -05:00
SET_AST_NODE_LOC(ast_stack.back(), @2, @2);
2013-12-04 14:06:54 -06:00
ast_stack.pop_back();
verilog: significant block scoping improvements
This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.
Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.
1. Unlabled generate blocks are now implicitly named according to the LRM in
`label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
synthetic unnamed generate block to avoid creating extra hierarchy levels
where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
of the topmost scope, which is necessary because such wires and cells often
appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
scope, completely deferring the inspection and elaboration of nested scopes;
names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
in largely the same manner as other blocks
before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode
Addresses the following issues: 656, 2423, 2493
2021-01-27 12:30:22 -06:00
} | gen_block;
2013-01-05 04:13:26 -06:00
opt_gen_else:
2020-07-14 17:04:23 -05:00
TOK_ELSE gen_stmt_block | %empty %prec FAKE_THEN;
2013-01-05 04:13:26 -06:00
expr:
basic_expr {
$$ = $1;
} |
basic_expr '?' attr expr ':' expr {
$$ = new AstNode(AST_TERNARY);
$$->children.push_back($1);
$$->children.push_back($4);
$$->children.push_back($6);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @$);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
2023-09-05 21:19:28 -05:00
} |
inc_or_dec_op attr rvalue {
$$ = addIncOrDecExpr($3, $2, $1, @1, @3, false);
} |
// TODO: Attributes are allowed in the middle here, but they create some
// non-trivial conflicts that don't seem worth solving for now.
rvalue inc_or_dec_op {
$$ = addIncOrDecExpr($1, nullptr, $2, @1, @2, true);
2013-01-05 04:13:26 -06:00
};
basic_expr:
2013-02-26 06:18:22 -06:00
rvalue {
$$ = $1;
} |
2020-03-11 12:21:44 -05:00
'(' expr ')' integral_number {
2019-08-07 14:20:08 -05:00
if ($4->compare(0, 1, "'") != 0)
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
2014-02-01 06:50:23 -06:00
AstNode *bits = $2;
2019-04-20 15:24:50 -05:00
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
2014-02-01 06:50:23 -06:00
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $4->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
delete $4;
} |
2020-03-11 12:21:44 -05:00
hierarchical_id integral_number {
2019-08-07 14:20:08 -05:00
if ($2->compare(0, 1, "'") != 0)
2018-10-24 18:37:56 -05:00
frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
2014-02-01 06:50:23 -06:00
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC(bits, @1, @1);
2019-04-20 15:24:50 -05:00
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
2020-04-10 17:37:36 -05:00
SET_AST_NODE_LOC(val, @2, @2);
2014-02-01 06:50:23 -06:00
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
delete $1;
delete $2;
} |
2020-03-11 12:21:44 -05:00
integral_number {
2019-04-20 15:24:50 -05:00
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
2020-04-10 17:37:36 -05:00
SET_AST_NODE_LOC($$, @1, @1);
2013-06-07 06:59:13 -05:00
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
2013-01-05 04:13:26 -06:00
delete $1;
} |
2014-06-14 05:00:47 -05:00
TOK_REALVAL {
2014-06-13 04:29:23 -05:00
$$ = new AstNode(AST_REALVALUE);
2016-08-06 06:16:23 -05:00
char *p = (char*)malloc(GetSize(*$1) + 1), *q;
for (int i = 0, j = 0; j < GetSize(*$1); j++)
if ((*$1)[j] != '_')
p[i++] = (*$1)[j], p[i] = 0;
2014-06-13 04:29:23 -05:00
$$->realvalue = strtod(p, &q);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @1);
2014-06-13 04:29:23 -05:00
log_assert(*q == 0);
delete $1;
free(p);
} |
2013-01-05 04:13:26 -06:00
TOK_STRING {
2013-12-05 05:53:49 -06:00
$$ = AstNode::mkconst_str(*$1);
2020-04-10 17:37:36 -05:00
SET_AST_NODE_LOC($$, @1, @1);
2013-01-05 04:13:26 -06:00
delete $1;
} |
2013-07-04 07:12:33 -05:00
hierarchical_id attr {
2013-01-05 04:13:26 -06:00
AstNode *node = new AstNode(AST_FCALL);
node->str = *$1;
delete $1;
ast_stack.push_back(node);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC(node, @1, @1);
2013-01-05 04:13:26 -06:00
append_attr(node, $2);
} '(' arg_list optional_comma ')' {
$$ = ast_stack.back();
ast_stack.pop_back();
} |
TOK_TO_SIGNED attr '(' expr ')' {
$$ = new AstNode(AST_TO_SIGNED, $4);
append_attr($$, $2);
} |
TOK_TO_UNSIGNED attr '(' expr ')' {
$$ = new AstNode(AST_TO_UNSIGNED, $4);
append_attr($$, $2);
} |
'(' expr ')' {
$$ = $2;
} |
2015-02-20 03:21:36 -06:00
'(' expr ':' expr ':' expr ')' {
delete $2;
$$ = $4;
delete $6;
} |
2013-01-05 04:13:26 -06:00
'{' concat_list '}' {
$$ = $2;
} |
2014-11-12 12:10:35 -06:00
'{' expr '{' concat_list '}' '}' {
2013-01-05 04:13:26 -06:00
$$ = new AstNode(AST_REPLICATE, $2, $4);
} |
'~' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_BIT_NOT, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
basic_expr '&' attr basic_expr {
$$ = new AstNode(AST_BIT_AND, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
2017-06-01 05:43:21 -05:00
basic_expr OP_NAND attr basic_expr {
$$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_AND, $1, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2017-06-01 05:43:21 -05:00
append_attr($$, $3);
} |
2013-01-05 04:13:26 -06:00
basic_expr '|' attr basic_expr {
$$ = new AstNode(AST_BIT_OR, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
2017-06-01 05:43:21 -05:00
basic_expr OP_NOR attr basic_expr {
$$ = new AstNode(AST_BIT_NOT, new AstNode(AST_BIT_OR, $1, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2017-06-01 05:43:21 -05:00
append_attr($$, $3);
} |
2013-01-05 04:13:26 -06:00
basic_expr '^' attr basic_expr {
$$ = new AstNode(AST_BIT_XOR, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_XNOR attr basic_expr {
$$ = new AstNode(AST_BIT_XNOR, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
'&' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_AND, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
2013-06-13 04:18:45 -05:00
OP_NAND attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_AND, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-06-13 04:18:45 -05:00
append_attr($$, $2);
$$ = new AstNode(AST_LOGIC_NOT, $$);
} |
2013-01-05 04:13:26 -06:00
'|' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_OR, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
2013-06-13 04:18:45 -05:00
OP_NOR attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_OR, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-06-13 04:18:45 -05:00
append_attr($$, $2);
$$ = new AstNode(AST_LOGIC_NOT, $$);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-06-13 04:18:45 -05:00
} |
2013-01-05 04:13:26 -06:00
'^' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_XOR, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
OP_XNOR attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_REDUCE_XNOR, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
basic_expr OP_SHL attr basic_expr {
2019-12-04 05:59:36 -06:00
$$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_SHR attr basic_expr {
2019-12-04 05:59:36 -06:00
$$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_SSHL attr basic_expr {
2019-12-04 05:59:36 -06:00
$$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_SSHR attr basic_expr {
2019-12-04 05:59:36 -06:00
$$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '<' attr basic_expr {
$$ = new AstNode(AST_LT, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_LE attr basic_expr {
$$ = new AstNode(AST_LE, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_EQ attr basic_expr {
$$ = new AstNode(AST_EQ, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_NE attr basic_expr {
$$ = new AstNode(AST_NE, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
2013-12-27 06:50:08 -06:00
basic_expr OP_EQX attr basic_expr {
$$ = new AstNode(AST_EQX, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-12-27 06:50:08 -06:00
append_attr($$, $3);
} |
basic_expr OP_NEX attr basic_expr {
$$ = new AstNode(AST_NEX, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-12-27 06:50:08 -06:00
append_attr($$, $3);
} |
2013-01-05 04:13:26 -06:00
basic_expr OP_GE attr basic_expr {
$$ = new AstNode(AST_GE, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '>' attr basic_expr {
$$ = new AstNode(AST_GT, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '+' attr basic_expr {
$$ = new AstNode(AST_ADD, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '-' attr basic_expr {
$$ = new AstNode(AST_SUB, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '*' attr basic_expr {
$$ = new AstNode(AST_MUL, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '/' attr basic_expr {
$$ = new AstNode(AST_DIV, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr '%' attr basic_expr {
$$ = new AstNode(AST_MOD, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_POW attr basic_expr {
$$ = new AstNode(AST_POW, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
'+' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_POS, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
'-' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_NEG, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
} |
basic_expr OP_LAND attr basic_expr {
$$ = new AstNode(AST_LOGIC_AND, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
basic_expr OP_LOR attr basic_expr {
$$ = new AstNode(AST_LOGIC_OR, $1, $4);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @4);
2013-01-05 04:13:26 -06:00
append_attr($$, $3);
} |
'!' attr basic_expr %prec UNARY_OPS {
$$ = new AstNode(AST_LOGIC_NOT, $3);
2020-03-09 19:43:03 -05:00
SET_AST_NODE_LOC($$, @1, @3);
2013-01-05 04:13:26 -06:00
append_attr($$, $2);
2020-06-14 17:15:59 -05:00
} |
TOK_SIGNED OP_CAST '(' expr ')' {
if (!sv_mode)
frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode.");
$$ = new AstNode(AST_TO_SIGNED, $4);
SET_AST_NODE_LOC($$, @1, @4);
} |
TOK_UNSIGNED OP_CAST '(' expr ')' {
if (!sv_mode)
frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode.");
$$ = new AstNode(AST_TO_UNSIGNED, $4);
SET_AST_NODE_LOC($$, @1, @4);
} |
basic_expr OP_CAST '(' expr ')' {
if (!sv_mode)
frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode.");
$$ = new AstNode(AST_CAST_SIZE, $1, $4);
SET_AST_NODE_LOC($$, @1, @4);
2023-09-05 21:19:28 -05:00
} |
'(' expr '=' expr ')' {
ensureAsgnExprAllowed();
AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $4);
ast_stack.back()->children.push_back(node);
SET_AST_NODE_LOC(node, @2, @4);
$$ = $2->clone();
} |
'(' expr asgn_binop expr ')' {
ensureAsgnExprAllowed();
$$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone();
2013-01-05 04:13:26 -06:00
};
concat_list:
expr {
$$ = new AstNode(AST_CONCAT, $1);
} |
expr ',' concat_list {
$$ = $3;
$$->children.push_back($1);
};
2020-03-11 12:21:44 -05:00
integral_number:
TOK_CONSTVAL { $$ = $1; } |
TOK_UNBASED_UNSIZED_CONSTVAL { $$ = $1; } |
TOK_BASE TOK_BASED_CONSTVAL {
$1->append(*$2);
$$ = $1;
delete $2;
} |
TOK_CONSTVAL TOK_BASE TOK_BASED_CONSTVAL {
$1->append(*$2).append(*$3);
$$ = $1;
delete $2;
delete $3;
};