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,
|
||||
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;
|
||||
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||
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:
|
||||
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])) {
|
||||
expr = ap->elaborate_expr_uarray_(des, scope, uarray_type,
|
||||
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])) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Array concatenation is not yet supported."
|
||||
|
|
@ -6986,13 +6989,86 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
|
|||
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());
|
||||
tmp->cast_signed(signed_flag_);
|
||||
tmp->set_line(*this);
|
||||
// This is a special case. The LRM allows string literals to be
|
||||
// assigned to unpacked arrays of bytes.
|
||||
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;
|
||||
des->errors++;
|
||||
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);
|
||||
if (! net_expr) return nullptr;
|
||||
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_cassign8 vvp_tests/sv_array_cassign8.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_constructor2 vvp_tests/sv_chained_constructor2.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