From 10d25d2b88977b257c9923e1f341168c21e3b270 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 21 Jan 2008 11:13:28 -0800 Subject: [PATCH] Support delays for all operators in a continuous assignments. Previously only the logical operators (~, &, |, ^, etc.) supported a delayed value in a continuous assignment. This patch should extend this to all operators. An extensive check of real values was done. The same will be done shortly for bit based nets. Checks for constructs currently unsupported in continuous assignments provide a more explicit message (** operator, real user functions, {!, && and ||} operators with a real argument). --- elab_net.cc | 219 ++++++++++++++++++++++++++++++++++---------- ivl.def | 1 + ivl_target.h | 9 +- t-dll-api.cc | 6 ++ t-dll.cc | 70 +++++++++++++- t-dll.h | 4 +- tgt-vvp/draw_mux.c | 18 +++- tgt-vvp/vvp_scope.c | 60 +++++++++++- 8 files changed, 328 insertions(+), 59 deletions(-) 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));