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:
parent
4d8db7b5bc
commit
b6f26e62df
|
|
@ -372,7 +372,14 @@ void NetFF::dump_node(ostream&o, unsigned ind) const
|
|||
void NetLiteral::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
152
elab_net.cc
152
elab_net.cc
|
|
@ -2381,6 +2381,11 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
|
|||
|
||||
NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value());
|
||||
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);
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
|
@ -2872,8 +2854,6 @@ NetNet* PENumber::elaborate_net(Design*des, NetScope*scope,
|
|||
num = verinum(num, lwidth);
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
con->rise_time(rise);
|
||||
con->fall_time(fall);
|
||||
con->decay_time(decay);
|
||||
con->pin(0).drive0(drive0);
|
||||
con->pin(0).drive1(drive1);
|
||||
|
||||
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);
|
||||
return net;
|
||||
|
|
@ -3000,33 +2962,15 @@ NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
|
|||
|
||||
NetConst*con = new NetConst(scope, scope->local_symbol(), num);
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
@ -3421,31 +3365,14 @@ NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope,
|
|||
|
||||
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);
|
||||
connect(con->pin(0), sig->pin(0));
|
||||
|
||||
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));
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
@ -3479,31 +3406,14 @@ NetNet* PEUnary::elab_net_uminus_const_real_(Design*des, NetScope*scope,
|
|||
|
||||
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);
|
||||
connect(con->pin(0), sig->pin(0));
|
||||
|
||||
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));
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
|
|||
1
ivl.def
1
ivl.def
|
|
@ -9,6 +9,7 @@ ivl_design_roots
|
|||
ivl_design_time_precision
|
||||
|
||||
ivl_const_bits
|
||||
ivl_const_delay
|
||||
ivl_const_real
|
||||
ivl_const_signed
|
||||
ivl_const_type
|
||||
|
|
|
|||
|
|
@ -483,6 +483,9 @@ extern ivl_net_const_t ivl_design_const(ivl_design_t, unsigned idx);
|
|||
* ivl_const_width
|
||||
* Return the width, in logical bits, of the constant.
|
||||
*
|
||||
* ivl_const_delay
|
||||
* T0 delay for a transition (0, 1 and Z).
|
||||
*
|
||||
* SEMANTIC NOTES
|
||||
*
|
||||
* 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 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 int ivl_const_signed(ivl_net_const_t net);
|
||||
extern unsigned ivl_const_width(ivl_net_const_t net);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
assert(net);
|
||||
|
|
|
|||
42
t-dll.cc
42
t-dll.cc
|
|
@ -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.
|
||||
*
|
||||
|
|
@ -2045,6 +2083,8 @@ bool dll_target::net_const(const NetConst*net)
|
|||
realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
|
||||
des_.consts[des_.nconsts-1] = obj;
|
||||
|
||||
make_const_delays_(obj, net);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2074,6 +2114,8 @@ bool dll_target::net_literal(const NetLiteral*net)
|
|||
realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
|
||||
des_.consts[des_.nconsts-1] = obj;
|
||||
|
||||
make_const_delays_(obj, net);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
3
t-dll.h
3
t-dll.h
|
|
@ -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_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_param_expr(ivl_parameter_t cur_par, NetExpr*etmp);
|
||||
|
||||
|
|
@ -417,6 +418,8 @@ struct ivl_net_const_s {
|
|||
} b;
|
||||
|
||||
ivl_nexus_t pin_;
|
||||
|
||||
ivl_expr_t delay[3];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -649,6 +649,30 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue