sv: support remaining assignment operators
authorZachary Snow <zach@zachjs.com>
Sat, 27 Mar 2021 19:59:48 +0000 (15:59 -0400)
committerZachary Snow <zachary.j.snow@gmail.com>
Tue, 25 May 2021 20:15:57 +0000 (16:15 -0400)
- Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>=
- Unify existing support for: +=, -=, &=, |=, ^=

frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y
tests/simple/asgn_binop.sv [new file with mode: 0644]

index 1a6dc96fd021364a538456c6122a9707c06f71ad..f52928c77f87fcc8aa1e076e26319d1c6be6c113 100644 (file)
@@ -544,11 +544,18 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
 
 ".*" { return TOK_WILDCARD_CONNECT; }
 
-"|=" { SV_KEYWORD(TOK_OR_ASSIGN); }
-"&=" { SV_KEYWORD(TOK_AND_ASSIGN); }
-"+=" { SV_KEYWORD(TOK_PLUS_ASSIGN); }
+"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); }
+"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); }
+"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); }
 "-=" { SV_KEYWORD(TOK_SUB_ASSIGN); }
-"^=" { SV_KEYWORD(TOK_XOR_ASSIGN); }
+"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); }
+"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); }
+"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); }
+"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); }
+"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); }
+">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); }
+"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); }
+">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); }
 
 [-+]?[=*]> {
        if (!specify_mode) REJECT;
index dd25f412f177dc4da6e195e0c853b6b2dff806d6..c2b43f45b9e75db44a9c670422c61a24b38ff402 100644 (file)
@@ -260,6 +260,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
        bool boolean;
        char ch;
        int integer;
+       YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type;
 }
 
 %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
@@ -272,7 +273,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
 %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
 %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT
 %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
-%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_PLUS_ASSIGN TOK_ALWAYS TOK_INITIAL
+%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
 %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
 %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
 %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
@@ -286,7 +287,9 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
 %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
 %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_UNIQUE0 TOK_PRIORITY
 %token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_UNION
-%token TOK_OR_ASSIGN TOK_XOR_ASSIGN TOK_AND_ASSIGN TOK_SUB_ASSIGN
+%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
 
 %type <ast> range range_or_multirange non_opt_range non_opt_multirange
 %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
@@ -298,6 +301,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode)
 %type <integer> integer_atom_type
 %type <al> attr case_attr
 %type <ast> struct_union
+%type <ast_node_type> asgn_binop
 
 %type <specify_target_ptr> specify_target
 %type <specify_triple_ptr> specify_triple specify_opt_triple
@@ -2449,47 +2453,35 @@ simple_behavioral_stmt:
                SET_AST_NODE_LOC(node, @2, @5);
                append_attr(node, $1);
        } |
-       attr lvalue TOK_XOR_ASSIGN delay expr {
-               AstNode *xor_node = new AstNode(AST_BIT_XOR, $2->clone(), $5);
-               AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, xor_node);
-               SET_AST_NODE_LOC(xor_node, @2, @5);
-               SET_AST_NODE_LOC(node, @2, @5);
-               ast_stack.back()->children.push_back(node);
-               append_attr(node, $1);
-       } |
-       attr lvalue TOK_OR_ASSIGN delay expr {
-               AstNode *or_node = new AstNode(AST_BIT_OR, $2->clone(), $5);
-               SET_AST_NODE_LOC(or_node, @2, @5);
-               AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, or_node);
-               SET_AST_NODE_LOC(node, @2, @5);
-               ast_stack.back()->children.push_back(node);
-               append_attr(node, $1);
-       } |
-       attr lvalue TOK_PLUS_ASSIGN delay expr {
-               AstNode *add_node = new AstNode(AST_ADD, $2->clone(), $5);
-               AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, add_node);
-               SET_AST_NODE_LOC(node, @2, @5);
-               SET_AST_NODE_LOC(add_node, @2, @5);
-               ast_stack.back()->children.push_back(node);
-               append_attr(node, $1);
-       } |
-       attr lvalue TOK_SUB_ASSIGN delay expr {
-               AstNode *sub_node = new AstNode(AST_SUB, $2->clone(), $5);
-               AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, sub_node);
-               SET_AST_NODE_LOC(node, @2, @5);
-               SET_AST_NODE_LOC(sub_node, @2, @5);
-               ast_stack.back()->children.push_back(node);
-               append_attr(node, $1);
-       } |
-       attr lvalue TOK_AND_ASSIGN delay expr {
-               AstNode *and_node = new AstNode(AST_BIT_AND, $2->clone(), $5);
-               AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, and_node);
+       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);
-               SET_AST_NODE_LOC(and_node, @2, @5);
                ast_stack.back()->children.push_back(node);
                append_attr(node, $1);
        };
 
+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; } ;
+
 // this production creates the obligatory if-else shift/reduce conflict
 behavioral_stmt:
        defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
diff --git a/tests/simple/asgn_binop.sv b/tests/simple/asgn_binop.sv
new file mode 100644 (file)
index 0000000..b134e56
--- /dev/null
@@ -0,0 +1,23 @@
+`define TEST(name, asgnop)\
+       module test_``name ( \
+               input logic [3:0] a, b, \
+               output logic [3:0] c \
+       ); \
+               always @* begin \
+                       c = a; \
+                       c asgnop b; \
+               end \
+       endmodule
+
+`TEST(add, +=)
+`TEST(sub, -=)
+`TEST(mul, *=)
+`TEST(div, /=)
+`TEST(mod, %=)
+`TEST(bit_and, &=)
+`TEST(bit_or , |=)
+`TEST(bit_xor, ^=)
+`TEST(shl, <<=)
+`TEST(shr, >>=)
+`TEST(sshl, <<<=)
+`TEST(sshr, >>>=)