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
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
146
elab_net.cc
146
elab_net.cc
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
1
ivl.def
1
ivl.def
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
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.
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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_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];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue