Merge pull request #590 from larsclausen/packed-type-cast

Add support for explicit cast to packed array, packed struct and enum
This commit is contained in:
Stephen Williams 2022-01-17 12:27:11 -08:00 committed by GitHub
commit 9898bffd41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 143 additions and 36 deletions

View File

@ -1007,6 +1007,7 @@ class PECastType : public PExpr {
private:
data_type_t* target_;
ivl_type_t target_type_;
PExpr* base_;
};

View File

@ -148,7 +148,7 @@ NetEConst* NetEConst::dup_expr() const
NetEConstEnum* NetEConstEnum::dup_expr() const
{
NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value());
NetEConstEnum*tmp = new NetEConstEnum(name_, enum_set_, value());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;

View File

@ -1969,8 +1969,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
des->errors += 1;
}
netenum_t::iterator item = netenum->first_name();
NetEConstEnum*tmp = new NetEConstEnum(scope, item->first,
netenum, item->second);
NetEConstEnum*tmp = new NetEConstEnum(item->first, netenum, item->second);
tmp->set_line(*li);
delete expr; // The elaborated enum variable is not needed.
return tmp;
@ -1987,8 +1986,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
des->errors += 1;
}
netenum_t::iterator item = netenum->last_name();
NetEConstEnum*tmp = new NetEConstEnum(scope, item->first,
netenum, item->second);
NetEConstEnum*tmp = new NetEConstEnum(item->first, netenum, item->second);
tmp->set_line(*li);
delete expr; // The elaborated enum variable is not needed.
return tmp;
@ -3351,25 +3349,25 @@ NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&)
{
ivl_type_t t = target_->elaborate_type(des, scope);
target_type_ = target_->elaborate_type(des, scope);
width_mode_t tmp_mode = PExpr::SIZED;
base_->test_width(des, scope, tmp_mode);
if (const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(t)) {
if (const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(target_type_)) {
expr_type_ = use_darray->element_base_type();
expr_width_ = use_darray->element_width();
} else if (const netstring_t*use_string = dynamic_cast<const netstring_t*>(t)) {
} else if (const netstring_t*use_string = dynamic_cast<const netstring_t*>(target_type_)) {
expr_type_ = use_string->base_type();
expr_width_ = 8;
} else {
expr_type_ = t->base_type();
expr_width_ = t->packed_width();
expr_type_ = target_type_->base_type();
expr_width_ = target_type_->packed_width();
}
min_width_ = expr_width_;
signed_flag_ = t->get_signed();
signed_flag_ = target_type_->get_signed();
return expr_width_;
}
@ -3427,11 +3425,8 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
}
NetExpr*tmp = 0;
if (dynamic_cast<const atom2_type_t*>(target_)) {
tmp = cast_to_int2(sub, expr_width_);
}
if (const vector_type_t*vec = dynamic_cast<const vector_type_t*>(target_)) {
switch (vec->base_type) {
if (target_type_ && target_type_->packed()) {
switch (target_type_->base_type()) {
case IVL_VT_BOOL:
tmp = cast_to_int2(sub, expr_width_);
break;
@ -3452,7 +3447,7 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
// the signedness pushed down from the main expression.
tmp = cast_to_width(sub, expr_width_, sub->has_sign(), *this);
}
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
return pad_to_width(tmp, expr_wid, signed_flag_, *this, target_type_);
}
if (dynamic_cast<const string_type_t*>(target_)) {

View File

@ -1,4 +1,4 @@
// This is currently unsupported, but is legal code.
// Test that cast to enum works in procedural assignments
module test();
typedef enum { a, b, c } enum_type;
@ -7,6 +7,12 @@ enum_type enum_value;
initial begin
enum_value = enum_type'(1);
if (enum_value == b) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -1,4 +1,4 @@
// This is currently unsupported, but is legal code.
// Test that cast to enum works in continuous assignments
module test();
typedef enum { a, b, c } enum_type;
@ -7,4 +7,12 @@ enum_type enum_value;
assign enum_value = enum_type'(1);
initial begin
if (enum_value == b) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,43 @@
// This tests SystemVerilog casting support
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Iztok Jeras.
// Extended by Maciej Suminski
// Copied and modified by Martin Whitaker
// Copied and modified again by Lars-Peter Clausen
module test();
typedef logic [7:0] pa08;
typedef pa08 [1:0] pa16;
typedef pa16 [1:0] pa32;
typedef pa32 [1:0] pa64;
// variables used in casting
pa08 var_08;
pa16 var_16;
pa32 var_32;
pa64 var_64;
real var_real;
// error counter
bit err = 0;
initial begin
var_08 = pa08'(4'h5); if (var_08 !== 8'h05) begin $display("FAILED -- var_08 = 'h%0h != 8'h05", var_08); err=1; end
var_16 = pa16'(var_08); if (var_16 !== 16'h05) begin $display("FAILED -- var_16 = 'h%0h != 16'h05", var_16); err=1; end
var_32 = pa32'(var_16); if (var_32 !== 32'h05) begin $display("FAILED -- var_32 = 'h%0h != 32'h05", var_32); err=1; end
var_64 = pa64'(var_32); if (var_64 !== 64'h05) begin $display("FAILED -- var_64 = 'h%0h != 64'h05", var_64); err=1; end
var_real = 13.4; var_08 = pa08'(var_real); if (var_08 !== 13) begin $display("FAILED -- var_08 = %d != 13", var_08); err=1; end
var_real = 14.5; var_16 = pa16'(var_real); if (var_16 !== 15) begin $display("FAILED -- var_16 = %d != 15", var_16); err=1; end
var_real = 15.6; var_32 = pa32'(var_real); if (var_32 !== 16) begin $display("FAILED -- var_32 = %d != 16", var_32); err=1; end
var_real = -15.6; var_64 = pa64'(var_real); if (var_64 !== -16) begin $display("FAILED -- var_64 = %d != -16", var_64); err=1; end
var_08 = pa08'(4'hf); if (var_08 !== 8'h0f) begin $display("FAILED -- var_08 = 'h%0h != 8'h0f", var_08); err=1; end
var_16 = pa08'(16'h0f0f); if (var_16 !== 16'h0f) begin $display("FAILED -- var_16 = 'h%0h != 16'h0f", var_16); err=1; end
if (!err) $display("PASSED");
end
endmodule // test

View File

@ -0,0 +1,45 @@
// This tests SystemVerilog casting support
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Iztok Jeras.
// Extended by Maciej Suminski
// Copied and modified by Martin Whitaker
// Copied and modified again by Lars-Peter Clausen
module test();
typedef struct packed signed { logic [7:0] x; } s08;
typedef struct packed signed { logic [15:0] x; } s16;
typedef struct packed signed { int x; } s32;
typedef struct packed signed { int x; shortint y; byte z; logic [7:0] w; } s64;
// variables used in casting
s08 var_08;
s16 var_16;
s32 var_32;
s64 var_64;
real var_real;
// error counter
bit err = 0;
initial begin
var_08 = s08'(4'sh5); if (var_08 !== 8'sh05) begin $display("FAILED -- var_08 = 'h%0h != 8'h05", var_08); err=1; end
var_16 = s16'(var_08); if (var_16 !== 16'sh05) begin $display("FAILED -- var_16 = 'h%0h != 16'h05", var_16); err=1; end
var_32 = s32'(var_16); if (var_32 !== 32'sh05) begin $display("FAILED -- var_32 = 'h%0h != 32'h05", var_32); err=1; end
var_64 = s64'(var_32); if (var_64 !== 64'sh05) begin $display("FAILED -- var_64 = 'h%0h != 64'h05", var_64); err=1; end
var_real = 13.4; var_08 = s08'(var_real); if (var_08 !== 13) begin $display("FAILED -- var_08 = %d != 13", var_08); err=1; end
var_real = 14.5; var_16 = s16'(var_real); if (var_16 !== 15) begin $display("FAILED -- var_16 = %d != 15", var_16); err=1; end
var_real = 15.6; var_32 = s32'(var_real); if (var_32 !== 16) begin $display("FAILED -- var_32 = %d != 16", var_32); err=1; end
var_real = -15.6; var_64 = s64'(var_real); if (var_64 !== -16) begin $display("FAILED -- var_64 = %d != -16", var_64); err=1; end
var_08 = s08'(4'hf); if (var_08 !== 8'sh0f) begin $display("FAILED -- var_08 = 'h%0h != 8'h0f", var_08); err=1; end
var_08 = s08'(4'shf); if (var_08 !== 8'shff) begin $display("FAILED -- var_08 = 'h%0h != 8'hff", var_08); err=1; end
var_16 = s08'(16'h0f0f); if (var_16 !== 16'sh0f) begin $display("FAILED -- var_16 = 'h%0h != 16'h0f", var_16); err=1; end
var_16 = s08'(4'shf) + 'd0; if (var_16 !== 16'shff) begin $display("FAILED -- var_16 = 'h%0h != 16'hff", var_16); err=1; end
if (!err) $display("PASSED");
end
endmodule // test

View File

@ -115,8 +115,6 @@ br605b normal ivltests
br971 normal ivltests
br1005 normal ivltests
br1015b normal ivltests
br_gh130b normal ivltests
br_gh386d normal ivltests
br_ml20150315b normal ivltests
sv_deferred_assert1 normal ivltests
sv_deferred_assert2 normal ivltests

View File

@ -294,8 +294,6 @@ br605b EF ivltests
br971 EF ivltests
br1005 CE,-g2009 ivltests
br1015b CE,-g2009 ivltests
br_gh130b CE,-g2009 ivltests
br_gh386d CE,-g2009 ivltests
br_ml20150315b CE,-g2009 ivltests
sv_deferred_assert1 CE,-g2009 ivltests gold=sv_deferred_assert1.gold
sv_deferred_assert2 CE,-g2009 ivltests gold=sv_deferred_assert2.gold

View File

@ -149,6 +149,7 @@ br_gh112e normal,-g2009 ivltests
br_gh112f normal,-g2009 ivltests
br_gh129 normal,-g2009 ivltests
br_gh130a CE,-g2009 ivltests
br_gh130b normal,-g2009 ivltests
br_gh165 normal,-g2009 ivltests gold=br_gh165.gold
br_gh164a normal,-g2009 ivltests
br_gh164b normal,-g2009 ivltests
@ -184,6 +185,7 @@ br_gh374 normal,-g2009 ivltests gold=br_gh374.gold
br_gh386a normal,-g2009 ivltests
br_gh386b normal,-g2009 ivltests
br_gh386c CE,-g2009 ivltests
br_gh386d normal,-g2009 ivltests
br_gh388 normal,-g2009 ivltests gold=br_gh388.gold
br_gh391 normal,-g2009 ivltests gold=br_gh391.gold
br_gh411 normal,-g2009 ivltests
@ -388,6 +390,8 @@ sv-constants normal,-g2005-sv ivltests
sv_array_assign_pattern2 normal,-g2009 ivltests
sv_cast_integer normal,-g2005-sv ivltests
sv_cast_integer2 normal,-g2005-sv ivltests
sv_cast_packed_array normal,-g2005-sv ivltests
sv_cast_packed_struct normal,-g2005-sv ivltests
sv_cast_string normal,-g2005-sv ivltests
sv_class1 normal,-g2009 ivltests
sv_class2 normal,-g2009 ivltests

View File

@ -118,6 +118,7 @@ cast_real_signed CE,-pallowsigned=1 ivltests
cast_real_unsigned CE ivltests
sv_cast_integer normal,-g2005-sv,-pallowsigned=1 ivltests
sv_cast_integer2 normal,-g2005-sv,-pallowsigned=1 ivltests
sv_cast_packed_struct normal,-g2005-sv,-pallowsigned=1 ivltests
sv_cast_string CE ivltests
clog2 CE ivltests # Also big int
delayed_sfunc CE ivltests
@ -733,6 +734,7 @@ br_gh99r normal,-pallowsigned=1 ivltests
br_gh112e normal,-g2009,-pallowsigned=1 ivltests
br_gh112f normal,-g2009,-pallowsigned=1 ivltests
br_gh129 normal,-g2009,-pallowsigned=1 ivltests
br_gh130b normal,-g2009,-pallowsigned=1 ivltests
br_gh198 normal,-pallowsigned=1 ivltests gold=br_gh198.gold
br_gh199a normal,-pallowsigned=1 ivltests
br_gh199b normal,-pallowsigned=1 ivltests
@ -743,6 +745,7 @@ br_gh283a normal,-pallowsigned=1 ivltests
br_gh283b normal,-pallowsigned=1 ivltests
br_gh283c normal,-pallowsigned=1 ivltests
br_gh289b normal,-g2009,-pallowsigned=1 ivltests
br_gh386d normal,-g2009,-pallowsigned=1 ivltests
br_gh477 normal,-g2009,-pallowsigned=1 ivltests
br_gh540 normal,-g2009,-pallowsigned=1 ivltests
ca_mult normal,-pallowsigned=1 ivltests gold=ca_mult.gold

View File

@ -263,8 +263,8 @@ void NetEConcat::set(unsigned idx, NetExpr*e)
expr_width( expr_width() + repeat_ * e->expr_width() );
}
NetEConstEnum::NetEConstEnum(Definitions*s, perm_string n, const netenum_t*eset, const verinum&v)
: NetEConst(v), scope_(s), enum_set_(eset), name_(n)
NetEConstEnum::NetEConstEnum(perm_string n, const netenum_t*eset, const verinum&v)
: NetEConst(v), enum_set_(eset), name_(n)
{
assert(has_width());
}

View File

@ -55,7 +55,7 @@ bool Definitions::add_enumeration_name(netenum_t*enum_set, perm_string name)
netenum_t::iterator enum_val = enum_set->find_name(name);
assert(enum_val != enum_set->end_name());
NetEConstEnum*val = new NetEConstEnum(this, name, enum_set, enum_val->second);
NetEConstEnum*val = new NetEConstEnum(name, enum_set, enum_val->second);
pair<map<perm_string,NetEConstEnum*>::iterator, bool> cur;
cur = enum_names_.insert(make_pair(name,val));

View File

@ -2153,8 +2153,8 @@ class NetEConst : public NetExpr {
class NetEConstEnum : public NetEConst {
public:
explicit NetEConstEnum(Definitions*scope, perm_string name,
const netenum_t*enum_set, const verinum&val);
explicit NetEConstEnum(perm_string name, const netenum_t*enum_set,
const verinum&val);
~NetEConstEnum();
perm_string name() const;
@ -2166,7 +2166,6 @@ class NetEConstEnum : public NetEConst {
virtual NetEConstEnum* dup_expr() const;
private:
Definitions*scope_;
const netenum_t*enum_set_;
perm_string name_;
};

View File

@ -161,13 +161,13 @@ inline NetScope* symbol_search(const LineInfo*li,
* signed_flag.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info);
const LineInfo&info, ivl_type_t use_type = 0);
/*
* This version determines the extension method from the base expression type.
*/
inline NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
inline NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info, ivl_type_t use_type = 0)
{
return pad_to_width(expr, wid, expr->has_sign(), info);
return pad_to_width(expr, wid, expr->has_sign(), info, use_type);
}
/*

View File

@ -19,15 +19,16 @@
# include "config.h"
# include "netenum.h"
# include "netlist.h"
# include "netvector.h"
# include "netmisc.h"
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info)
const LineInfo&info, ivl_type_t use_type)
{
if (wid <= expr->expr_width()) {
if (wid <= expr->expr_width() && !use_type) {
expr->cast_signed(signed_flag);
return expr;
}
@ -38,13 +39,19 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
verinum oval = tmp->value();
oval.has_sign(signed_flag);
oval = pad_to_width(oval, wid);
tmp = new NetEConst(oval);
if (const netenum_t *enum_type = dynamic_cast<const netenum_t *>(use_type)) {
// The name of the enum is set to <nil> here, but the name is
// only used in debugging output, so this is ok
tmp = new NetEConstEnum(perm_string(), enum_type, oval);
} else {
tmp = new NetEConst(oval);
}
tmp->set_line(info);
delete expr;
return tmp;
}
NetESelect*tmp = new NetESelect(expr, 0, wid);
NetESelect*tmp = new NetESelect(expr, 0, wid, use_type);
tmp->cast_signed(signed_flag);
tmp->set_line(info);
return tmp;