Elaborate abs() is continuous assign expressions.

In continuous assign expressions, the abs() operator can't easily be
burried in generic unary handling, so add the IVL_LPM_ABS type and
generate it as needed.
This commit is contained in:
Stephen Williams 2008-05-05 22:00:39 -07:00
parent a43f336c6c
commit e91243e1c6
14 changed files with 170 additions and 1 deletions

View File

@ -247,6 +247,15 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
}
}
void NetAbs::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Absolute value (NetAbs): " << name()
<< " width=" << width() << " pin_count=" << pin_count()
<< endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetAddSub::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Adder (NetAddSub): " << name()

View File

@ -3212,6 +3212,32 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
connect(gate->pin(0), sig->pin(0));
break;
case 'm': // abs(sub_sig)
// If this expression is self determined, get its width
// from the sub_expression.
if (owidth == 0)
owidth = sub_sig->vector_width();
if (sub_sig->vector_width() < owidth)
sub_sig = pad_to_width(des, sub_sig, owidth);
sig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, owidth);
sig->set_line(*this);
sig->data_type(sub_sig->data_type());
sig->local_flag(true);
NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width());
tmp->set_line(*this);
des->add_node(tmp);
tmp->rise_time(rise);
tmp->fall_time(fall);
tmp->decay_time(decay);
connect(tmp->pin(1), sub_sig->pin(0));
connect(tmp->pin(0), sig->pin(0));
break;
case 'N': // Reduction NOR
case '!': // Reduction NOT
reduction=true; rtype = NetUReduce::NOR; break;
@ -3290,7 +3316,7 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
break;
default:
cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl;
sig = 0;
}

View File

@ -49,6 +49,12 @@ bool NetUDP::emit_node(struct target_t*tgt) const
return true;
}
bool NetAbs::emit_node(struct target_t*tgt) const
{
tgt->lpm_abs(this);
return true;
}
bool NetAddSub::emit_node(struct target_t*tgt) const
{
tgt->lpm_add_sub(this);

View File

@ -40,6 +40,10 @@ void functor_t::process(class Design*, class NetProcTop*)
{
}
void functor_t::lpm_abs(class Design*, class NetAbs*)
{
}
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
{
}
@ -174,6 +178,11 @@ void NetNode::functor_node(Design*, functor_t*)
{
}
void NetAbs::functor_node(Design*des, functor_t*fun)
{
fun->lpm_abs(des, this);
}
void NetAddSub::functor_node(Design*des, functor_t*fun)
{
fun->lpm_add_sub(des, this);

View File

@ -48,6 +48,9 @@ struct functor_t {
/* This method is called for each process in the design. */
virtual void process(class Design*des, class NetProcTop*);
/* This method is called for each structural abs(). */
virtual void lpm_abs(class Design*des, class NetAbs*);
/* This method is called for each structural adder. */
virtual void lpm_add_sub(class Design*des, class NetAddSub*);

View File

@ -228,6 +228,7 @@ typedef enum ivl_logic_e {
/* This is the type of an LPM object. */
typedef enum ivl_lpm_type_e {
IVL_LPM_ABS = 32,
IVL_LPM_ADD = 0,
IVL_LPM_ARRAY = 30,
IVL_LPM_CONCAT = 16,

View File

@ -1046,6 +1046,24 @@ const verinum& NetFF::sset_value() const
}
NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w)
: NetNode(s, n, 2), width_(w)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name(perm_string::literal("Result"), 0);
pin(1).set_dir(Link::INPUT);
pin(1).set_name(perm_string::literal("DataA"), 0);
}
NetAbs::~NetAbs()
{
}
unsigned NetAbs::width() const
{
return width_;
}
/*
* The NetAddSub class represents an LPM_ADD_SUB device. The pinout is
* assigned like so:

View File

@ -578,6 +578,27 @@ class NetNet : public NetObj {
vector<class NetDelaySrc*> delay_paths_;
};
/*
* This class implements the LPM_ABS component. The node has a single
* input, a signe expression, that it converts to the absolute
* value. The gate is simple: pin(0) is the output and pin(1) is the input.
*/
class NetAbs : public NetNode {
public:
NetAbs(NetScope*s, perm_string n, unsigned width);
~NetAbs();
unsigned width() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
virtual void functor_node(Design*des, functor_t*fun);
private:
unsigned width_;
};
/*
* This class implements the LPM_ADD_SUB component as described in the
* EDIF LPM Version 2 1 0 standard. It is used as a structural

View File

@ -864,6 +864,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
{
assert(net);
switch (net->type) {
case IVL_LPM_ABS:
assert(idx == 0);
return net->u_.arith.a;
case IVL_LPM_ADD:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
@ -1002,6 +1006,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
assert(net);
switch (net->type) {
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
@ -1118,6 +1123,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_FF:
case IVL_LPM_MUX:
return 0;
case IVL_LPM_ABS:
case IVL_LPM_ADD:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:

View File

@ -1303,6 +1303,38 @@ void dll_target::udp(const NetUDP*net)
scope_add_logic(scope, obj);
}
void dll_target::lpm_abs(const NetAbs*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_ABS;
obj->name = net->name(); // NetAddSub names are permallocated.
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->u_.arith.signed_flag = 0;
obj->width = net->width();
const Nexus*nex;
/* the output is pin(0) */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.arith.q = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
nex = net->pin(0).nexus();
assert(nex->t_cookie());
/* pin(1) is the input data. */
obj->u_.arith.a = nex->t_cookie();
nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
make_lpm_delays_(obj, net);
scope_add_lpm(obj->scope, obj);
}
void dll_target::lpm_add_sub(const NetAddSub*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;

View File

@ -70,6 +70,7 @@ struct dll_target : public target_t, public expr_scan_t {
bool ureduce(const NetUReduce*);
void net_case_cmp(const NetCaseCmp*);
void udp(const NetUDP*);
void lpm_abs(const NetAbs*);
void lpm_add_sub(const NetAddSub*);
bool lpm_array_dq(const NetArrayDq*);
void lpm_clshift(const NetCLShift*);

View File

@ -81,6 +81,12 @@ bool target_t::ureduce(const NetUReduce*)
return false;
}
void target_t::lpm_abs(const NetAbs*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetAbs." << endl;
}
void target_t::lpm_add_sub(const NetAddSub*)
{
cerr << "target (" << typeid(*this).name() << "): "

View File

@ -68,6 +68,7 @@ struct target_t {
virtual bool func_def(const NetScope*);
/* LPM style components are handled here. */
virtual void lpm_abs(const NetAbs*);
virtual void lpm_add_sub(const NetAddSub*);
virtual bool lpm_array_dq(const NetArrayDq*);
virtual void lpm_clshift(const NetCLShift*);

View File

@ -175,6 +175,32 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net)
fprintf(out, " DataB: %s\n", nex? ivl_nexus_name(nex) : "");
}
static void show_lpm_abs(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
fprintf(out, " LPM_ABS %s: <width=%u>\n",
ivl_lpm_basename(net), width);
ivl_nexus_t nex;
nex = ivl_lpm_q(net, 0);
fprintf(out, " Q: %s\n", ivl_nexus_name(ivl_lpm_q(net, 0)));
nex = ivl_lpm_data(net, 0);
fprintf(out, " D: %s\n", nex? ivl_nexus_name(nex) : "");
if (nex == 0) {
fprintf(out, " ERROR: missing input\n");
stub_errors += 1;
return;
}
if (width_of_nexus(nex) != width) {
fprintf(out, " ERROR: D width (%d) is wrong\n",
width_of_nexus(nex));
stub_errors += 1;
}
}
static void show_lpm_add(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
@ -796,6 +822,10 @@ static void show_lpm(ivl_lpm_t net)
switch (ivl_lpm_type(net)) {
case IVL_LPM_ABS:
show_lpm_abs(net);
break;
case IVL_LPM_ADD:
show_lpm_add(net);
break;