diff --git a/PDelays.cc b/PDelays.cc index efbc36861..9ce84eb0f 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -92,15 +92,10 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr) units, and return an adjusted value. */ if (NetECReal*tmp = dynamic_cast(dex)) { - verireal fn = tmp->value(); - - int shift = scope->time_unit() - des->get_precision(); - int64_t delay = fn.as_long64(shift); - if (delay < 0) - delay = 0; + uint64_t delay = get_scaled_time_from_real(des, scope, tmp); delete tmp; - NetEConst*tmp2 = new NetEConst(verinum(delay)); + NetEConst*tmp2 = new NetEConst(verinum(delay, 64)); tmp2->set_line(*expr); return tmp2; } @@ -108,11 +103,10 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr) if (NetEConst*tmp = dynamic_cast(dex)) { verinum fn = tmp->value(); - uint64_t delay = des->scale_to_precision(fn.as_ulong64(), scope); delete tmp; - NetEConst*tmp2 = new NetEConst(verinum(delay)); + NetEConst*tmp2 = new NetEConst(verinum(delay, 64)); tmp2->set_line(*expr); return tmp2; } @@ -132,7 +126,8 @@ static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr) NetNet*sig = expr->synthesize(des, scope, expr); if (sig == 0) { cerr << expr->get_fileline() << ": error: Expression " << *expr - << " is not suitable for delay expression." << endl; + << " is not suitable as a delay expression." << endl; + des->errors += 1; return 0; } diff --git a/dup_expr.cc b/dup_expr.cc index 49eef2dfd..97720703d 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -161,3 +161,11 @@ NetEUReduce* NetEUReduce::dup_expr() const tmp->set_line(*this); return tmp; } + +NetECast* NetECast::dup_expr() const +{ + NetECast*tmp = new NetECast(op_, expr_->dup_expr()); + assert(tmp); + tmp->set_line(*this); + return tmp; +} diff --git a/elaborate.cc b/elaborate.cc index f78b45e2c..0b66ed65a 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1960,55 +1960,68 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope) units, and return an adjusted NetEConst. */ if (NetECReal*tmp = dynamic_cast(dex)) { - verireal fn = tmp->value(); - - int shift = scope->time_unit() - des->get_precision(); - int64_t delay = fn.as_long64(shift); - if (delay < 0) - delay = 0; + uint64_t delay = get_scaled_time_from_real(des, scope, tmp); delete tmp; - return new NetEConst(verinum(delay)); + NetEConst*tmp2 = new NetEConst(verinum(delay, 64)); + tmp2->set_line(*expr); + return tmp2; } if (NetEConst*tmp = dynamic_cast(dex)) { verinum fn = tmp->value(); - - uint64_t delay = - des->scale_to_precision(fn.as_ulong64(), scope); + uint64_t delay = des->scale_to_precision(fn.as_ulong64(), scope); delete tmp; - return new NetEConst(verinum(delay)); + NetEConst*tmp2 = new NetEConst(verinum(delay, 64)); + tmp2->set_line(*expr); + return tmp2; } /* The expression is not constant, so generate an expanded expression that includes the necessary scale shifts, and return that expression. */ - int shift = scope->time_unit() - des->get_precision(); - if (shift > 0) { - uint64_t scale = 1; - while (shift > 0) { - scale *= 10; - shift -= 1; - } + ivl_assert(*expr, dex); + if (dex->expr_type() == IVL_VT_REAL) { + // Scale the real value. + int shift = scope->time_unit() - scope->time_precision(); + assert(shift >= 0); + double round = 1; + for (int lp = 0; lp < shift; lp += 1) round *= 10.0; - ivl_assert(*expr, dex); - NetExpr*scal_val = new NetEConst(verinum(scale)); + NetExpr*scal_val = new NetECReal(verireal(round)); + scal_val->set_line(*expr); dex = new NetEBMult('*', dex, scal_val); - } + dex->set_line(*expr); - if (shift < 0) { - unsigned long scale = 1; - while (shift < 0) { - scale *= 10; - shift += 1; - } + // Cast this part of the expression to an integer. + dex = new NetECast('i', dex); + dex->set_width(64); + dex->set_line(*expr); - ivl_assert(*expr, dex); - NetExpr*scal_val = new NetEConst(verinum(scale)); - dex = new NetEBDiv('/', dex, scal_val); + // Now scale the integer value. + shift = scope->time_precision() - des->get_precision(); + assert(shift >= 0); + uint64_t scale = 1; + for (int lp = 0; lp < shift; lp += 1) scale *= 10; + + scal_val = new NetEConst(verinum(scale, 64)); + scal_val->set_line(*expr); + dex = new NetEBMult('*', dex, scal_val); + dex->set_width(64); + dex->set_line(*expr); + } else { + int shift = scope->time_unit() - des->get_precision(); + assert(shift >= 0); + uint64_t scale = 1; + for (int lp = 0; lp < shift; lp += 1) scale *= 10; + + NetExpr*scal_val = new NetEConst(verinum(scale, 64)); + scal_val->set_line(*expr); + dex = new NetEBMult('*', dex, scal_val); + dex->set_line(*expr); } return dex; @@ -3901,7 +3914,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const "module(s) with no `timescale." << endl; display_ts_dly_warning = false; } - int shift = scope->time_unit() - des->get_precision(); /* Elaborate the delay values themselves. Remember to scale them for the timescale/precision of the scope. */ @@ -3910,17 +3922,18 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const probe_expr_width(des, scope, exp); NetExpr*cur = elab_and_eval(des, scope, exp, 0); - if (NetEConst*cur_con = dynamic_cast (cur)) { - delay_value[idx] = cur_con->value().as_ulong(); - for (int tmp = 0 ; tmp < shift ; tmp += 1) - delay_value[idx] *= 10; + if (NetEConst*con = dynamic_cast (cur)) { + verinum fn = con->value(); + delay_value[idx] = des->scale_to_precision(fn.as_ulong64(), + scope); - } else if (NetECReal*cur_rcon = dynamic_cast(cur)) { - delay_value[idx] = cur_rcon->value().as_long(shift); + } else if (NetECReal*rcon = dynamic_cast(cur)) { + delay_value[idx] = get_scaled_time_from_real(des, scope, + rcon); } else { cerr << get_fileline() << ": error: Path delay value " - << "must be constant." << endl; + << "must be constant (" << *cur << ")." << endl; delay_value[idx] = 0; des->errors += 1; } diff --git a/expr_synth.cc b/expr_synth.cc index 175a59072..e58c2b30d 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -977,6 +977,28 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope, NetExpr*root) return osig; } +NetNet* NetECast::synthesize(Design*des, NetScope*scope, NetExpr*root) +{ + NetNet*isig = expr_->synthesize(des, scope, root); + + if (isig == 0) return 0; + + switch (op()) { + case 'i': + isig = cast_to_int(des, scope, isig, isig->vector_width()); + break; + case 'r': + isig = cast_to_real(des, scope, isig); + break; + default: + cerr << get_fileline() << ": internal error: " + << "Unable to synthesize " << *this << "." << endl; + return 0; + } + + return isig; +} + /* * Turn a part/bit select expression into gates. * We know some things about the expression that elaboration enforces diff --git a/netlist.cc b/netlist.cc index 11bccce1b..2e8de81da 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2430,6 +2430,32 @@ ivl_variable_type_t NetEUReduce::expr_type() const return expr_->expr_type(); } +NetECast::NetECast(char op__, NetExpr*ex) +: NetEUnary(op__, ex) +{ +} + +NetECast::~NetECast() +{ +} + +ivl_variable_type_t NetECast::expr_type() const +{ + ivl_variable_type_t ret; + switch (op_) { + case 'i': + ret = IVL_VT_LOGIC; + break; + case 'r': + ret = IVL_VT_REAL; + break; + default: + assert(0); + } + + return ret; +} + NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins, TYPE t, unsigned wid) : NetNode(s, n, pins), type_(t), width_(wid) diff --git a/netlist.h b/netlist.h index c779a6c84..2619d7316 100644 --- a/netlist.h +++ b/netlist.h @@ -3750,6 +3750,8 @@ class NetETernary : public NetExpr { * N -- Reduction NOR (~|) * X -- Reduction NXOR (~^ or ^~) * m -- abs(x) (i.e. "magnitude") + * i -- Cast from real to integer (vector) + * r -- Cast from integer (vector) to real */ class NetEUnary : public NetExpr { @@ -3805,6 +3807,17 @@ class NetEUReduce : public NetEUnary { virtual ivl_variable_type_t expr_type() const; }; +class NetECast : public NetEUnary { + + public: + NetECast(char op, NetExpr*ex); + ~NetECast(); + + virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); + virtual NetECast* dup_expr() const; + virtual ivl_variable_type_t expr_type() const; +}; + /* * When a signal shows up in an expression, this type represents * it. From this the expression can get any kind of access to the diff --git a/netmisc.cc b/netmisc.cc index 39017dca6..f2644cc56 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -494,3 +494,19 @@ const_bool const_logical(const NetExpr*expr) return C_NON; } + +uint64_t get_scaled_time_from_real(Design*des, NetScope*scope, NetECReal*val) +{ + verireal fn = val->value(); + + int shift = scope->time_unit() - scope->time_precision(); + assert(shift >= 0); + int64_t delay = fn.as_long64(shift); + + + shift = scope->time_precision() - des->get_precision(); + assert(shift >= 0); + for (int lp = 0; lp < shift; lp += 1) delay *= 10; + + return delay; +} diff --git a/netmisc.h b/netmisc.h index 5617a8255..31d97def7 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef __netmisc_H #define __netmisc_H /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -235,4 +235,12 @@ extern bool dly_used_no_timescale; extern bool dly_used_timescale; extern bool display_ts_dly_warning; +/* + * When scaling a real value to a time we need to do some standard + * processing. + */ +extern uint64_t get_scaled_time_from_real(Design*des, + NetScope*scope, + NetECReal*val); + #endif diff --git a/set_width.cc b/set_width.cc index 2e013d438..cdd75b094 100644 --- a/set_width.cc +++ b/set_width.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -474,6 +474,8 @@ bool NetEUnary::set_width(unsigned w, bool) switch (op_) { case '~': case '-': + case 'r': + case 'i': flag = expr_->set_width(w); expr_width(w); break; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index ef64879b6..4cdf04642 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -286,8 +286,8 @@ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix) case IVL_VT_REAL: word = draw_eval_real(expr); - clr_word(word); fprintf(vvp_out, " %%cvt/sr %u, %u;\n", ix, word); + clr_word(word); break; default: @@ -2933,7 +2933,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) struct vector_info res; ivl_expr_t sub = ivl_expr_oper1(expr); const char *rop = 0; - int inv = 0; + int word, inv = 0; switch (ivl_expr_opcode(expr)) { case '&': rop = "and"; break; @@ -3117,15 +3117,32 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) } fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid); - fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); + fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, + local_count); fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid); fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid); fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count); local_count += 1; break; + case 'i': /* Cast a real value to an integer. */ + assert(ivl_expr_value(sub) == IVL_VT_REAL); + word = draw_eval_real(sub); + res.base = allocate_vector(wid); + res.wid = wid; + fprintf(vvp_out, " %%cvt/vr %u, %u, %u;\n", res.base, word, + res.wid); + clr_word(word); + break; + + case 'r': /* Handled in eval_real.c. */ + fprintf(stderr, "vvp error: integer -> real cast in integer " + "context.\n"); + assert(0); + break; + default: - fprintf(stderr, "vvp error: unhandled unary: %c\n", + fprintf(stderr, "vvp error: unhandled unary operator: %c\n", ivl_expr_opcode(expr)); assert(0); } diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index a946de4e2..e10eeb85b 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -139,6 +139,7 @@ static int draw_binary_real(ivl_expr_t expr) fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); break; } + default: fprintf(stderr, "XXXX draw_binary_real(%c)\n", ivl_expr_opcode(expr)); @@ -444,6 +445,20 @@ static int draw_unary_real(ivl_expr_t expr) } sube = ivl_expr_oper1(expr); + + if (ivl_expr_opcode(expr) == 'r') { /* Cast an integer value to a real. */ + struct vector_info res; + char *suffix = ""; + assert(ivl_expr_value(sube) != IVL_VT_REAL); + res = draw_eval_expr(sube, 1); + if (ivl_expr_signed(sube)) suffix = "/s"; + sub = allocate_word(); + fprintf(vvp_out, " %%cvt/rv%s %d, %u, %u;\n", suffix, sub, + res.base, res.wid); + clr_vector(res); + return sub; + } + sub = draw_eval_real(sube); if (ivl_expr_opcode(expr) == '+') @@ -458,16 +473,20 @@ static int draw_unary_real(ivl_expr_t expr) return res; } - if (ivl_expr_opcode(expr) == 'm') { /* abs(sube) */ + if (ivl_expr_opcode(expr) == 'm') { /* abs() */ fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub); return sub; } - fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n", - ivl_expr_opcode(expr), sub); - fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n", - ivl_expr_opcode(expr), sub); - return 0; + if (ivl_expr_opcode(expr) == 'i') { /* Handled in eval_expr.c. */ + fprintf(stderr, "vvp error: real -> integer cast in real " + "context.\n"); + assert(0); + } + + fprintf(stderr, "vvp error: unhandled real unary operator: %c.\n", + ivl_expr_opcode(expr)); + assert(0); } int draw_eval_real(ivl_expr_t expr) diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 5990b9000..048c16046 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -192,10 +192,6 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, delay_vals[idx].type = vpiScaledRealTime; if (delval_list->val[idx].defined) { delay_vals[idx].real = delval_list->val[idx].value; - /* Simulation cannot support negative delays. */ - if (delay_vals[idx].real < 0.0) { - delay_vals[idx].real = 0.0; - } } } diff --git a/vvp/delay.cc b/vvp/delay.cc index 0a85a82dd..32950e80d 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -781,7 +781,7 @@ static int modpath_src_free_object( vpiHandle ref ) /* * This routine will put specific dimension of delay[] values - * into a vpiHandle. In this case, he will put + * into a vpiHandle. In this case, we will put * specific delays values in a vpiModPathIn object * */ @@ -817,6 +817,11 @@ static void modpath_src_put_delays (vpiHandle ref, p_vpi_delay delays) tmp[idx] = vpip_timestruct_to_time(delays->da+use_map[0][idx]); } } else { + // You cannot create a modpath with a negative delay so set it + // to zero per 1364-2005 section 14.3.1. + for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) { + if (delays->da[idx].real < 0.0) delays->da[idx].real = 0.0; + } for (idx = 0 ; idx < 12 ; idx += 1) { tmp[idx] = vpip_scaled_real_to_time64(delays->da[use_map[0][idx]].real, src->dest->scope); diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 43a4e6e00..12f965804 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -67,18 +67,33 @@ double vpip_time_to_scaled_real(vvp_time64_t ti, struct __vpiScope*scope) return val; } +/* + * This routine does not currently support negative real delays and it + * does not check for overflow. It is only used for modpath delays and + * they are required to be non-negative. + */ vvp_time64_t vpip_scaled_real_to_time64(double val, struct __vpiScope*scope) { - int units; - if (scope) - units = scope->time_units; - else - units = vpi_time_precision; + int shift = 0; + if (scope) shift = scope->time_units - scope->time_precision; + assert(shift >= 0); - double scale = pow(10.0L, units - vpi_time_precision); + assert(val >= 0); + + // Scale to the local precision and then round away from zero. + double scale = pow(10.0L, shift); val *= scale; - return (vvp_time64_t) val; + vvp_time64_t delay = (vvp_time64_t) (val + 0.5); + + // If needed now scale the value to the simulator precision. + if (scope) { + shift = scope->time_precision - vpi_time_precision; + assert(shift >= 0); + for (int lp = 0; lp < shift; lp += 1) delay *= 10; + } + + return delay; } static int timevar_time_get(int code, vpiHandle ref)