Merge pull request #1338 from larsclausen/byte-array-string-literal
Support assignment of string literals to byte arrays
This commit is contained in:
commit
99c7a9f940
6
PExpr.h
6
PExpr.h
|
|
@ -690,12 +690,16 @@ class PEString : public PExpr {
|
||||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||||
width_mode_t&mode) override;
|
width_mode_t&mode) override;
|
||||||
|
|
||||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*scope,
|
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||||
ivl_type_t type, unsigned flags) const override;
|
ivl_type_t type, unsigned flags) const override;
|
||||||
|
|
||||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||||
unsigned expr_wid, unsigned) const override;
|
unsigned expr_wid, unsigned) const override;
|
||||||
|
|
||||||
|
NetExpr *elaborate_expr_uarray_(Design *des, NetScope *scope,
|
||||||
|
const netuarray_t *uarray_type,
|
||||||
|
const std::vector<netrange_t> &dims,
|
||||||
|
unsigned int cur_dim) const;
|
||||||
private:
|
private:
|
||||||
char*text_;
|
char*text_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
86
elab_expr.cc
86
elab_expr.cc
|
|
@ -344,6 +344,9 @@ NetExpr* PEAssignPattern::elaborate_expr_uarray_(Design *des, NetScope *scope,
|
||||||
if (const auto ap = dynamic_cast<PEAssignPattern*>(parms_[idx])) {
|
if (const auto ap = dynamic_cast<PEAssignPattern*>(parms_[idx])) {
|
||||||
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
|
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
|
||||||
dims, cur_dim, need_const);
|
dims, cur_dim, need_const);
|
||||||
|
} else if (auto s = dynamic_cast<PEString*>(parms_[idx])) {
|
||||||
|
expr = s->elaborate_expr_uarray_(des, scope, uarray_type,
|
||||||
|
dims, cur_dim);
|
||||||
} else if (dynamic_cast<PEConcat*>(parms_[idx])) {
|
} else if (dynamic_cast<PEConcat*>(parms_[idx])) {
|
||||||
cerr << get_fileline() << ": sorry: "
|
cerr << get_fileline() << ": sorry: "
|
||||||
<< "Array concatenation is not yet supported."
|
<< "Array concatenation is not yet supported."
|
||||||
|
|
@ -6986,13 +6989,86 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t, unsigned) const
|
NetExpr* PEString::elaborate_expr_uarray_(Design *des, NetScope *,
|
||||||
|
const netuarray_t *uarray_type,
|
||||||
|
const std::vector<netrange_t> &dims,
|
||||||
|
unsigned int cur_dim) const
|
||||||
{
|
{
|
||||||
NetECString*tmp = new NetECString(value());
|
// This is a special case. The LRM allows string literals to be
|
||||||
tmp->cast_signed(signed_flag_);
|
// assigned to unpacked arrays of bytes.
|
||||||
tmp->set_line(*this);
|
const auto element_type = uarray_type->element_type();
|
||||||
|
|
||||||
return tmp;
|
if (dims.size() - 1 != cur_dim || !element_type->packed() ||
|
||||||
|
element_type->base_type() != IVL_VT_BOOL ||
|
||||||
|
element_type->packed_width() != 8 || !element_type->get_signed()) {
|
||||||
|
cerr << get_fileline() << ": error: "
|
||||||
|
<< "String literal can not be implicitly cast to the target type."
|
||||||
|
<< endl;
|
||||||
|
des->errors++;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The size doesn't have to match. Elements are copied left aligned, which
|
||||||
|
// is different from assignments of string literals to packed arrays where
|
||||||
|
// they are copied right aligned.
|
||||||
|
|
||||||
|
vector<NetExpr*> elem_exprs(dims[cur_dim].width());
|
||||||
|
bool asc = dims[cur_dim].get_msb() < dims[cur_dim].get_lsb();
|
||||||
|
unsigned int elem_idx = asc ? 0 : elem_exprs.size() - 1;
|
||||||
|
|
||||||
|
verinum text_val(text_);
|
||||||
|
|
||||||
|
if (text_val.len() > elem_exprs.size() * 8) {
|
||||||
|
cerr << get_fileline() << ": warning: "
|
||||||
|
<< "Target array smaller than assigned value. "
|
||||||
|
<< "Value will be truncated." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < min((size_t)text_val.len() / 8, elem_exprs.size()); i++) {
|
||||||
|
verinum val(text_val >> (text_val.len() - 8 - i * 8), 8);
|
||||||
|
val.has_sign(true);
|
||||||
|
|
||||||
|
elem_exprs[elem_idx] = new NetEConst(element_type, val);
|
||||||
|
|
||||||
|
if (asc)
|
||||||
|
elem_idx++;
|
||||||
|
else
|
||||||
|
elem_idx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add padding if necessary
|
||||||
|
for (unsigned int i = text_val.len() / 8; i < elem_exprs.size(); i++) {
|
||||||
|
verinum val(verinum::V0, 8);
|
||||||
|
val.has_sign(true);
|
||||||
|
|
||||||
|
elem_exprs[elem_idx] = new NetEConst(element_type, val);
|
||||||
|
|
||||||
|
if (asc)
|
||||||
|
elem_idx++;
|
||||||
|
else
|
||||||
|
elem_idx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NetEArrayPattern(uarray_type, elem_exprs);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetExpr* PEString::elaborate_expr(Design *des, NetScope *scope, ivl_type_t type, unsigned) const
|
||||||
|
{
|
||||||
|
NetExpr *expr;
|
||||||
|
|
||||||
|
auto uarray_type = dynamic_cast<const netuarray_t*>(type);
|
||||||
|
if (uarray_type) {
|
||||||
|
expr = elaborate_expr_uarray_(des, scope, uarray_type,
|
||||||
|
uarray_type->static_dimensions(), 0);
|
||||||
|
} else {
|
||||||
|
expr = new NetECString(value());
|
||||||
|
expr->cast_signed(signed_flag_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr)
|
||||||
|
expr->set_line(*this);
|
||||||
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,8 @@ NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &l
|
||||||
<< endl;
|
<< endl;
|
||||||
des->errors++;
|
des->errors++;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (dynamic_cast<PEAssignPattern*> (expr)) {
|
} else if (dynamic_cast<PEAssignPattern*> (expr) ||
|
||||||
|
dynamic_cast<PEString*> (expr)) {
|
||||||
auto net_expr = elaborate_rval_expr(des, scope, lval->array_type(), expr);
|
auto net_expr = elaborate_rval_expr(des, scope, lval->array_type(), expr);
|
||||||
if (! net_expr) return nullptr;
|
if (! net_expr) return nullptr;
|
||||||
expr_net = net_expr->synthesize(des, scope, net_expr);
|
expr_net = net_expr->synthesize(des, scope, net_expr);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Check that string literals can be assigned to one-dimensional byte arrays.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit failed = 1'b0;
|
||||||
|
|
||||||
|
`define check(val, exp) do \
|
||||||
|
if (val !== exp) begin \
|
||||||
|
$display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \
|
||||||
|
`"val`", exp, val); \
|
||||||
|
failed = 1'b1; \
|
||||||
|
end \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
byte desc [3:0] = "AB\n";
|
||||||
|
byte asc [0:3];
|
||||||
|
byte unsized [4];
|
||||||
|
|
||||||
|
assign asc = "AB\n";
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
|
||||||
|
`check(desc[3], 8'h41);
|
||||||
|
`check(desc[2], 8'h42);
|
||||||
|
`check(desc[1], 8'h0a);
|
||||||
|
`check(desc[0], 8'h00);
|
||||||
|
|
||||||
|
`check(asc[0], 8'h41);
|
||||||
|
`check(asc[1], 8'h42);
|
||||||
|
`check(asc[2], 8'h0a);
|
||||||
|
`check(asc[3], 8'h00);
|
||||||
|
|
||||||
|
unsized = "AB\n";
|
||||||
|
`check(unsized[0], 8'h41);
|
||||||
|
`check(unsized[1], 8'h42);
|
||||||
|
`check(unsized[2], 8'h0a);
|
||||||
|
`check(unsized[3], 8'h00);
|
||||||
|
|
||||||
|
if (!failed) begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Check that string literals can be assigned to nested byte arrays using
|
||||||
|
// assignment patterns.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit failed = 1'b0;
|
||||||
|
|
||||||
|
`define check(val, exp) do \
|
||||||
|
if (val !== exp) begin \
|
||||||
|
$display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \
|
||||||
|
`"val`", exp, val); \
|
||||||
|
failed = 1'b1; \
|
||||||
|
end \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
byte desc [0:1][3:0] = '{"AB\n", "CD\t"};
|
||||||
|
byte asc [1:0][0:3];
|
||||||
|
byte unsized [2][4];
|
||||||
|
|
||||||
|
assign asc = '{"AB\n", "CD\t"};
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
|
||||||
|
`check(desc[0][3], 8'h41);
|
||||||
|
`check(desc[0][2], 8'h42);
|
||||||
|
`check(desc[0][1], 8'h0a);
|
||||||
|
`check(desc[0][0], 8'h00);
|
||||||
|
|
||||||
|
`check(desc[1][3], 8'h43);
|
||||||
|
`check(desc[1][2], 8'h44);
|
||||||
|
`check(desc[1][1], 8'h09);
|
||||||
|
`check(desc[1][0], 8'h00);
|
||||||
|
|
||||||
|
`check(asc[0][0], 8'h43);
|
||||||
|
`check(asc[0][1], 8'h44);
|
||||||
|
`check(asc[0][2], 8'h09);
|
||||||
|
`check(asc[0][3], 8'h00);
|
||||||
|
|
||||||
|
`check(asc[1][0], 8'h41);
|
||||||
|
`check(asc[1][1], 8'h42);
|
||||||
|
`check(asc[1][2], 8'h0a);
|
||||||
|
`check(asc[1][3], 8'h00);
|
||||||
|
|
||||||
|
unsized = '{"AB\n", "CD\t"};
|
||||||
|
`check(unsized[0][0], 8'h41);
|
||||||
|
`check(unsized[0][1], 8'h42);
|
||||||
|
`check(unsized[0][2], 8'h0a);
|
||||||
|
`check(unsized[0][3], 8'h00);
|
||||||
|
|
||||||
|
`check(unsized[1][0], 8'h43);
|
||||||
|
`check(unsized[1][1], 8'h44);
|
||||||
|
`check(unsized[1][2], 8'h09);
|
||||||
|
`check(unsized[1][3], 8'h00);
|
||||||
|
|
||||||
|
if (!failed) begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Check that string literals shorter than the target byte array are padded
|
||||||
|
// with null bytes.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit failed = 1'b0;
|
||||||
|
|
||||||
|
`define check(val, exp) do \
|
||||||
|
if (val !== exp) begin \
|
||||||
|
$display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \
|
||||||
|
`"val`", exp, val); \
|
||||||
|
failed = 1'b1; \
|
||||||
|
end \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
byte desc [3:0] = "AB";
|
||||||
|
byte asc [0:3];
|
||||||
|
byte unsized [4];
|
||||||
|
|
||||||
|
assign asc = "AB";
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
|
||||||
|
`check(desc[3], 8'h41);
|
||||||
|
`check(desc[2], 8'h42);
|
||||||
|
`check(desc[1], 8'h00);
|
||||||
|
`check(desc[0], 8'h00);
|
||||||
|
|
||||||
|
`check(asc[0], 8'h41);
|
||||||
|
`check(asc[1], 8'h42);
|
||||||
|
`check(asc[2], 8'h00);
|
||||||
|
`check(asc[3], 8'h00);
|
||||||
|
|
||||||
|
unsized = "AB";
|
||||||
|
`check(unsized[0], 8'h41);
|
||||||
|
`check(unsized[1], 8'h42);
|
||||||
|
`check(unsized[2], 8'h00);
|
||||||
|
`check(unsized[3], 8'h00);
|
||||||
|
|
||||||
|
if (!failed) begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Check that string literals longer than the target byte array are truncated.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit failed = 1'b0;
|
||||||
|
|
||||||
|
`define check(val, exp) do \
|
||||||
|
if (val !== exp) begin \
|
||||||
|
$display("FAILED(%0d). '%s' expected %02h, got %02h", `__LINE__, \
|
||||||
|
`"val`", exp, val); \
|
||||||
|
failed = 1'b1; \
|
||||||
|
end \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
byte desc [1:0] = "ABC";
|
||||||
|
byte asc [0:1];
|
||||||
|
byte unsized [2];
|
||||||
|
|
||||||
|
assign asc = "ABC";
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
|
||||||
|
`check(desc[1], 8'h41);
|
||||||
|
`check(desc[0], 8'h42);
|
||||||
|
|
||||||
|
`check(asc[0], 8'h41);
|
||||||
|
`check(asc[1], 8'h42);
|
||||||
|
|
||||||
|
unsized = "ABCD";
|
||||||
|
`check(unsized[0], 8'h41);
|
||||||
|
`check(unsized[1], 8'h42);
|
||||||
|
|
||||||
|
if (!failed) begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Check that string literals cannot be assigned to unpacked arrays whose
|
||||||
|
// element type is 4-state.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
logic [7:0] value [0:3] = "AB"; // Error: target element type is 4-state
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Check that string literals cannot be assigned directly to multi-dimensional
|
||||||
|
// byte arrays.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
byte value [0:1][0:3] = "AB"; // Error: string is not nested
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Check that string literals cannot be connected to output byte array ports.
|
||||||
|
|
||||||
|
module M (
|
||||||
|
output byte out [0:1]
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
out = "CD";
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
M i_m("AB"); // Error: output expression is not assignable
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Check that string literals cannot be assigned to unpacked arrays whose
|
||||||
|
// element type is narrower than 8 bits.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit [6:0] value [0:3] = "AB"; // Error: target element type is too narrow
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Check that string literals cannot be assigned to unpacked arrays whose
|
||||||
|
// element type is wider than 8 bits.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit [8:0] value [0:3] = "AB"; // Error: target element type is too wide
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -226,6 +226,15 @@ sv_array_cassign6 vvp_tests/sv_array_cassign6.json
|
||||||
sv_array_cassign7 vvp_tests/sv_array_cassign7.json
|
sv_array_cassign7 vvp_tests/sv_array_cassign7.json
|
||||||
sv_array_cassign8 vvp_tests/sv_array_cassign8.json
|
sv_array_cassign8 vvp_tests/sv_array_cassign8.json
|
||||||
sv_automatic_2state vvp_tests/sv_automatic_2state.json
|
sv_automatic_2state vvp_tests/sv_automatic_2state.json
|
||||||
|
sv_byte_array_string1 vvp_tests/sv_byte_array_string1.json
|
||||||
|
sv_byte_array_string2 vvp_tests/sv_byte_array_string2.json
|
||||||
|
sv_byte_array_string3 vvp_tests/sv_byte_array_string3.json
|
||||||
|
sv_byte_array_string4 vvp_tests/sv_byte_array_string4.json
|
||||||
|
sv_byte_array_string_fail1 vvp_tests/sv_byte_array_string_fail1.json
|
||||||
|
sv_byte_array_string_fail2 vvp_tests/sv_byte_array_string_fail2.json
|
||||||
|
sv_byte_array_string_fail3 vvp_tests/sv_byte_array_string_fail3.json
|
||||||
|
sv_byte_array_string_fail4 vvp_tests/sv_byte_array_string_fail4.json
|
||||||
|
sv_byte_array_string_fail5 vvp_tests/sv_byte_array_string_fail5.json
|
||||||
sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json
|
sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json
|
||||||
sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json
|
sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json
|
||||||
sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json
|
sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_byte_array_string1.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_byte_array_string2.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_byte_array_string3.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_byte_array_string4.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "CE",
|
||||||
|
"source" : "sv_byte_array_string_fail1.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "CE",
|
||||||
|
"source" : "sv_byte_array_string_fail2.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "CE",
|
||||||
|
"source" : "sv_byte_array_string_fail3.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "CE",
|
||||||
|
"source" : "sv_byte_array_string_fail4.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"type" : "CE",
|
||||||
|
"source" : "sv_byte_array_string_fail5.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue