mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 14:13:23 +00:00
Merge 10bb0f472f
into 0fcf5c080d
This commit is contained in:
commit
b8ed809d26
6 changed files with 204 additions and 17 deletions
|
@ -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
|
||||
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"
|
||||
(defined by using the ``parallel_case`` attribute or detected by an
|
||||
optimization).
|
||||
(defined by using the ``parallel_case`` attribute, the ``unique`` or ``unique0``
|
||||
SystemVerilog keywords, or detected by an optimization).
|
||||
|
||||
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``
|
||||
|
|
|
@ -377,7 +377,7 @@ from SystemVerilog:
|
|||
- Assignments within expressions are supported.
|
||||
|
||||
- The ``unique``, ``unique0``, and ``priority`` SystemVerilog keywords are
|
||||
accepted on ``if`` and ``case`` conditionals. (Those keywords are currently
|
||||
handled in the same way as their equivalent ``full_case`` and
|
||||
``parallel_case`` attributes on ``case`` statements, and checked
|
||||
for syntactic validity but otherwise ignored on ``if`` statements.)
|
||||
supported on ``if`` and ``case`` conditionals. (The Verilog frontend
|
||||
will process conditionals using these keywords by annotating their
|
||||
representation with the appropriate ``full_case`` and/or ``parallel_case``
|
||||
attributes, which are described above.)
|
||||
|
|
|
@ -2873,16 +2873,34 @@ behavioral_stmt:
|
|||
ast_stack.pop_back();
|
||||
} |
|
||||
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 *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);
|
||||
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);
|
||||
} behavioral_stmt {
|
||||
SET_AST_NODE_LOC(ast_stack.back(), @7, @7);
|
||||
} optional_else {
|
||||
|
@ -2908,21 +2926,25 @@ if_attr:
|
|||
} |
|
||||
attr TOK_UNIQUE0 {
|
||||
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.");
|
||||
$$ = $1; // accept unique0 keyword, but ignore it for now
|
||||
(*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false);
|
||||
$$ = $1;
|
||||
} |
|
||||
attr TOK_PRIORITY {
|
||||
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.");
|
||||
$$ = $1; // accept priority keyword, but ignore it for now
|
||||
(*$1)[ID::full_case] = AstNode::mkconst_int(1, false);
|
||||
$$ = $1;
|
||||
} |
|
||||
attr TOK_UNIQUE {
|
||||
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.");
|
||||
$$ = $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:
|
||||
|
|
57
tests/proc/case_attr.ys
Normal file
57
tests/proc/case_attr.ys
Normal 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
|
54
tests/verilog/unique_priority_case.ys
Normal file
54
tests/verilog/unique_priority_case.ys
Normal 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
|
54
tests/verilog/unique_priority_if.ys
Normal file
54
tests/verilog/unique_priority_if.ys
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue