Skip to content

Commit dc1c3a4

Browse files
Fix for GitHub issue steveicarus#94 - enhance support for SystemVerilog size casting.
Allow the size expression to be any constant expression. Also ensure that the expression width and type are correctly calculated and applied.
1 parent b5324c7 commit dc1c3a4

File tree

7 files changed

+137
-31
lines changed

7 files changed

+137
-31
lines changed

PExpr.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998-2012 Stephen Williams <[email protected]>
2+
* Copyright (c) 1998-2016 Stephen Williams <[email protected]>
33
* Copyright CERN 2013 / Stephen Williams ([email protected])
44
*
55
* This source code is free software; you can redistribute it
@@ -137,7 +137,7 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
137137
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
138138
}
139139

140-
PECastSize::PECastSize(unsigned si, PExpr*b)
140+
PECastSize::PECastSize(PExpr*si, PExpr*b)
141141
: size_(si), base_(b)
142142
{
143143
}

PExpr.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef IVL_PExpr_H
22
#define IVL_PExpr_H
33
/*
4-
* Copyright (c) 1998-2014 Stephen Williams <[email protected]>
4+
* Copyright (c) 1998-2016 Stephen Williams <[email protected]>
55
* Copyright CERN 2013 / Stephen Williams ([email protected])
66
*
77
* This source code is free software; you can redistribute it
@@ -971,7 +971,7 @@ class PECallFunction : public PExpr {
971971
class PECastSize : public PExpr {
972972

973973
public:
974-
explicit PECastSize(unsigned expr_wid, PExpr*base);
974+
explicit PECastSize(PExpr*size, PExpr*base);
975975
~PECastSize();
976976

977977
void dump(ostream &out) const;
@@ -984,7 +984,7 @@ class PECastSize : public PExpr {
984984
width_mode_t&mode);
985985

986986
private:
987-
unsigned size_;
987+
PExpr* size_;
988988
PExpr* base_;
989989
};
990990

elab_expr.cc

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999-2015 Stephen Williams ([email protected])
2+
* Copyright (c) 1999-2016 Stephen Williams ([email protected])
33
* Copyright CERN 2013 / Stephen Williams ([email protected])
44
*
55
* This source code is free software; you can redistribute it
@@ -2517,22 +2517,54 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
25172517

25182518
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
25192519
{
2520-
expr_width_ = size_;
2520+
ivl_assert(*this, size_);
2521+
ivl_assert(*this, base_);
2522+
2523+
NetExpr*size_ex = elab_and_eval(des, scope, size_, -1, true);
2524+
NetEConst*size_ce = dynamic_cast<NetEConst*>(size_ex);
2525+
expr_width_ = size_ce ? size_ce->value().as_ulong() : 0;
2526+
delete size_ex;
2527+
if (expr_width_ == 0) {
2528+
cerr << get_fileline() << ": error: Cast size expression "
2529+
"must be constant and greater than zero." << endl;
2530+
des->errors += 1;
2531+
return 0;
2532+
}
25212533

25222534
width_mode_t tmp_mode = PExpr::SIZED;
25232535
base_->test_width(des, scope, tmp_mode);
25242536

2525-
return size_;
2537+
if (!type_is_vectorable(base_->expr_type())) {
2538+
cerr << get_fileline() << ": error: Cast base expression "
2539+
"must be a vector type." << endl;
2540+
des->errors += 1;
2541+
return 0;
2542+
}
2543+
2544+
expr_type_ = base_->expr_type();
2545+
min_width_ = expr_width_;
2546+
signed_flag_ = base_->has_sign();
2547+
2548+
return expr_width_;
25262549
}
25272550

25282551
NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
2529-
unsigned, unsigned) const
2552+
unsigned expr_wid, unsigned flags) const
25302553
{
2531-
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
2532-
NetESelect*sel = new NetESelect(sub, 0, size_);
2533-
sel->set_line(*this);
2554+
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
25342555

2535-
return sel;
2556+
ivl_assert(*this, size_);
2557+
ivl_assert(*this, base_);
2558+
2559+
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), flags);
2560+
2561+
// Perform the cast. The extension method (zero/sign), if needed,
2562+
// depends on the type of the base expression.
2563+
NetExpr*tmp = cast_to_width(sub, expr_width_, base_->has_sign(), *this);
2564+
2565+
// Pad up to the expression width. The extension method (zero/sign)
2566+
// depends on the type of enclosing expression.
2567+
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
25362568
}
25372569

25382570
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)

netmisc.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef IVL_netmisc_H
22
#define IVL_netmisc_H
33
/*
4-
* Copyright (c) 1999-2014 Stephen Williams ([email protected])
4+
* Copyright (c) 1999-2016 Stephen Williams ([email protected])
55
*
66
* This source code is free software; you can redistribute it
77
* and/or modify it in source code form under the terms of the GNU
@@ -66,6 +66,27 @@ inline NetScope* symbol_search(const LineInfo*li,
6666
* enough.
6767
*/
6868
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info);
69+
70+
/*
71+
* This function transforms an expression by either zero or sign extending
72+
* the high bits until the expression has the desired width. This may mean
73+
* not transforming the expression at all, if it is already wide enough.
74+
* The extension method and the returned expression type is determined by
75+
* signed_flag.
76+
*/
77+
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
78+
const LineInfo&info);
79+
80+
/*
81+
* This function transforms an expression by either zero or sign extending
82+
* or discarding the high bits until the expression has the desired width.
83+
* This may mean not transforming the expression at all, if it is already
84+
* the correct width. The extension method (if needed) and the returned
85+
* expression type is determined by signed_flag.
86+
*/
87+
extern NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
88+
const LineInfo&info);
89+
6990
extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w,
7091
const LineInfo&info);
7192

pad_to_width.cc

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999-2011 Stephen Williams ([email protected])
2+
* Copyright (c) 1999-2016 Stephen Williams ([email protected])
33
*
44
* This source code is free software; you can redistribute it
55
* and/or modify it in source code form under the terms of the GNU
@@ -51,6 +51,54 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
5151
return tmp;
5252
}
5353

54+
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
55+
const LineInfo&info)
56+
{
57+
if (wid <= expr->expr_width()) {
58+
expr->cast_signed(signed_flag);
59+
return expr;
60+
}
61+
62+
/* If the expression is a const, then replace it with a wider
63+
const. This is a more efficient result. */
64+
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
65+
verinum oval = tmp->value();
66+
oval.has_sign(signed_flag);
67+
oval = pad_to_width(oval, wid);
68+
tmp = new NetEConst(oval);
69+
tmp->set_line(info);
70+
delete expr;
71+
return tmp;
72+
}
73+
74+
NetESelect*tmp = new NetESelect(expr, 0, wid);
75+
tmp->cast_signed(signed_flag);
76+
tmp->set_line(info);
77+
return tmp;
78+
}
79+
80+
NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
81+
const LineInfo&info)
82+
{
83+
/* If the expression is a const, then replace it with a new
84+
const. This is a more efficient result. */
85+
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
86+
tmp->cast_signed(signed_flag);
87+
if (wid != tmp->expr_width()) {
88+
tmp = new NetEConst(verinum(tmp->value(), wid));
89+
tmp->set_line(info);
90+
delete expr;
91+
}
92+
return tmp;
93+
}
94+
95+
NetESelect*tmp = new NetESelect(expr, 0, wid);
96+
tmp->cast_signed(signed_flag);
97+
tmp->set_line(info);
98+
99+
return tmp;
100+
}
101+
54102
/*
55103
* Pad a NetNet to the desired vector width by concatenating a
56104
* NetConst of constant zeros. Use a NetConcat node to do the

parse.y

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
613613
%type <gates> gate_instance_list
614614

615615
%type <pform_name> hierarchy_identifier implicit_class_handle
616-
%type <expr> assignment_pattern expression expr_primary expr_mintypmax
616+
%type <expr> assignment_pattern expression expr_mintypmax
617+
%type <expr> expr_primary_or_typename expr_primary
617618
%type <expr> class_new dynamic_array_new
618619
%type <expr> inc_or_dec_expression inside_expression lpvalue
619620
%type <expr> branch_probe_expression streaming_concatenation
@@ -3083,7 +3084,7 @@ branch_probe_expression
30833084
;
30843085

30853086
expression
3086-
: expr_primary
3087+
: expr_primary_or_typename
30873088
{ $$ = $1; }
30883089
| inc_or_dec_expression
30893090
{ $$ = $1; }
@@ -3378,6 +3379,20 @@ expression_list_proper
33783379
}
33793380
;
33803381

3382+
expr_primary_or_typename
3383+
: expr_primary
3384+
3385+
/* There are a few special cases (notably $bits argument) where the
3386+
expression may be a type name. Let the elaborator sort this out. */
3387+
| TYPE_IDENTIFIER
3388+
{ PETypename*tmp = new PETypename($1.type);
3389+
FILE_NAME(tmp,@1);
3390+
$$ = tmp;
3391+
delete[]$1.text;
3392+
}
3393+
3394+
;
3395+
33813396
expr_primary
33823397
: number
33833398
{ assert($1);
@@ -3419,15 +3434,6 @@ expr_primary
34193434
delete[]$1;
34203435
}
34213436

3422-
/* There are a few special cases (notably $bits argument) where the
3423-
expression may be a type name. Let the elaborator sort this out. */
3424-
| TYPE_IDENTIFIER
3425-
{ PETypename*tmp = new PETypename($1.type);
3426-
FILE_NAME(tmp,@1);
3427-
$$ = tmp;
3428-
delete[]$1.text;
3429-
}
3430-
34313437
/* The hierarchy_identifier rule matches simple identifiers as well as
34323438
indexed arrays and part selects */
34333439

@@ -3731,12 +3737,11 @@ expr_primary
37313737

37323738
/* Cast expressions are primaries */
37333739

3734-
| DEC_NUMBER '\'' '(' expression ')'
3740+
| expr_primary '\'' '(' expression ')'
37353741
{ PExpr*base = $4;
37363742
if (gn_system_verilog()) {
3737-
PECastSize*tmp = new PECastSize($1->as_ulong(), base);
3743+
PECastSize*tmp = new PECastSize($1, base);
37383744
FILE_NAME(tmp, @1);
3739-
delete $1;
37403745
$$ = tmp;
37413746
} else {
37423747
yyerror(@1, "error: Size cast requires SystemVerilog.");

pform_dump.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998-2014 Stephen Williams ([email protected])
2+
* Copyright (c) 1998-2016 Stephen Williams ([email protected])
33
*
44
* This source code is free software; you can redistribute it
55
* and/or modify it in source code form under the terms of the GNU
@@ -318,7 +318,7 @@ void PECallFunction::dump(ostream &out) const
318318

319319
void PECastSize::dump(ostream &out) const
320320
{
321-
out << size_ << "'(";
321+
out << *size_ << "'(";
322322
base_->dump(out);
323323
out << ")";
324324
}

0 commit comments

Comments
 (0)