Add support for increment and decrement operators

This patch adds support for increment/decrement operators as an
expression. The operations on real and vector slices have been
disabled for now.

These operators can be used as in independent statements. However, the
corresponding support is not added in parser.

Changes since V2:
- Additional error checking in elaboration to deny operation on vector
slices and real (suggested by Martin)

Changes since V1:
- Use 'i' and 'I' for increment (suggested by Cary)
- Evaluate sub-expression once (suggested by Cary and Stev)
- Add necessary checks during elaboration to ensure that the
	expression is valid (suggested Stev)
- Proper width handling with vectors (suggested by Martin)

Signed-off-by: Prasad Joshi <prasad@canopusconsultancy.com>
This commit is contained in:
Prasad Joshi 2011-08-06 22:54:38 +01:00 committed by Stephen Williams
parent 6a40d9edaa
commit fa589badd8
5 changed files with 243 additions and 1 deletions

View File

@ -3590,6 +3590,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid, unsigned flags) const
{
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
ivl_variable_type_t t;
unsigned sub_width = expr_wid;
switch (op_) {
@ -3617,6 +3618,46 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
NetExpr*tmp;
switch (op_) {
case 'i':
case 'I':
case 'D':
case 'd':
t = ip->expr_type();
if (expr_wid != expr_->expr_width()) {
/*
* TODO: Need to modify draw_unary_expr() to support
* increment/decrement operations on slice of vector.
*/
cerr << get_fileline() << ": sorry: "
<< human_readable_op(op_, true)
<< " operation is not yet supported on "
<< "vector slice." << endl;
des->errors += 1;
return 0;
} else if (t == IVL_VT_REAL) {
/*
* TODO: Need to modify draw_unary_real() to support
* operations on real variables
*/
cerr << get_fileline() << ": sorry: "
<< human_readable_op(op_, true)
<< " operation is not yet supported on "
<< "reals." << endl;
des->errors += 1;
return 0;
} else if (t == IVL_VT_LOGIC || t == IVL_VT_BOOL) {
tmp = new NetEUnary(op_, ip, expr_wid, signed_flag_);
tmp->set_line(*this);
} else {
cerr << get_fileline() << ": error: "
<< "inappropriate use of "
<< human_readable_op(op_, true)
<< " operator." << endl;
des->errors += 1;
return 0;
}
break;
default:
tmp = new NetEUnary(op_, ip, expr_wid, signed_flag_);
tmp->set_line(*this);

View File

@ -187,6 +187,8 @@ TU [munpf]
">>=" { return K_RS_EQ; }
"<<<=" { return K_LS_EQ; }
">>>=" { return K_RSS_EQ; }
"++" { return K_INCR; }
"--" {return K_DECR; }
/* Watch out for the tricky case of (*). Cannot parse this as "(*"

View File

@ -746,6 +746,12 @@ const char *human_readable_op(const char op, bool unary)
case 'R': type = ">>>"; break; // Arithmetic right shift
case 'p': type = "**"; break; // Power
case 'i':
case 'I': type = "++"; break; /* increment */
case 'd':
case 'D': type = "--"; break; /* decrement */
default:
type = "???";
assert(0);

26
parse.y
View File

@ -330,7 +330,7 @@ static long check_enum_seq_value(const YYLTYPE&loc, verinum *arg, bool zero_ok)
%token <text> PATHPULSE_IDENTIFIER
%token <number> BASED_NUMBER DEC_NUMBER
%token <realtime> REALTIME
%token K_PLUS_EQ K_MINUS_EQ
%token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG
/* K_CONTRIBUTE is <+, the contribution assign. */
%token K_CONTRIBUTE
@ -1288,6 +1288,30 @@ 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);

View File

@ -21,6 +21,7 @@
# include <string.h>
# include <stdlib.h>
# include <assert.h>
# include <stdbool.h>
# include "ivl_alloc.h"
static void draw_eval_expr_dest(ivl_expr_t expr, struct vector_info dest,
@ -2921,6 +2922,158 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid)
return res;
}
static struct vector_info increment(ivl_expr_t e, unsigned wid, bool pre)
{
ivl_signal_t s;
unsigned w;
struct vector_info r;
struct vector_info rc;
switch (ivl_expr_type(e)) {
case IVL_EX_SELECT: {
ivl_expr_t e1 = ivl_expr_oper1(e);
s = ivl_expr_signal(e1);
/* select expression: calculate the width */
w = ivl_expr_width(e1);
break;
}
case IVL_EX_SIGNAL: {
s = ivl_expr_signal(e);
w = wid;
break;
}
default: {
assert(0);
break;
}
}
r = draw_eval_expr_wid(e, wid, STUFF_OK_XZ);
rc = r;
switch (r.base) {
case 0:
r.base = 1;
break;
case 1:
r.base = 0;
break;
case 2:
case 3:
r.base = 2;
break;
default:
if (!pre) {
/*
* post-increment must return the non-incremented
* value. Therefore, copy the current value in a
* new vector and return it.
*/
rc.base = allocate_vector(r.wid);
rc.wid = r.wid;
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
rc.base, r.base, rc.wid);
}
fprintf(vvp_out, " %%addi %u, 1, %u;\n", r.base, w);
fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", s,
r.base, w);
break;
}
return rc;
}
static inline struct vector_info pre_increment(ivl_expr_t e, unsigned wid)
{
return increment(e, wid, true);
}
static inline struct vector_info post_increment(ivl_expr_t e, unsigned wid)
{
return increment(e, wid, false);
}
static struct vector_info decrement(ivl_expr_t e, unsigned wid, bool pre)
{
ivl_signal_t s;
unsigned w;
struct vector_info r;
struct vector_info rc;
switch (ivl_expr_type(e)) {
case IVL_EX_SELECT: {
ivl_expr_t e1 = ivl_expr_oper1(e);
s = ivl_expr_signal(e1);
/* select expression: calculate the width */
w = ivl_expr_width(e1);
break;
}
case IVL_EX_SIGNAL: {
s = ivl_expr_signal(e);
w = wid;
break;
}
default: {
assert(0);
break;
}
}
r = draw_eval_expr_wid(e, wid, STUFF_OK_XZ);
rc = r;
switch (r.base) {
case 0:
r.base = 1;
break;
case 1:
r.base = 0;
break;
case 2:
case 3:
r.base = 2;
break;
default:
if (!pre) {
/*
* post-decrement must return the non-decremented
* value. Therefore, copy the current value in a
* new vector and return it.
*/
rc.base = allocate_vector(r.wid);
rc.wid = r.wid;
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
rc.base, r.base, rc.wid);
}
fprintf(vvp_out, " %%subi %u, 1, %u;\n", r.base, w);
fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", s,
r.base, w);
break;
}
return rc;
}
static inline struct vector_info pre_decrement(ivl_expr_t e, unsigned wid)
{
return decrement(e, wid, true);
}
static inline struct vector_info post_decrement(ivl_expr_t e, unsigned wid)
{
return decrement(e, wid, false);
}
static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
{
struct vector_info res;
@ -2957,6 +3110,22 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
}
break;
case 'D':
res = pre_decrement(sub, wid);
break;
case 'd':
res = post_decrement(sub, wid);
break;
case 'I':
res = pre_increment(sub, wid);
break;
case 'i':
res = post_increment(sub, wid);
break;
case '-':
/* Unary minus is implemented by generating the 2's
complement of the number. That is the 1's complement