Implement increment/decrement statements.
During parse/pform processing, convert increment statements to the equivalent compressed assignment statement. This is less weird for elaboration processing and better expresses what is going on.
This commit is contained in:
parent
6b4251626b
commit
f8e346f108
4
PExpr.h
4
PExpr.h
|
|
@ -509,6 +509,10 @@ class PEUnary : public PExpr {
|
|||
unsigned flags) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
public:
|
||||
inline char get_op() const { return op_; }
|
||||
inline PExpr*get_expr() const { return expr_; }
|
||||
|
||||
private:
|
||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;
|
||||
|
||||
|
|
|
|||
97
parse.y
97
parse.y
|
|
@ -496,7 +496,7 @@ static void current_task_set_statement(vector<Statement*>*s)
|
|||
|
||||
%type <pform_name> hierarchy_identifier
|
||||
%type <expr> assignment_pattern expression expr_primary expr_mintypmax
|
||||
%type <expr> lpvalue
|
||||
%type <expr> inc_or_dec_expression lpvalue
|
||||
%type <expr> branch_probe_expression
|
||||
%type <expr> delay_value delay_value_simple
|
||||
%type <exprs> delay1 delay3 delay3_opt delay_value_list
|
||||
|
|
@ -665,6 +665,35 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */
|
|||
| K_super
|
||||
;
|
||||
|
||||
/* SystemVerilog adds support for the increment/decrement
|
||||
expressions, which look like a++, --a, etc. These are primaries
|
||||
but are in their own rules because they can also be
|
||||
statements. Note that the operator can only take l-value
|
||||
expressions. */
|
||||
|
||||
inc_or_dec_expression /* IEEE1800-2005: A.4.3 */
|
||||
: K_INCR lpvalue %prec UNARY_PREC
|
||||
{ PEUnary*tmp = new PEUnary('I', $2);
|
||||
FILE_NAME(tmp, @2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_INCR %prec UNARY_PREC
|
||||
{ PEUnary*tmp = new PEUnary('i', $1);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_DECR lpvalue %prec UNARY_PREC
|
||||
{ PEUnary*tmp = new PEUnary('D', $2);
|
||||
FILE_NAME(tmp, @2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_DECR %prec UNARY_PREC
|
||||
{ PEUnary*tmp = new PEUnary('d', $1);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
number : BASED_NUMBER
|
||||
{ $$ = $1; based_size = 0;}
|
||||
| DEC_NUMBER
|
||||
|
|
@ -1790,32 +1819,10 @@ branch_probe_expression
|
|||
expression
|
||||
: expr_primary
|
||||
{ $$ = $1; }
|
||||
| inc_or_dec_expression
|
||||
{ $$ = $1; }
|
||||
| '+' expr_primary %prec UNARY_PREC
|
||||
{ $$ = $2; }
|
||||
| K_INCR expr_primary %prec UNARY_PREC
|
||||
{
|
||||
PEUnary*tmp = new PEUnary('I', $2);
|
||||
FILE_NAME(tmp, @2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expr_primary K_INCR %prec UNARY_PREC
|
||||
{
|
||||
PEUnary*tmp = new PEUnary('i', $1);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_DECR expr_primary %prec UNARY_PREC
|
||||
{
|
||||
PEUnary*tmp = new PEUnary('D', $2);
|
||||
FILE_NAME(tmp, @2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expr_primary K_DECR %prec UNARY_PREC
|
||||
{
|
||||
PEUnary*tmp = new PEUnary('d', $1);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| '-' expr_primary %prec UNARY_PREC
|
||||
{ PEUnary*tmp = new PEUnary('-', $2);
|
||||
FILE_NAME(tmp, @2);
|
||||
|
|
@ -4897,7 +4904,7 @@ spec_notifier
|
|||
;
|
||||
|
||||
|
||||
statement
|
||||
statement /* This is roughly statement_item in the LRM */
|
||||
|
||||
/* assign and deassign statements are procedural code to do
|
||||
structural assignments, and to turn that structural assignment
|
||||
|
|
@ -5094,16 +5101,29 @@ statement
|
|||
{ $$ = 0;
|
||||
yyerror(@1, "error: Error in while loop condition.");
|
||||
}
|
||||
| compressed_statement ';'
|
||||
{ $$ = $1; }
|
||||
| delay1 statement_or_null
|
||||
{ PExpr*del = $1->front();
|
||||
assert($1->size() == 1);
|
||||
delete $1;
|
||||
PDelayStatement*tmp = new PDelayStatement(del, $2);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* SytemVerilog adds the compressed_statement */
|
||||
|
||||
| compressed_statement ';'
|
||||
{ $$ = $1; }
|
||||
|
||||
/* increment/decrement expressions can also be statements. When used
|
||||
as statements, we can rewrite a++ as a += 1, and so on. */
|
||||
|
||||
| inc_or_dec_expression ';'
|
||||
{ $$ = pform_compressed_assign_from_inc_dec(@1, $1); }
|
||||
|
||||
/* */
|
||||
|
||||
| delay1 statement_or_null
|
||||
{ PExpr*del = $1->front();
|
||||
assert($1->size() == 1);
|
||||
delete $1;
|
||||
PDelayStatement*tmp = new PDelayStatement(del, $2);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| event_control attribute_list_opt statement_or_null
|
||||
{ PEventStatement*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
|
|
@ -5129,6 +5149,9 @@ statement
|
|||
tmp->set_statement($6);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Various assignment statements */
|
||||
|
||||
| lpvalue '=' expression ';'
|
||||
{ PAssign*tmp = new PAssign($1,$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
|
|
@ -5184,6 +5207,8 @@ statement
|
|||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
|
||||
| K_wait '(' expression ')' statement_or_null
|
||||
{ PEventStatement*tmp;
|
||||
PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3);
|
||||
|
|
|
|||
37
pform.cc
37
pform.cc
|
|
@ -2208,6 +2208,43 @@ svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
|
|||
range_tmp, names);
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser calls this in the rule that matches increment/decrement
|
||||
* statements. The rule that does the matching creates a PEUnary with
|
||||
* all the information we need, but here we convert that expression to
|
||||
* a compressed assignment statement.
|
||||
*/
|
||||
PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp)
|
||||
{
|
||||
PEUnary*expu = dynamic_cast<PEUnary*> (exp);
|
||||
ivl_assert(*exp, expu != 0);
|
||||
|
||||
char use_op = 0;
|
||||
switch (expu->get_op()) {
|
||||
case 'i':
|
||||
case 'I':
|
||||
use_op = '+';
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
use_op = '-';
|
||||
break;
|
||||
default:
|
||||
ivl_assert(*exp, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
PExpr*lval = expu->get_expr();
|
||||
PExpr*rval = new PENumber(new verinum((uint64_t)1, 1));
|
||||
FILE_NAME(rval, loc);
|
||||
|
||||
PAssign*tmp = new PAssign(lval, use_op, rval);
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
delete exp;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void pform_set_attrib(perm_string name, perm_string key, char*value)
|
||||
{
|
||||
if (PWire*cur = lexical_scope->wires_find(name)) {
|
||||
|
|
|
|||
7
pform.h
7
pform.h
|
|
@ -398,6 +398,13 @@ extern svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
|
|||
data_type_t*vtype,
|
||||
list<perm_string>*names);
|
||||
|
||||
/*
|
||||
* The parser uses this function to convert a unary
|
||||
* increment/decrement expression to the equivilent compressed
|
||||
* assignment statement.
|
||||
*/
|
||||
extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc,
|
||||
PExpr*exp);
|
||||
|
||||
/*
|
||||
* These are functions that the outside-the-parser code uses the do
|
||||
|
|
|
|||
Loading…
Reference in New Issue