3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-06 22:23:23 +00:00
This commit is contained in:
garytwong 2025-06-04 14:06:34 +00:00 committed by GitHub
commit b8ed809d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 204 additions and 17 deletions

View file

@ -24,8 +24,8 @@ are zero, the value from ``A`` input is sent to the output. If the :math:`n`\
'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of 'th bit from ``S`` is set, the value :math:`n`\ 'th ``WIDTH`` bits wide slice of
the ``B`` input is sent to the output. When more than one bit from ``S`` is set the ``B`` input is sent to the output. When more than one bit from ``S`` is set
the output is undefined. Cells of this type are used to model "parallel cases" the output is undefined. Cells of this type are used to model "parallel cases"
(defined by using the ``parallel_case`` attribute or detected by an (defined by using the ``parallel_case`` attribute, the ``unique`` or ``unique0``
optimization). SystemVerilog keywords, or detected by an optimization).
The `$tribuf` cell is used to implement tristate logic. Cells of this type have The `$tribuf` cell is used to implement tristate logic. Cells of this type have
a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A`` a ``WIDTH`` parameter and inputs ``A`` and ``EN`` and an output ``Y``. The ``A``

View file

@ -377,7 +377,7 @@ from SystemVerilog:
- Assignments within expressions are supported. - Assignments within expressions are supported.
- The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are - The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are
accepted on ``if`` and ``case`` conditionals. (Those keywords are currently supported on ``if`` and ``case`` conditionals. (The Verilog frontend
handled in the same way as their equivalent ``full_case`` and will process conditionals using these keywords by annotating their
``parallel_case`` attributes on ``case`` statements, and checked representation with the appropriate ``full_case`` and/or ``parallel_case``
for syntactic validity but otherwise ignored on ``if`` statements.) attributes, which are described above.)

View file

@ -2873,16 +2873,34 @@ behavioral_stmt:
ast_stack.pop_back(); ast_stack.pop_back();
} | } |
if_attr TOK_IF '(' expr ')' { if_attr TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_CASE); AstNode *node = 0;
AstNode *context = ast_stack.back();
if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if)) {
AstNode *outer = ast_stack[ast_stack.size() - 2];
log_assert (outer && outer->type == AST_CASE);
if (outer->get_bool_attribute(ID::parallel_case)) {
// parallel "else if": append condition to outer "if"
node = outer;
log_assert (node->children.size());
delete node->children.back();
node->children.pop_back();
} else if (outer->get_bool_attribute(ID::full_case))
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
}
AstNode *expr = new AstNode(AST_REDUCE_BOOL, $4);
if (!node) {
// not parallel "else if": begin new construction
node = new AstNode(AST_CASE);
append_attr(node, $1);
ast_stack.back()->children.push_back(node);
node->children.push_back(node->get_bool_attribute(ID::parallel_case) ? AstNode::mkconst_int(1, false, 1) : expr);
}
AstNode *block = new AstNode(AST_BLOCK); AstNode *block = new AstNode(AST_BLOCK);
AstNode *cond = new AstNode(AST_COND, AstNode::mkconst_int(1, false, 1), block); AstNode *cond = new AstNode(AST_COND, node->get_bool_attribute(ID::parallel_case) ? expr : AstNode::mkconst_int(1, false, 1), block);
SET_AST_NODE_LOC(cond, @4, @4); SET_AST_NODE_LOC(cond, @4, @4);
ast_stack.back()->children.push_back(node);
node->children.push_back(new AstNode(AST_REDUCE_BOOL, $4));
node->children.push_back(cond); node->children.push_back(cond);
ast_stack.push_back(node); ast_stack.push_back(node);
ast_stack.push_back(block); ast_stack.push_back(block);
append_attr(node, $1);
} behavioral_stmt { } behavioral_stmt {
SET_AST_NODE_LOC(ast_stack.back(), @7, @7); SET_AST_NODE_LOC(ast_stack.back(), @7, @7);
} optional_else { } optional_else {
@ -2908,21 +2926,25 @@ if_attr:
} | } |
attr TOK_UNIQUE0 { attr TOK_UNIQUE0 {
AstNode *context = ast_stack.back(); AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) ) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch."); frontend_verilog_yyerror("unique0 keyword cannot be used for 'else if' branch.");
$$ = $1; // accept unique0 keyword, but ignore it for now (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
$$ = $1;
} | } |
attr TOK_PRIORITY { attr TOK_PRIORITY {
AstNode *context = ast_stack.back(); AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) ) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch."); frontend_verilog_yyerror("priority keyword cannot be used for 'else if' branch.");
$$ = $1; // accept priority keyword, but ignore it for now (*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
$$ = $1;
} | } |
attr TOK_UNIQUE { attr TOK_UNIQUE {
AstNode *context = ast_stack.back(); AstNode *context = ast_stack.back();
if( context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if) ) if (context && context->type == AST_BLOCK && context->get_bool_attribute(ID::promoted_if))
frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch."); frontend_verilog_yyerror("unique keyword cannot be used for 'else if' branch.");
$$ = $1; // accept unique keyword, but ignore it for now (*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
$$ = $1;
}; };
case_attr: case_attr:

57
tests/proc/case_attr.ys Normal file
View file

@ -0,0 +1,57 @@
read_verilog -sv << EOF
module top (input A, B, C, D, E, F, output reg W, X, Y, Z);
always @* begin
W = F;
(* full_case *)
case (C)
A: W = D;
B: W = E;
endcase
end
always @* begin
X = F;
case (C)
A: X = D;
B: X = E;
endcase
end
always @* begin
Y = F;
(* full_case, parallel_case *)
case (C)
A: Y = D;
B: Y = E;
endcase
end
always @* begin
Z = F;
(* parallel_case *)
case (C)
A: Z = D;
B: Z = E;
endcase
end
endmodule
EOF
prep
# For the ones which use full_case, the F signal shouldn't be included in
# the input cone of W and Y.
select -set full o:W o:Y %u %ci*
select -assert-none i:F @full %i
select -assert-count 1 o:X %ci* i:F %i
select -assert-count 1 o:Z %ci* i:F %i
# And for parallel_case there should be 1 $pmux compared to the 2 $mux
# cells without.
select -assert-none o:W %ci* t:$pmux %i
select -assert-none o:X %ci* t:$pmux %i
select -assert-count 1 o:Y %ci* t:$pmux %i
select -assert-count 1 o:Z %ci* t:$pmux %i
select -assert-count 2 o:W %ci* t:$mux %i
select -assert-count 2 o:X %ci* t:$mux %i
select -assert-none o:Y %ci* t:$mux %i
select -assert-none o:Z %ci* t:$mux %i

View file

@ -0,0 +1,54 @@
read_verilog -sv << EOF
module top (input A, B, C, D, E, F, output reg W, X, Y, Z);
always_comb begin
W = F;
priority case (C)
A: W = D;
B: W = E;
endcase
end
always_comb begin
X = F;
case (C)
A: X = D;
B: X = E;
endcase
end
always_comb begin
Y = F;
unique case (C)
A: Y = D;
B: Y = E;
endcase
end
always_comb begin
Z = F;
unique0 case (C)
A: Z = D;
B: Z = E;
endcase
end
endmodule
EOF
prep
# For the ones which use priority/unique, the F signal shouldn't be included in
# the input cone of W and Y.
select -set full o:W o:Y %u %ci*
select -assert-none i:F @full %i
select -assert-count 1 o:X %ci* i:F %i
select -assert-count 1 o:Z %ci* i:F %i
# And for unique/unique0 there should be 1 $pmux compared to the 2 $mux
# cells without.
select -assert-none o:W %ci* t:$pmux %i
select -assert-none o:X %ci* t:$pmux %i
select -assert-count 1 o:Y %ci* t:$pmux %i
select -assert-count 1 o:Z %ci* t:$pmux %i
select -assert-count 2 o:W %ci* t:$mux %i
select -assert-count 2 o:X %ci* t:$mux %i
select -assert-none o:Y %ci* t:$mux %i
select -assert-none o:Z %ci* t:$mux %i

View file

@ -0,0 +1,54 @@
read_verilog -sv << EOF
module top (input A, B, C, D, E, F, output reg W, X, Y, Z);
always_comb begin
W = F;
priority if (C == A)
W = D;
else if (C == B)
W = E;
end
always_comb begin
X = F;
if (C == A)
X = D;
else if (C == B)
X = E;
end
always_comb begin
Y = F;
unique if (C == A)
Y = D;
else if (C == B)
Y = E;
end
always_comb begin
Z = F;
unique0 if (C == A)
Z = D;
else if (C == B)
Z = E;
end
endmodule
EOF
prep
# For the ones which use priority/unique, the F signal shouldn't be included in
# the input cone of W and Y.
select -set full o:W o:Y %u %ci*
select -assert-none i:F @full %i
select -assert-count 1 o:X %ci* i:F %i
select -assert-count 1 o:Z %ci* i:F %i
# And for unique/unique0 there should be 1 $pmux compared to the 2 $mux
# cells without.
select -assert-none o:W %ci* t:$pmux %i
select -assert-none o:X %ci* t:$pmux %i
select -assert-count 1 o:Y %ci* t:$pmux %i
select -assert-count 1 o:Z %ci* t:$pmux %i
select -assert-count 2 o:W %ci* t:$mux %i
select -assert-count 2 o:X %ci* t:$mux %i
select -assert-none o:Y %ci* t:$mux %i
select -assert-none o:Z %ci* t:$mux %i