diff --git a/elab_net.cc b/elab_net.cc index 9041e1dac..c98f2945f 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -96,60 +96,35 @@ NetNet* PEBinary::elaborate_net(Design*des, NetScope*scope, case 'r': // >> case 'R': // >>> return elaborate_net_shift_(des, scope, width, rise, fall, decay); + case 'p': // ** + cerr << get_fileline() << ": sorry: ** is currently unsupported" + " in continuous assignments." << endl; + des->errors += 1; + + return 0; } + /* This is an undefined operator, but we may as well check the + arguments since we are here. */ NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0), *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0); if (lsig == 0) { cerr << get_fileline() << ": error: Cannot elaborate "; left_->dump(cerr); cerr << endl; - return 0; } if (rsig == 0) { cerr << get_fileline() << ": error: Cannot elaborate "; right_->dump(cerr); cerr << endl; - return 0; } - NetNet*osig; + /* We can only get here with an undefined operator. */ + cerr << get_fileline() << ": internal error: unsupported" + " combinational operator (" << op_ << ")." << endl; + des->errors += 1; - switch (op_) { - case '^': // XOR - case 'X': // XNOR - case '&': // AND - case '|': // Bitwise OR - assert(0); - break; - - case 'E': // === (Case equals) - case 'e': // == - case 'n': // != - case '<': - case '>': - case 'G': // >= - case 'L': // <= - assert(0); - break; - - case '+': - assert(0); - break; - - case 'l': - case 'r': - case 'R': - assert(0); - break; - default: - cerr << get_fileline() << ": internal error: unsupported" - " combinational operator (" << op_ << ")." << endl; - des->errors += 1; - osig = 0; - } - - return osig; + return 0; } /* @@ -243,6 +218,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope, osig->data_type(lsig->data_type()); osig->set_signed(expr_signed); osig->local_flag(true); + osig->set_line(*this); if (debug_elaborate) { cerr << get_fileline() << ": debug: Elaborate NetAddSub " << "width=" << width << " lwidth=" << lwidth @@ -259,6 +235,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope, connect(osig->pin(width), adder->pin_Cout()); #endif NetNode*gate = adder; + gate->set_line(*this); gate->rise_time(rise); gate->fall_time(fall); gate->decay_time(decay); @@ -324,6 +301,7 @@ NetNet* PEBinary::elaborate_net_bit_(Design*des, NetScope*scope, NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, lsig->vector_width()); osig->local_flag(true); + osig->set_line(*this); osig->data_type( lsig->data_type() ); NetLogic::TYPE gtype=NetLogic::AND; @@ -394,6 +372,10 @@ static NetNet* compare_eq_constant(Design*des, NetScope*scope, NetEConst*ogate = new NetEConst(oval); NetNet*osig = ogate->synthesize(des); osig->data_type(lsig->data_type()); + osig->set_line(*lsig); + osig->rise_time(rise); + osig->fall_time(fall); + osig->decay_time(decay); delete ogate; if (debug_elaborate) @@ -445,6 +427,9 @@ static NetNet* compare_eq_constant(Design*des, NetScope*scope, type, zeros+ones); des->add_node(red); red->set_line(*lsig); + red->rise_time(rise); + red->fall_time(fall); + red->decay_time(decay); NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 0, 0); @@ -727,6 +712,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, assert(0); } + gate->set_line(*this); gate->rise_time(rise); gate->fall_time(fall); gate->decay_time(decay); @@ -789,6 +775,10 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope, NetDivide*div = new NetDivide(scope, scope->local_symbol(), rwidth, lsig->vector_width(), rsig->vector_width()); + div->set_line(*this); + div->rise_time(rise); + div->fall_time(fall); + div->decay_time(decay); des->add_node(div); div->set_signed(lsig->get_signed() && rsig->get_signed()); @@ -808,6 +798,7 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope, NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, lwidth); osig->local_flag(true); + osig->set_line(*this); osig->data_type(data_type); osig->set_signed(div->get_signed()); @@ -857,6 +848,9 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope, lsig->vector_width(), rsig->vector_width()); mod->set_line(*this); + mod->rise_time(rise); + mod->fall_time(fall); + mod->decay_time(decay); des->add_node(mod); connect(mod->pin_DataA(), lsig->pin(0)); @@ -893,6 +887,23 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope, cerr << endl; return 0; } + if (rsig->data_type() == IVL_VT_REAL || + lsig->data_type() == IVL_VT_REAL) { + cerr << get_fileline() << ": sorry: "; + switch (op_) { + case 'a': + cerr << "&&"; + break; + case 'o': + cerr << "||"; + break; + default: + assert(0); + } + + cerr << " is currently unsupported for real values." << endl; + return 0; + } NetLogic*gate; switch (op_) { @@ -907,9 +918,6 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope, default: assert(0); } - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); // The first OR gate returns 1 if the left value is true... if (lsig->vector_width() > 1) { @@ -960,6 +968,11 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope, osig->local_flag(true); osig->data_type(IVL_VT_LOGIC); connect(gate->pin(0), osig->pin(0)); + + gate->set_line(*this); + gate->rise_time(rise); + gate->fall_time(fall); + gate->decay_time(decay); des->add_node(gate); return osig; } @@ -990,6 +1003,9 @@ NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope, NetConst*odev = new NetConst(scope, scope->local_symbol(), res); des->add_node(odev); + odev->rise_time(rise); + odev->fall_time(fall); + odev->decay_time(decay); odev->set_line(*this); NetNet*osig = new NetNet(scope, scope->local_symbol(), @@ -1044,6 +1060,9 @@ NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope, lsig->vector_width(), rsig->vector_width()); mult->set_line(*this); + mult->rise_time(rise); + mult->fall_time(fall); + mult->decay_time(decay); des->add_node(mult); mult->set_signed( arith_is_signed ); @@ -1192,6 +1211,10 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope, assert(0); } + part->set_line(*this); + part->rise_time(rise); + part->fall_time(fall); + part->decay_time(decay); des->add_node(part); if (debug_elaborate) { @@ -1227,6 +1250,10 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope, NetCLShift*gate = new NetCLShift(scope, scope->local_symbol(), lwidth, rsig->vector_width(), right_flag, signed_flag); + gate->set_line(*this); + gate->rise_time(rise); + gate->fall_time(fall); + gate->decay_time(decay); des->add_node(gate); NetNet*osig = new NetNet(scope, scope->local_symbol(), @@ -1330,10 +1357,21 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope, if (errors > 0) return 0; + if (def->return_sig()->data_type() == IVL_VT_REAL) { + cerr << get_fileline() << ": sorry: real user functions are" + " not currently supported in continuous assignments." + << endl; + des->errors += 1; + return 0; + } NetUserFunc*net = new NetUserFunc(scope, scope->local_symbol(), dscope); + net->set_line(*this); + net->rise_time(rise); + net->fall_time(fall); + net->decay_time(decay); des->add_node(net); /* Create an output signal and connect it to the output pins @@ -1423,8 +1461,11 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(), def, 1+parms_.count()); - des->add_node(net); net->set_line(*this); + net->rise_time(rise); + net->fall_time(fall); + net->decay_time(decay); + des->add_node(net); NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, def->wid); @@ -2231,7 +2272,31 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope, net->local_flag(true); net->set_line(*this); - connect(net->pin(0), obj->pin(0)); + /* 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)); + } + return net; } @@ -2959,7 +3024,6 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope, connect(sig->pin(0), tmpz->pin(0)); des->add_node(tmpz); - } else { connect(mux->pin_Result(), sig->pin(0)); } @@ -3182,6 +3246,7 @@ NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope, NetNet::WIRE, width); sig->data_type(IVL_VT_LOGIC); sig->local_flag(true); + sig->set_line(*this); /* Take the 2s complement by taking the 1s complement and adding 1. */ @@ -3191,7 +3256,34 @@ NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope, tmp.has_sign(val.has_sign()); NetConst*con = new NetConst(scope, scope->local_symbol(), tmp); - connect(sig->pin(0), con->pin(0)); + + /* 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)); + } + con->set_line(*this); + + des->add_node(con); if (debug_elaborate) { cerr << get_fileline() << ": debug: Replace expression " @@ -3199,7 +3291,7 @@ NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope, } delete expr; - des->add_node(con); + return sig; } @@ -3223,7 +3315,32 @@ NetNet* PEUnary::elab_net_uminus_const_real_(Design*des, NetScope*scope, NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), -val); - connect(con->pin(0), sig->pin(0)); + /* 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)); + } + con->set_line(*this); + des->add_node(con); if (debug_elaborate) { @@ -3272,12 +3389,20 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope, << op_ << " expression with real values." << endl; des->errors += 1; break; + case '!': + cerr << get_fileline() << ": sorry: ! is currently unsupported" + " for real values." << endl; + des->errors += 1; + break; case '-': NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1); sub->attribute(perm_string::literal("LPM_Direction"), verinum("SUB")); sub->set_line(*this); + sub->rise_time(rise); + sub->fall_time(fall); + sub->decay_time(decay); des->add_node(sub); connect(sig->pin(0), sub->pin_Result()); connect(sub_sig->pin(0), sub->pin_DataB()); diff --git a/ivl.def b/ivl.def index 78148985f..9c495d1d4 100644 --- a/ivl.def +++ b/ivl.def @@ -77,6 +77,7 @@ ivl_lpm_clk ivl_lpm_data ivl_lpm_datab ivl_lpm_define +ivl_lpm_delay ivl_lpm_enable ivl_lpm_file ivl_lpm_lineno diff --git a/ivl_target.h b/ivl_target.h index 09c51a1e5..381e84014 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ #ifndef __ivl_target_H #define __ivl_target_H /* - * Copyright (c) 2000-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2008 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 @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: ivl_target.h,v 1.182 2007/04/02 01:12:34 steve Exp $" -#endif # include @@ -870,6 +867,9 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); * Return the name of the device. The name is the name of the * device with the scope part, and the basename is without the scope. * + * ivl_lpm_delay + * LPM devices have a delay for each transition (0, 1 and Z). + * * ivl_lpm_scope * LPM devices exist within a scope. Return the scope that contains * this device. @@ -1089,6 +1089,7 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net); extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */ extern const char* ivl_lpm_basename(ivl_lpm_t net); +extern ivl_expr_t ivl_lpm_delay(ivl_lpm_t net, unsigned transition); extern ivl_scope_t ivl_lpm_scope(ivl_lpm_t net); extern int ivl_lpm_signed(ivl_lpm_t net); extern ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net); diff --git a/t-dll-api.cc b/t-dll-api.cc index db6b2a619..1c6a2d5cc 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -728,6 +728,12 @@ extern "C" ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net) } } +extern "C" ivl_expr_t ivl_lpm_delay(ivl_lpm_t net, unsigned transition) +{ + assert(transition < 3); + return net->delay[transition]; +} + extern "C" ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net) { assert(net); diff --git a/t-dll.cc b/t-dll.cc index 3c8329c14..cf69f14d0 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2008 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 @@ -661,6 +661,44 @@ void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj, } } +void dll_target::make_lpm_delays_(struct ivl_lpm_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. * @@ -950,6 +988,8 @@ bool dll_target::sign_extend(const NetSignExtend*net) obj->u_.reduce.a = nex->t_cookie(); nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; @@ -1002,6 +1042,8 @@ bool dll_target::ureduce(const NetUReduce*net) obj->u_.reduce.a = nex->t_cookie(); nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; @@ -1038,6 +1080,8 @@ void dll_target::net_case_cmp(const NetCaseCmp*net) obj->u_.arith.q = nex->t_cookie(); nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); } @@ -1078,6 +1122,8 @@ bool dll_target::net_sysfunction(const NetSysFunc*net) IVL_DR_HiZ, IVL_DR_HiZ); } + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; } @@ -1126,6 +1172,8 @@ bool dll_target::net_function(const NetUserFunc*net) nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive); } + make_lpm_delays_(obj, net); + /* All done. Add this LPM to the scope. */ scope_add_lpm(obj->scope, obj); @@ -1263,6 +1311,8 @@ void dll_target::lpm_add_sub(const NetAddSub*net) cerr << "XXXX: t-dll.cc: Forgot how to connect cout." << endl; } + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); } @@ -1278,6 +1328,8 @@ bool dll_target::lpm_array_dq(const NetArrayDq*net) obj->width = net->width(); obj->u_.array.swid = net->awidth(); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); const Nexus*nex; @@ -1341,6 +1393,8 @@ void dll_target::lpm_clshift(const NetCLShift*net) obj->u_.shift.s = nex->t_cookie(); nexus_lpm_add(obj->u_.shift.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); } @@ -1446,6 +1500,8 @@ void dll_target::lpm_compare(const NetCompare*net) nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); } @@ -1483,6 +1539,7 @@ void dll_target::lpm_divide(const NetDivide*net) obj->u_.arith.b = nex->t_cookie(); nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); scope_add_lpm(obj->scope, obj); } @@ -1521,6 +1578,8 @@ void dll_target::lpm_modulo(const NetModulo*net) obj->u_.arith.b = nex->t_cookie(); nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); } @@ -1657,6 +1716,7 @@ void dll_target::lpm_mult(const NetMult*net) obj->u_.arith.b = nex->t_cookie(); nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); scope_add_lpm(obj->scope, obj); } @@ -1677,6 +1737,8 @@ void dll_target::lpm_mux(const NetMux*net) obj->u_.mux.size = net->size(); obj->u_.mux.swid = net->sel_width(); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); const Nexus*nex; @@ -1731,6 +1793,8 @@ bool dll_target::concat(const NetConcat*net) nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr); } + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; @@ -1836,6 +1900,8 @@ bool dll_target::part_select(const NetPartSelect*net) if (obj->u_.part.s) nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; @@ -1867,6 +1933,8 @@ bool dll_target::replicate(const NetReplicate*net) obj->u_.repeat.a = nex->t_cookie(); nexus_lpm_add(obj->u_.repeat.a, obj, 0, dr, dr); + make_lpm_delays_(obj, net); + scope_add_lpm(obj->scope, obj); return true; diff --git a/t-dll.h b/t-dll.h index e7547664b..f25f83b63 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef __t_dll_H #define __t_dll_H /* - * Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2008 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 @@ -161,6 +161,7 @@ struct dll_target : public target_t, public expr_scan_t { void mul_expr_by_const_(long); 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_scope_parameters(ivl_scope_t scope, const NetScope*net); void make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp); @@ -293,6 +294,7 @@ struct ivl_lpm_s { unsigned lineno; // Value returned by ivl_lpm_width; unsigned width; + ivl_expr_t delay[3]; union { struct ivl_lpm_ff_s { diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index ed53817f3..73cb075f6 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -41,7 +41,23 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) assert(ivl_lpm_size(net) == 2); assert(ivl_lpm_selects(net) == 1); - fprintf(vvp_out, "L_%p .functor %s %u", net, muxz, width); + ivl_expr_t d_rise = ivl_lpm_delay(net, 0); + ivl_expr_t d_fall = ivl_lpm_delay(net, 1); + ivl_expr_t d_decay = ivl_lpm_delay(net, 2); + + const char*dly = ""; + 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)); + dly = "/d"; + fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", + net, get_number_immediate(d_rise), + get_number_immediate(d_rise), + get_number_immediate(d_rise), net); + } + + fprintf(vvp_out, "L_%p%s .functor %s %u", net, dly, muxz, width); fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,0))); fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_data(net,1))); fprintf(vvp_out, ", %s", draw_input_from_net(ivl_lpm_select(net))); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index abe67c778..e8ed119a5 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1682,8 +1682,25 @@ static void draw_lpm_add(ivl_lpm_t net) } draw_lpm_data_inputs(net, 0, 2, src_table); - fprintf(vvp_out, "L_%p .arith/%s %u, %s, %s;\n", - net, type, width, src_table[0], src_table[1]); + + ivl_expr_t d_rise = ivl_lpm_delay(net, 0); + ivl_expr_t d_fall = ivl_lpm_delay(net, 1); + ivl_expr_t d_decay = ivl_lpm_delay(net, 2); + + const char*dly = ""; + 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)); + dly = "/d"; + fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", + net, get_number_immediate(d_rise), + get_number_immediate(d_rise), + get_number_immediate(d_rise), net); + } + + fprintf(vvp_out, "L_%p%s .arith/%s %u, %s, %s;\n", + net, dly, type, width, src_table[0], src_table[1]); } /* @@ -1762,8 +1779,25 @@ static void draw_lpm_cmp(ivl_lpm_t net) } draw_lpm_data_inputs(net, 0, 2, src_table); - fprintf(vvp_out, "L_%p .cmp/%s%s %u, %s, %s;\n", - net, type, signed_string, width, + + ivl_expr_t d_rise = ivl_lpm_delay(net, 0); + ivl_expr_t d_fall = ivl_lpm_delay(net, 1); + ivl_expr_t d_decay = ivl_lpm_delay(net, 2); + + const char*dly = ""; + 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)); + dly = "/d"; + fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", + net, get_number_immediate(d_rise), + get_number_immediate(d_rise), + get_number_immediate(d_rise), net); + } + + fprintf(vvp_out, "L_%p%s .cmp/%s%s %u, %s, %s;\n", + net, dly, type, signed_string, width, src_table[0], src_table[1]); } @@ -2018,8 +2052,24 @@ static void draw_type_string_of_nex(ivl_nexus_t nex) static void draw_lpm_sfunc(ivl_lpm_t net) { + ivl_expr_t d_rise = ivl_lpm_delay(net, 0); + ivl_expr_t d_fall = ivl_lpm_delay(net, 1); + ivl_expr_t d_decay = ivl_lpm_delay(net, 2); + + const char*dly = ""; + 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)); + dly = "/d"; + fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", + net, get_number_immediate(d_rise), + get_number_immediate(d_rise), + get_number_immediate(d_rise), net); + } + unsigned idx; - fprintf(vvp_out, "L_%p .sfunc %u %u \"%s\"", net, + fprintf(vvp_out, "L_%p%s .sfunc %u %u \"%s\"", net, dly, ivl_file_table_index(ivl_lpm_file(net)), ivl_lpm_lineno(net), ivl_lpm_string(net));