Fix the compiler and modpath scaling of real delays.

A real delay must be scaled and rounded using the local precision
before it is finally scaled to the simulation time units. This
patch fixes the compiler to do this correctly or generate the
correct code for run time calculated delays. Delays in a CA
already worked correctly. The run time was also fixed to scale
modpath (SDF back annotation) delays correctly.
This commit is contained in:
Cary R 2010-06-18 16:03:17 -07:00 committed by Stephen Williams
parent 3868334f5c
commit 21d15ceece
14 changed files with 230 additions and 75 deletions

View File

@ -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<NetECReal*>(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<NetEConst*>(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;
}

View File

@ -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;
}

View File

@ -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<NetECReal*>(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<NetEConst*>(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<NetEConst*> (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<NetEConst*> (cur)) {
verinum fn = con->value();
delay_value[idx] = des->scale_to_precision(fn.as_ulong64(),
scope);
} else if (NetECReal*cur_rcon = dynamic_cast<NetECReal*>(cur)) {
delay_value[idx] = cur_rcon->value().as_long(shift);
} else if (NetECReal*rcon = dynamic_cast<NetECReal*>(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;
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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)