From e91243e1c601232ab26d104109896089dfea610b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 5 May 2008 22:00:39 -0700 Subject: [PATCH] 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. --- design_dump.cc | 9 +++++++++ elab_net.cc | 28 +++++++++++++++++++++++++++- emit.cc | 6 ++++++ functor.cc | 9 +++++++++ functor.h | 3 +++ ivl_target.h | 1 + netlist.cc | 18 ++++++++++++++++++ netlist.h | 21 +++++++++++++++++++++ t-dll-api.cc | 6 ++++++ t-dll.cc | 32 ++++++++++++++++++++++++++++++++ t-dll.h | 1 + target.cc | 6 ++++++ target.h | 1 + tgt-stub/stub.c | 30 ++++++++++++++++++++++++++++++ 14 files changed, 170 insertions(+), 1 deletion(-) diff --git a/design_dump.cc b/design_dump.cc index 12c4a6e5a..82eb6919f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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() diff --git a/elab_net.cc b/elab_net.cc index c1b628e5c..d3c542b16 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -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; } diff --git a/emit.cc b/emit.cc index f94d0403b..c52190684 100644 --- a/emit.cc +++ b/emit.cc @@ -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); diff --git a/functor.cc b/functor.cc index f318ef80d..406d0ff9f 100644 --- a/functor.cc +++ b/functor.cc @@ -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); diff --git a/functor.h b/functor.h index 31e204261..d3b9b5088 100644 --- a/functor.h +++ b/functor.h @@ -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*); diff --git a/ivl_target.h b/ivl_target.h index 6beca4af4..bdd983a75 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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, diff --git a/netlist.cc b/netlist.cc index 4d7e8a9c8..45fee8f34 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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: diff --git a/netlist.h b/netlist.h index 891864b84..341947241 100644 --- a/netlist.h +++ b/netlist.h @@ -578,6 +578,27 @@ class NetNet : public NetObj { vector 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 diff --git a/t-dll-api.cc b/t-dll-api.cc index db8dd8b64..64b079ada 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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: diff --git a/t-dll.cc b/t-dll.cc index edade0859..9dba1b907 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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; diff --git a/t-dll.h b/t-dll.h index 9d7440ada..7e8e7e58b 100644 --- a/t-dll.h +++ b/t-dll.h @@ -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*); diff --git a/target.cc b/target.cc index 9c1f88b95..379a91754 100644 --- a/target.cc +++ b/target.cc @@ -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() << "): " diff --git a/target.h b/target.h index e6e1b8546..c68ffc2f0 100644 --- a/target.h +++ b/target.h @@ -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*); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 917b4b43d..7b455d171 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -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: \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;