mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-07 06:33:24 +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
|
'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``
|
||||||
|
|
|
@ -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.)
|
||||||
|
|
|
@ -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
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