diff --git a/design_dump.cc b/design_dump.cc index 03821c044..d0e4bfae0 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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); } diff --git a/elab_net.cc b/elab_net.cc index a2ff432cd..c66dfb2ec 100644 --- a/elab_net.cc +++ b/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); diff --git a/ivl.def b/ivl.def index 9c495d1d4..6e3772b39 100644 --- a/ivl.def +++ b/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 diff --git a/ivl_target.h b/ivl_target.h index a022859a0..d3ae71ab8 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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); diff --git a/t-dll-api.cc b/t-dll-api.cc index 4b5156f87..b8f8621cd 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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); diff --git a/t-dll.cc b/t-dll.cc index 2e2e06316..45ca0b6c5 100644 --- a/t-dll.cc +++ b/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; } diff --git a/t-dll.h b/t-dll.h index 618e4a645..4cb3f7545 100644 --- a/t-dll.h +++ b/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]; }; /* diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index aae63e41c..4bb7ecd91 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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; }