Add support for delaying constants at T0.

This patch adds support for delaying constants at time zero. It also
cleans up the code in elab_net.cc to use this capability instead of
building it with an extra BUFZ to carry the delay information.
This commit is contained in:
Cary R 2008-02-13 18:10:12 -08:00 committed by Stephen Williams
parent 4d8db7b5bc
commit b6f26e62df
8 changed files with 119 additions and 122 deletions

View File

@ -372,7 +372,14 @@ void NetFF::dump_node(ostream&o, unsigned ind) const
void NetLiteral::dump_node(ostream&o, unsigned ind) const void NetLiteral::dump_node(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << "constant real " << real_ o << setw(ind) << "" << "constant real " << real_
<< ": " << name() << endl; << ": " << name();
if (rise_time())
o << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
else
o << " #(.,.,.)";
o << endl;
dump_node_pins(o, ind+4); dump_node_pins(o, ind+4);
} }

View File

@ -2381,6 +2381,11 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value()); NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value());
obj->set_line(*this); obj->set_line(*this);
obj->rise_time(rise);
obj->fall_time(fall);
obj->decay_time(decay);
obj->pin(0).drive0(drive0);
obj->pin(0).drive1(drive1);
des->add_node(obj); des->add_node(obj);
NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1); NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1);
@ -2389,30 +2394,7 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
net->local_flag(true); net->local_flag(true);
net->set_line(*this); net->set_line(*this);
/* If there are non-zero output delays, then create bufz
devices to carry the propagation delays. Otherwise, just
connect the result to the output. */
if (rise || fall || decay) {
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, lwidth);
tmp->data_type(IVL_VT_REAL);
tmp->local_flag(true);
NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), lwidth);
tmpz->rise_time(rise);
tmpz->fall_time(fall);
tmpz->decay_time(decay);
tmpz->pin(0).drive0(drive0);
tmpz->pin(0).drive1(drive1);
connect(obj->pin(0), tmp->pin(0));
connect(tmp->pin(0), tmpz->pin(1));
connect(tmpz->pin(0), net->pin(0));
des->add_node(tmpz);
} else {
connect(obj->pin(0), net->pin(0)); connect(obj->pin(0), net->pin(0));
}
return net; return net;
} }
@ -2872,8 +2854,6 @@ NetNet* PENumber::elaborate_net(Design*des, NetScope*scope,
num = verinum(num, lwidth); num = verinum(num, lwidth);
con = new NetConst(scope, scope->local_symbol(), num); con = new NetConst(scope, scope->local_symbol(), num);
con->pin(0).drive0(drive0);
con->pin(0).drive1(drive1);
/* If the number has a length, then use that to size the /* If the number has a length, then use that to size the
number. Generate a constant object of exactly the user number. Generate a constant object of exactly the user
@ -2928,31 +2908,13 @@ NetNet* PENumber::elaborate_net(Design*des, NetScope*scope,
con = new NetConst(scope, scope->local_symbol(), num); con = new NetConst(scope, scope->local_symbol(), num);
} }
/* If there are non-zero output delays, then create bufz con->rise_time(rise);
devices to carry the propagation delays. Otherwise, just con->fall_time(fall);
connect the result to the output. */ con->decay_time(decay);
if (rise || fall || decay) { con->pin(0).drive0(drive0);
NetNet*tmp = new NetNet(scope, scope->local_symbol(), con->pin(0).drive1(drive1);
NetNet::WIRE, net->vector_width());
tmp->data_type(IVL_VT_LOGIC);
tmp->local_flag(true);
NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(),
net->vector_width());
tmpz->rise_time(rise);
tmpz->fall_time(fall);
tmpz->decay_time(decay);
tmpz->pin(0).drive0(drive0);
tmpz->pin(0).drive1(drive1);
connect(con->pin(0), tmp->pin(0));
connect(tmp->pin(0), tmpz->pin(1));
connect(net->pin(0), tmpz->pin(0));
des->add_node(tmpz);
} else {
connect(con->pin(0), net->pin(0)); connect(con->pin(0), net->pin(0));
}
des->add_node(con); des->add_node(con);
return net; return net;
@ -3000,33 +2962,15 @@ NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
NetConst*con = new NetConst(scope, scope->local_symbol(), num); NetConst*con = new NetConst(scope, scope->local_symbol(), num);
con->set_line(*this); con->set_line(*this);
con->rise_time(rise);
con->fall_time(fall);
con->decay_time(decay);
con->pin(0).drive0(drive0);
con->pin(0).drive1(drive1);
des->add_node(con); des->add_node(con);
/* If there are non-zero output delays, then create bufz
devices to carry the propagation delays. Otherwise, just
connect the result to the output. */
if (rise || fall || decay) {
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, net->vector_width());
tmp->data_type(IVL_VT_LOGIC);
tmp->local_flag(true);
NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(),
net->vector_width());
tmpz->rise_time(rise);
tmpz->fall_time(fall);
tmpz->decay_time(decay);
tmpz->pin(0).drive0(drive0);
tmpz->pin(0).drive1(drive1);
connect(con->pin(0), tmp->pin(0));
connect(tmp->pin(0), tmpz->pin(1));
connect(net->pin(0), tmpz->pin(0));
des->add_node(tmpz);
} else {
connect(con->pin(0), net->pin(0)); connect(con->pin(0), net->pin(0));
}
return net; return net;
} }
@ -3421,31 +3365,14 @@ NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope,
NetConst*con = new NetConst(scope, scope->local_symbol(), tmp); NetConst*con = new NetConst(scope, scope->local_symbol(), tmp);
/* If there are non-zero output delays, then create bufz
devices to carry the propagation delays. Otherwise, just
connect the result to the output. */
if (rise || fall || decay) {
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, width);
tmp->data_type(IVL_VT_LOGIC);
tmp->local_flag(true);
NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), width);
tmpz->rise_time(rise);
tmpz->fall_time(fall);
tmpz->decay_time(decay);
tmpz->pin(0).drive0(drive0);
tmpz->pin(0).drive1(drive1);
connect(con->pin(0), tmp->pin(0));
connect(tmp->pin(0), tmpz->pin(1));
connect(sig->pin(0), tmpz->pin(0));
des->add_node(tmpz);
} else {
connect(con->pin(0), sig->pin(0)); connect(con->pin(0), sig->pin(0));
}
con->set_line(*this); con->set_line(*this);
con->rise_time(rise);
con->fall_time(fall);
con->decay_time(decay);
con->pin(0).drive0(drive0);
con->pin(0).drive1(drive1);
des->add_node(con); des->add_node(con);
@ -3479,31 +3406,14 @@ NetNet* PEUnary::elab_net_uminus_const_real_(Design*des, NetScope*scope,
NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), -val); NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), -val);
/* If there are non-zero output delays, then create bufz
devices to carry the propagation delays. Otherwise, just
connect the result to the output. */
if (rise || fall || decay) {
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, width);
tmp->data_type(IVL_VT_REAL);
tmp->local_flag(true);
NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), width);
tmpz->rise_time(rise);
tmpz->fall_time(fall);
tmpz->decay_time(decay);
tmpz->pin(0).drive0(drive0);
tmpz->pin(0).drive1(drive1);
connect(con->pin(0), tmp->pin(0));
connect(tmp->pin(0), tmpz->pin(1));
connect(sig->pin(0), tmpz->pin(0));
des->add_node(tmpz);
} else {
connect(con->pin(0), sig->pin(0)); connect(con->pin(0), sig->pin(0));
}
con->set_line(*this); con->set_line(*this);
con->rise_time(rise);
con->fall_time(fall);
con->decay_time(decay);
con->pin(0).drive0(drive0);
con->pin(0).drive1(drive1);
des->add_node(con); des->add_node(con);

View File

@ -9,6 +9,7 @@ ivl_design_roots
ivl_design_time_precision ivl_design_time_precision
ivl_const_bits ivl_const_bits
ivl_const_delay
ivl_const_real ivl_const_real
ivl_const_signed ivl_const_signed
ivl_const_type ivl_const_type

View File

@ -483,6 +483,9 @@ extern ivl_net_const_t ivl_design_const(ivl_design_t, unsigned idx);
* ivl_const_width * ivl_const_width
* Return the width, in logical bits, of the constant. * Return the width, in logical bits, of the constant.
* *
* ivl_const_delay
* T0 delay for a transition (0, 1 and Z).
*
* SEMANTIC NOTES * SEMANTIC NOTES
* *
* The const_type of the literal constant must match the * The const_type of the literal constant must match the
@ -498,6 +501,7 @@ extern ivl_net_const_t ivl_design_const(ivl_design_t, unsigned idx);
*/ */
extern ivl_variable_type_t ivl_const_type(ivl_net_const_t net); extern ivl_variable_type_t ivl_const_type(ivl_net_const_t net);
extern const char* ivl_const_bits(ivl_net_const_t net); extern const char* ivl_const_bits(ivl_net_const_t net);
extern ivl_expr_t ivl_const_delay(ivl_net_const_t net, unsigned transition);
extern ivl_nexus_t ivl_const_nex(ivl_net_const_t net); extern ivl_nexus_t ivl_const_nex(ivl_net_const_t net);
extern int ivl_const_signed(ivl_net_const_t net); extern int ivl_const_signed(ivl_net_const_t net);
extern unsigned ivl_const_width(ivl_net_const_t net); extern unsigned ivl_const_width(ivl_net_const_t net);

View File

@ -129,6 +129,12 @@ extern "C" const char*ivl_const_bits(ivl_net_const_t net)
} }
} }
extern "C" ivl_expr_t ivl_const_delay(ivl_net_const_t net, unsigned transition)
{
assert(transition < 3);
return net->delay[transition];
}
extern "C" ivl_nexus_t ivl_const_nex(ivl_net_const_t net) extern "C" ivl_nexus_t ivl_const_nex(ivl_net_const_t net)
{ {
assert(net); assert(net);

View File

@ -699,6 +699,44 @@ void dll_target::make_lpm_delays_(struct ivl_lpm_s*obj,
} }
} }
void dll_target::make_const_delays_(struct ivl_net_const_s*obj,
const NetObj*net)
{
obj->delay[0] = 0;
obj->delay[1] = 0;
obj->delay[2] = 0;
/* Translate delay expressions to ivl_target form. Try to
preserve pointer equality, not as a rule but to save on
expression trees. */
if (net->rise_time()) {
expr_ = 0;
net->rise_time()->expr_scan(this);
obj->delay[0] = expr_;
expr_ = 0;
}
if (net->fall_time()) {
if (net->fall_time() == net->rise_time()) {
obj->delay[1] = obj->delay[0];
} else {
expr_ = 0;
net->fall_time()->expr_scan(this);
obj->delay[1] = expr_;
expr_ = 0;
}
}
if (net->decay_time()) {
if (net->decay_time() == net->rise_time()) {
obj->delay[2] = obj->delay[0];
} else {
expr_ = 0;
net->decay_time()->expr_scan(this);
obj->delay[2] = expr_;
expr_ = 0;
}
}
}
/* /*
* Add a bufz object to the scope that contains it. * Add a bufz object to the scope that contains it.
* *
@ -2045,6 +2083,8 @@ bool dll_target::net_const(const NetConst*net)
realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t)); realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
des_.consts[des_.nconsts-1] = obj; des_.consts[des_.nconsts-1] = obj;
make_const_delays_(obj, net);
return true; return true;
} }
@ -2074,6 +2114,8 @@ bool dll_target::net_literal(const NetLiteral*net)
realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t)); realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
des_.consts[des_.nconsts-1] = obj; des_.consts[des_.nconsts-1] = obj;
make_const_delays_(obj, net);
return true; return true;
} }

View File

@ -163,6 +163,7 @@ struct dll_target : public target_t, public expr_scan_t {
void make_logic_delays_(struct ivl_net_logic_s*obj, const NetObj*net); void make_logic_delays_(struct ivl_net_logic_s*obj, const NetObj*net);
void make_lpm_delays_(struct ivl_lpm_s*obj, const NetObj*net); void make_lpm_delays_(struct ivl_lpm_s*obj, const NetObj*net);
void make_const_delays_(struct ivl_net_const_s*obj, const NetObj*net);
void make_scope_parameters(ivl_scope_t scope, const NetScope*net); void make_scope_parameters(ivl_scope_t scope, const NetScope*net);
void make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp); void make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp);
@ -417,6 +418,8 @@ struct ivl_net_const_s {
} b; } b;
ivl_nexus_t pin_; ivl_nexus_t pin_;
ivl_expr_t delay[3];
}; };
/* /*

View File

@ -649,6 +649,30 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
break; break;
} }
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64));
assert(number_is_immediate(d_fall, 64));
assert(number_is_immediate(d_decay, 64));
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
cptr, get_number_immediate(d_rise),
get_number_immediate(d_rise),
get_number_immediate(d_rise), cptr);
free(result);
char tmp[128];
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
}
return result; return result;
} }