mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-27 02:45:52 +00:00
sv: support assignments within expressions
- Add support for assignments within expressions, e.g., `x[y++] = z;` or `x = (y *= 2) - 1;`. The logic is handled entirely within the parser by injecting statements into the current procedural block. - Add support for pre-increment/decrement statements, which are behaviorally equivalent to post-increment/decrement statements. - Fix non-standard attribute position used for post-increment/decrement statements.
This commit is contained in:
parent
83b1a57eed
commit
4edb1a1921
15 changed files with 231 additions and 24 deletions
|
@ -292,6 +292,61 @@ static void rewriteGenForDeclInit(AstNode *loop)
|
|||
substitute(incr);
|
||||
}
|
||||
|
||||
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
|
||||
static const AstNode *addIncOrDecStmt(AstNode *lhs, dict<IdString, AstNode*> *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end)
|
||||
{
|
||||
AstNode *one = AstNode::mkconst_int(1, true);
|
||||
AstNode *rhs = new AstNode(op, lhs->clone(), one);
|
||||
AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs);
|
||||
SET_AST_NODE_LOC(stmt, begin, end);
|
||||
if (attr != nullptr)
|
||||
append_attr(stmt, attr);
|
||||
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();
|
||||
const AstNode *stmt = addIncOrDecStmt(lhs, attr, op, begin, end);
|
||||
log_assert(stmt->type == AST_ASSIGN_EQ);
|
||||
AstNode *expr = stmt->children[0]->clone();
|
||||
if (undo) {
|
||||
AstNode *minus_one = AstNode::mkconst_int(-1, true);
|
||||
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;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%define api.prefix {frontend_verilog_yy}
|
||||
|
@ -358,7 +413,7 @@ static void rewriteGenForDeclInit(AstNode *loop)
|
|||
%type <integer> integer_atom_type integer_vector_type
|
||||
%type <al> attr case_attr
|
||||
%type <ast> struct_union
|
||||
%type <ast_node_type> asgn_binop
|
||||
%type <ast_node_type> asgn_binop inc_or_dec_op
|
||||
%type <ast> genvar_identifier
|
||||
|
||||
%type <specify_target_ptr> specify_target
|
||||
|
@ -2610,17 +2665,15 @@ simple_behavioral_stmt:
|
|||
SET_AST_NODE_LOC(node, @2, @5);
|
||||
append_attr(node, $1);
|
||||
} |
|
||||
attr lvalue TOK_INCREMENT {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true)));
|
||||
ast_stack.back()->children.push_back(node);
|
||||
SET_AST_NODE_LOC(node, @2, @3);
|
||||
append_attr(node, $1);
|
||||
attr lvalue attr inc_or_dec_op {
|
||||
// The position 1 attr to avoid shift/reduce conflicts with the
|
||||
// other productions. We reject attributes in that position.
|
||||
if (!$1->empty())
|
||||
frontend_verilog_yyerror("Attributes are not allowed on this size of the lvalue in an inc_or_dec_expression!");
|
||||
addIncOrDecStmt($2, $3, $4, @1, @4);
|
||||
} |
|
||||
attr lvalue TOK_DECREMENT {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true)));
|
||||
ast_stack.back()->children.push_back(node);
|
||||
SET_AST_NODE_LOC(node, @2, @3);
|
||||
append_attr(node, $1);
|
||||
inc_or_dec_op attr lvalue {
|
||||
addIncOrDecStmt($3, $2, $1, @1, @3);
|
||||
} |
|
||||
attr lvalue OP_LE delay expr {
|
||||
AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5);
|
||||
|
@ -2629,18 +2682,7 @@ simple_behavioral_stmt:
|
|||
append_attr(node, $1);
|
||||
} |
|
||||
attr lvalue asgn_binop delay expr {
|
||||
AstNode *expr_node = $5;
|
||||
if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT ||
|
||||
$3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) {
|
||||
expr_node = new AstNode(AST_TO_UNSIGNED, expr_node);
|
||||
SET_AST_NODE_LOC(expr_node, @5, @5);
|
||||
}
|
||||
AstNode *op_node = new AstNode($3, $2->clone(), expr_node);
|
||||
AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node);
|
||||
SET_AST_NODE_LOC(op_node, @2, @5);
|
||||
SET_AST_NODE_LOC(node, @2, @5);
|
||||
ast_stack.back()->children.push_back(node);
|
||||
append_attr(node, $1);
|
||||
addAsgnBinopStmt($1, $2, $3, $5, @2, @5);
|
||||
};
|
||||
|
||||
asgn_binop:
|
||||
|
@ -2657,6 +2699,12 @@ asgn_binop:
|
|||
TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } |
|
||||
TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ;
|
||||
|
||||
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; } ;
|
||||
|
||||
for_initialization:
|
||||
TOK_ID '=' expr {
|
||||
AstNode *ident = new AstNode(AST_IDENTIFIER);
|
||||
|
@ -3149,6 +3197,14 @@ expr:
|
|||
$$->children.push_back($6);
|
||||
SET_AST_NODE_LOC($$, @1, @$);
|
||||
append_attr($$, $3);
|
||||
} |
|
||||
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);
|
||||
};
|
||||
|
||||
basic_expr:
|
||||
|
@ -3436,6 +3492,17 @@ basic_expr:
|
|||
frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode.");
|
||||
$$ = new AstNode(AST_CAST_SIZE, $1, $4);
|
||||
SET_AST_NODE_LOC($$, @1, @4);
|
||||
} |
|
||||
'(' 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();
|
||||
};
|
||||
|
||||
concat_list:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue