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).
This commit is contained in:
Cary R 2008-01-21 11:13:28 -08:00 committed by Stephen Williams
parent 3ea72109f8
commit 10d25d2b88
8 changed files with 328 additions and 59 deletions

View File

@ -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());

View File

@ -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

View File

@ -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 <inttypes.h>
@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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)));

View File

@ -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));