Browse files

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.
  • Loading branch information...
1 parent a43f336 commit e91243e1c601232ab26d104109896089dfea610b @steveicarus committed May 6, 2008
Showing with 170 additions and 1 deletion.
  1. +9 −0 design_dump.cc
  2. +27 −1 elab_net.cc
  3. +6 −0 emit.cc
  4. +9 −0 functor.cc
  5. +3 −0 functor.h
  6. +1 −0 ivl_target.h
  7. +18 −0 netlist.cc
  8. +21 −0 netlist.h
  9. +6 −0 t-dll-api.cc
  10. +32 −0 t-dll.cc
  11. +1 −0 t-dll.h
  12. +6 −0 target.cc
  13. +1 −0 target.h
  14. +30 −0 tgt-stub/stub.c
View
9 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()
View
28 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;
}
View
6 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);
View
9 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);
View
3 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*);
View
1 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,
View
18 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:
View
21 netlist.h
@@ -579,6 +579,27 @@ class NetNet : public NetObj {
};
/*
+ * 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
* implementation of the + and - operators.
View
6 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:
View
32 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;
View
1 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*);
View
6 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() << "): "
View
1 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*);
View
30 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: <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;

0 comments on commit e91243e

Please sign in to comment.