mirror of https://github.com/YosysHQ/yosys.git
sv: fix two struct access bugs
- preserve signedness of struct members - fix initial width detection of struct members (e.g., in case expressions)
This commit is contained in:
parent
1aab608cff
commit
a9c8ca21d5
|
@ -370,6 +370,9 @@ namespace AST
|
||||||
|
|
||||||
// Helper for setting the src attribute.
|
// Helper for setting the src attribute.
|
||||||
void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);
|
void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);
|
||||||
|
|
||||||
|
// struct helper exposed from simplify for genrtlil
|
||||||
|
AstNode *make_struct_member_range(AstNode *node, AstNode *member_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace AST_INTERNAL
|
namespace AST_INTERNAL
|
||||||
|
|
|
@ -812,6 +812,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
||||||
if (children.size() > 1)
|
if (children.size() > 1)
|
||||||
range = children[1];
|
range = children[1];
|
||||||
|
} else if (id_ast->type == AST_STRUCT_ITEM) {
|
||||||
|
AstNode *tmp_range = make_struct_member_range(this, id_ast);
|
||||||
|
this_width = tmp_range->range_left - tmp_range->range_right + 1;
|
||||||
|
delete tmp_range;
|
||||||
} else
|
} else
|
||||||
log_file_error(filename, location.first_line, "Failed to detect width for identifier %s!\n", str.c_str());
|
log_file_error(filename, location.first_line, "Failed to detect width for identifier %s!\n", str.c_str());
|
||||||
if (range) {
|
if (range) {
|
||||||
|
|
|
@ -456,7 +456,7 @@ static AstNode *slice_range(AstNode *rnode, AstNode *snode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node)
|
AstNode *AST::make_struct_member_range(AstNode *node, AstNode *member_node)
|
||||||
{
|
{
|
||||||
// Work out the range in the packed array that corresponds to a struct member
|
// Work out the range in the packed array that corresponds to a struct member
|
||||||
// taking into account any range operations applicable to the current node
|
// taking into account any range operations applicable to the current node
|
||||||
|
@ -1693,6 +1693,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
newNode = new AstNode(AST_IDENTIFIER, range);
|
newNode = new AstNode(AST_IDENTIFIER, range);
|
||||||
newNode->str = sname;
|
newNode->str = sname;
|
||||||
newNode->basic_prep = true;
|
newNode->basic_prep = true;
|
||||||
|
if (item_node->is_signed)
|
||||||
|
newNode = new AstNode(AST_TO_SIGNED, newNode);
|
||||||
goto apply_newNode;
|
goto apply_newNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
module top;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic a;
|
||||||
|
logic signed b;
|
||||||
|
byte c;
|
||||||
|
byte unsigned d;
|
||||||
|
reg [3:0] e;
|
||||||
|
reg signed [3:0] f;
|
||||||
|
struct packed {
|
||||||
|
logic a;
|
||||||
|
logic signed b;
|
||||||
|
} x;
|
||||||
|
struct packed signed {
|
||||||
|
logic a;
|
||||||
|
logic signed b;
|
||||||
|
} y;
|
||||||
|
} S;
|
||||||
|
S s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// test codegen for LHS
|
||||||
|
s.a = '1;
|
||||||
|
s.b = '1;
|
||||||
|
s.c = '1;
|
||||||
|
s.d = '1;
|
||||||
|
s.e = '1;
|
||||||
|
s.f = '1;
|
||||||
|
s.x.a = '1;
|
||||||
|
s.x.b = '1;
|
||||||
|
s.y.a = '1;
|
||||||
|
s.y.b = '1;
|
||||||
|
end
|
||||||
|
|
||||||
|
`define CHECK(expr, width, signedness) \
|
||||||
|
case (expr) \
|
||||||
|
1'sb1: \
|
||||||
|
case (expr) \
|
||||||
|
2'sb11: if (!(signedness)) fail = 1; \
|
||||||
|
default: if (signedness) fail = 1; \
|
||||||
|
endcase \
|
||||||
|
default: if (signedness) fail = 1; \
|
||||||
|
endcase \
|
||||||
|
case (expr) \
|
||||||
|
1'b1: if ((width) != 1) fail = 1; \
|
||||||
|
2'b11: if ((width) != 2) fail = 1; \
|
||||||
|
3'b111: if ((width) != 3) fail = 1; \
|
||||||
|
4'b1111: if ((width) != 4) fail = 1; \
|
||||||
|
5'b1111_1: if ((width) != 5) fail = 1; \
|
||||||
|
6'b1111_11: if ((width) != 6) fail = 1; \
|
||||||
|
7'b1111_11: if ((width) != 7) fail = 1; \
|
||||||
|
8'b1111_1111: if ((width) != 8) fail = 1; \
|
||||||
|
9'b1111_1111_1: if ((width) != 9) fail = 1; \
|
||||||
|
default: fail = 1; \
|
||||||
|
endcase \
|
||||||
|
begin \
|
||||||
|
reg [9:0] indirect; \
|
||||||
|
indirect = (expr); \
|
||||||
|
if ((indirect != (expr)) != (signedness)) fail = 1; \
|
||||||
|
indirect = $unsigned(expr); \
|
||||||
|
if ($countones(indirect) != (width)) fail = 1; \
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
reg fail;
|
||||||
|
fail = 0;
|
||||||
|
|
||||||
|
`CHECK(s.a, 1, 0)
|
||||||
|
`CHECK(s.b, 1, 1)
|
||||||
|
`CHECK(s.c, 8, 1)
|
||||||
|
`CHECK(s.d, 8, 0)
|
||||||
|
`CHECK(s.e, 4, 0)
|
||||||
|
`CHECK(s.f, 4, 1)
|
||||||
|
|
||||||
|
`CHECK(s.x.a, 1, 0)
|
||||||
|
`CHECK(s.x.b, 1, 1)
|
||||||
|
`CHECK(s.y.a, 1, 0)
|
||||||
|
`CHECK(s.y.b, 1, 1)
|
||||||
|
|
||||||
|
// TODO(zachjs): support access to whole sub-structs and unions
|
||||||
|
// `CHECK(s.x, 2, 0)
|
||||||
|
// `CHECK(s.y, 2, 1)
|
||||||
|
|
||||||
|
assert (fail === 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,4 @@
|
||||||
|
read_verilog -formal -sv struct_access.sv
|
||||||
|
proc
|
||||||
|
opt -full
|
||||||
|
sat -verify -seq 1 -prove-asserts -show-all
|
Loading…
Reference in New Issue