1998-11-04 00:28:49 +01:00
|
|
|
#ifndef __netlist_H
|
|
|
|
|
#define __netlist_H
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 1998 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
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
#if !defined(WINNT)
|
1999-04-19 03:59:36 +02:00
|
|
|
#ident "$Id: netlist.h,v 1.23 1999/04/19 01:59:36 steve Exp $"
|
1998-11-04 00:28:49 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The netlist types, as described in this header file, are intended
|
|
|
|
|
* to be the output from elaboration of the source design. The design
|
|
|
|
|
* can be passed around in this form to the various stages and design
|
|
|
|
|
* processors.
|
|
|
|
|
*/
|
|
|
|
|
# include <string>
|
1998-11-18 05:25:22 +01:00
|
|
|
# include <map>
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "verinum.h"
|
1999-02-01 01:26:48 +01:00
|
|
|
# include "LineInfo.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
class NetNode;
|
|
|
|
|
class NetProc;
|
|
|
|
|
class NetProcTop;
|
|
|
|
|
class NetExpr;
|
|
|
|
|
class ostream;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct target;
|
|
|
|
|
|
|
|
|
|
/* =========
|
|
|
|
|
* A NetObj is anything that has any kind of behavior in the
|
|
|
|
|
* netlist. Nodes can be gates, registers, etc. and are linked
|
|
|
|
|
* together to form a design web.
|
|
|
|
|
*
|
|
|
|
|
* The web of nodes that makes up a circuit is held together by the
|
|
|
|
|
* Link class. There is a link for each pin. All mutually connected
|
|
|
|
|
* pins form a ring of links.
|
1998-12-02 05:37:13 +01:00
|
|
|
*
|
|
|
|
|
* A link can be INPUT, OUTPUT or PASSIVE. An input never drives the
|
|
|
|
|
* signal, and PASSIVE never receives the value of the signal. Wires
|
|
|
|
|
* are PASSIVE, for example.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
class NetObj {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
class Link {
|
|
|
|
|
friend void connect(Link&, Link&);
|
|
|
|
|
friend class NetObj;
|
|
|
|
|
|
|
|
|
|
public:
|
1998-12-02 05:37:13 +01:00
|
|
|
enum DIR { PASSIVE, INPUT, OUTPUT };
|
|
|
|
|
Link() : dir_(PASSIVE), next_(this), prev_(this) { }
|
1998-11-04 00:28:49 +01:00
|
|
|
~Link() { unlink(); }
|
|
|
|
|
|
1998-12-02 05:37:13 +01:00
|
|
|
// Manipulate the link direction.
|
|
|
|
|
void set_dir(DIR d) { dir_ = d; }
|
|
|
|
|
DIR get_dir() const { return dir_; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
void cur_link(NetObj*&net, unsigned &pin)
|
|
|
|
|
{ net = node_;
|
|
|
|
|
pin = pin_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void next_link(NetObj*&net, unsigned&pin)
|
|
|
|
|
{ net = next_->node_;
|
|
|
|
|
pin = next_->pin_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void next_link(const NetObj*&net, unsigned&pin) const
|
|
|
|
|
{ net = next_->node_;
|
|
|
|
|
pin = next_->pin_;
|
|
|
|
|
}
|
|
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
Link* next_link() { return next_; }
|
|
|
|
|
const Link* next_link() const { return next_; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// Remove this link from the set of connected pins. The
|
|
|
|
|
// destructor will automatically do this if needed.
|
|
|
|
|
void unlink()
|
|
|
|
|
{ next_->prev_ = prev_;
|
|
|
|
|
prev_->next_ = next_;
|
|
|
|
|
next_ = prev_ = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return true if this link is connected to anything else.
|
|
|
|
|
bool is_linked() const { return next_ != this; }
|
|
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
// Return true if these pins are connected.
|
|
|
|
|
bool is_linked(const NetObj::Link&that) const;
|
|
|
|
|
|
|
|
|
|
// Return true if this link is connected to any pin of r.
|
|
|
|
|
bool is_linked(const NetObj&r) const;
|
|
|
|
|
|
|
|
|
|
bool is_equal(const NetObj::Link&that) const
|
|
|
|
|
{ return (node_ == that.node_) && (pin_ == that.pin_); }
|
|
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
// Return information about the object that this link is
|
|
|
|
|
// a part of.
|
|
|
|
|
const NetObj*get_obj() const { return node_; }
|
|
|
|
|
NetObj*get_obj() { return node_; }
|
|
|
|
|
unsigned get_pin() const { return pin_; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
private:
|
|
|
|
|
// The NetNode manages these. They point back to the
|
|
|
|
|
// NetNode so that following the links can get me here.
|
|
|
|
|
NetObj *node_;
|
|
|
|
|
unsigned pin_;
|
1998-12-02 05:37:13 +01:00
|
|
|
DIR dir_;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Link *next_;
|
|
|
|
|
Link *prev_;
|
|
|
|
|
|
|
|
|
|
private: // not implemented
|
|
|
|
|
Link(const Link&);
|
|
|
|
|
Link& operator= (const Link&);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetObj(const string&n, unsigned npins);
|
|
|
|
|
virtual ~NetObj();
|
|
|
|
|
|
|
|
|
|
const string& name() const { return name_; }
|
|
|
|
|
|
|
|
|
|
unsigned pin_count() const { return npins_; }
|
|
|
|
|
|
|
|
|
|
unsigned delay1() const { return delay1_; }
|
|
|
|
|
unsigned delay2() const { return delay2_; }
|
|
|
|
|
unsigned delay3() const { return delay3_; }
|
|
|
|
|
|
|
|
|
|
void delay1(unsigned d) { delay1_ = d; }
|
|
|
|
|
void delay2(unsigned d) { delay2_ = d; }
|
|
|
|
|
void delay3(unsigned d) { delay3_ = d; }
|
|
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
void set_attributes(const map<string,string>&);
|
|
|
|
|
string attribute(const string&key) const;
|
1998-12-07 05:53:16 +01:00
|
|
|
void attribute(const string&key, const string&value);
|
1998-11-23 01:20:22 +01:00
|
|
|
|
1998-12-02 05:37:13 +01:00
|
|
|
// Return true if this has all the attributes in that and they
|
|
|
|
|
// all have the same values.
|
|
|
|
|
bool has_compat_attributes(const NetObj&that) const;
|
|
|
|
|
|
1998-11-13 07:23:17 +01:00
|
|
|
bool test_mark() const { return mark_; }
|
|
|
|
|
void set_mark(bool flag=true) { mark_ = flag; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
Link&pin(unsigned idx) { return pins_[idx]; }
|
|
|
|
|
const Link&pin(unsigned idx) const { return pins_[idx]; }
|
|
|
|
|
|
|
|
|
|
void dump_node_pins(ostream&, unsigned) const;
|
1998-11-23 01:20:22 +01:00
|
|
|
void dump_obj_attr(ostream&, unsigned) const;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
string name_;
|
|
|
|
|
Link*pins_;
|
|
|
|
|
const unsigned npins_;
|
|
|
|
|
unsigned delay1_;
|
|
|
|
|
unsigned delay2_;
|
|
|
|
|
unsigned delay3_;
|
1998-11-13 07:23:17 +01:00
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
map<string,string> attributes_;
|
|
|
|
|
|
1998-11-13 07:23:17 +01:00
|
|
|
bool mark_;
|
1998-11-04 00:28:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A NetNode is a device of some sort, where each pin has a different
|
|
|
|
|
* meaning. (i.e. pin(0) is the output to an and gate.) NetNode
|
|
|
|
|
* objects are listed in the nodes_ of the Design object.
|
|
|
|
|
*/
|
|
|
|
|
class NetNode : public NetObj {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetNode(const string&n, unsigned npins)
|
|
|
|
|
: NetObj(n, npins), node_next_(0), node_prev_(0), design_(0) { }
|
|
|
|
|
|
|
|
|
|
virtual ~NetNode();
|
|
|
|
|
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump_node(ostream&, unsigned) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class Design;
|
|
|
|
|
NetNode*node_next_, *node_prev_;
|
|
|
|
|
Design*design_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* NetNet is a special kind of NetObj that doesn't really do anything,
|
|
|
|
|
* but carries the properties of the wire/reg/trireg. Thus, a set of
|
|
|
|
|
* pins connected together would also be connected to exactly one of
|
|
|
|
|
* these.
|
|
|
|
|
*
|
|
|
|
|
* Note that a net of any sort has exactly one pin. The pins feature
|
|
|
|
|
* of the NetObj class is used to make a set of identical wires, in
|
|
|
|
|
* order to support ranges, or busses.
|
|
|
|
|
*/
|
|
|
|
|
class NetNet : public NetObj {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum Type { IMPLICIT, WIRE, TRI, TRI1, SUPPLY0, WAND, TRIAND,
|
|
|
|
|
TRI0, SUPPLY1, WOR, TRIOR, REG };
|
|
|
|
|
|
|
|
|
|
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
explicit NetNet(const string&n, Type t, unsigned npins =1);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
explicit NetNet(const string&n, Type t, long ms, long ls);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
virtual ~NetNet();
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
Type type() const { return type_; }
|
|
|
|
|
void type(Type t) { type_ = t; }
|
|
|
|
|
|
|
|
|
|
PortType port_type() const { return port_type_; }
|
|
|
|
|
void port_type(PortType t) { port_type_ = t; }
|
|
|
|
|
|
|
|
|
|
long msb() const { return msb_; }
|
|
|
|
|
long lsb() const { return lsb_; }
|
|
|
|
|
|
|
|
|
|
unsigned sb_to_idx(long sb) const
|
|
|
|
|
{ if (msb_ >= lsb_)
|
|
|
|
|
return sb - lsb_;
|
|
|
|
|
else
|
|
|
|
|
return lsb_ - sb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool local_flag() const { return local_flag_; }
|
|
|
|
|
void local_flag(bool f) { local_flag_ = f; }
|
|
|
|
|
|
1998-12-20 03:05:41 +01:00
|
|
|
verinum::V get_ival(unsigned pin) const
|
|
|
|
|
{ return ivalue_[pin]; }
|
|
|
|
|
void set_ival(unsigned pin, verinum::V val)
|
|
|
|
|
{ ivalue_[pin] = val; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
virtual void dump_net(ostream&, unsigned) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// The Design class uses this for listing signals.
|
|
|
|
|
friend class Design;
|
|
|
|
|
NetNet*sig_next_, *sig_prev_;
|
|
|
|
|
Design*design_;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Type type_;
|
|
|
|
|
PortType port_type_;
|
|
|
|
|
|
|
|
|
|
long msb_, lsb_;
|
|
|
|
|
|
|
|
|
|
bool local_flag_;
|
1998-12-20 03:05:41 +01:00
|
|
|
|
|
|
|
|
verinum::V*ivalue_;
|
1998-11-04 00:28:49 +01:00
|
|
|
};
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
/*
|
|
|
|
|
* This class represents the declared memory object. The parser
|
|
|
|
|
* creates one of these for each declared memory in the elaborated
|
|
|
|
|
* design. A reference to one of these is handled by the NetEMemory
|
|
|
|
|
* object, which is derived from NetExpr.
|
|
|
|
|
*/
|
|
|
|
|
class NetMemory {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetMemory(const string&n, long w, long s, long e)
|
|
|
|
|
: name_(n), width_(w), idxh_(s), idxl_(e) { }
|
|
|
|
|
|
|
|
|
|
const string&name() const { return name_; }
|
|
|
|
|
unsigned width() const { return width_; }
|
|
|
|
|
|
|
|
|
|
void set_attributes(const map<string,string>&a);
|
|
|
|
|
|
|
|
|
|
void dump(ostream&o, unsigned lm) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
string name_;
|
|
|
|
|
unsigned width_;
|
|
|
|
|
long idxh_;
|
|
|
|
|
long idxl_;
|
|
|
|
|
|
|
|
|
|
map<string,string> attributes_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
/* =========
|
|
|
|
|
* There are cases where expressions need to be represented. The
|
|
|
|
|
* NetExpr class is the root of a heirarchy that serves that purpose.
|
|
|
|
|
*
|
|
|
|
|
* The expr_width() is the width of the expression, that accounts
|
|
|
|
|
* for the widths of the sub-expressions I might have. It is up to the
|
|
|
|
|
* derived classes to properly set the expr width, if need be. The
|
|
|
|
|
* set_width() method is used to compel an expression to have a
|
|
|
|
|
* certain width, and is used particulary when the expression is an
|
|
|
|
|
* rvalue in an assignment statement.
|
|
|
|
|
*
|
|
|
|
|
* The NetExpr::REF type can be used sort of like a pointer to
|
|
|
|
|
* NetExpr objects. The NetExpr uses this list to know if it is still
|
|
|
|
|
* being referenced, so can handle garbage collection. Also, this
|
|
|
|
|
* trick can be used to replace subexpressions.
|
|
|
|
|
*/
|
|
|
|
|
class NetExpr {
|
|
|
|
|
public:
|
|
|
|
|
explicit NetExpr(unsigned w =0) : width_(w), reflist_(0) { }
|
|
|
|
|
virtual ~NetExpr() =0;
|
|
|
|
|
|
|
|
|
|
virtual void expr_scan(struct expr_scan_t*) const =0;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
unsigned expr_width() const { return width_; }
|
|
|
|
|
virtual void set_width(unsigned);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
class REF {
|
|
|
|
|
friend class NetExpr;
|
|
|
|
|
public:
|
|
|
|
|
void clr();
|
|
|
|
|
void set(NetExpr*);
|
|
|
|
|
NetExpr*ref() const { return ref_; }
|
|
|
|
|
|
|
|
|
|
void clr_and_delete()
|
|
|
|
|
{ NetExpr*tmp = ref_;
|
|
|
|
|
clr();
|
|
|
|
|
if (tmp && tmp->is_referenced() == false)
|
|
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*operator-> () const { return ref_; }
|
|
|
|
|
REF& operator=(NetExpr*that) { set(that); return *this; }
|
|
|
|
|
|
|
|
|
|
REF() : ref_(0), next_(0) { }
|
|
|
|
|
REF(NetExpr*that) : ref_(0), next_(0) { set(that); }
|
|
|
|
|
REF(const REF&that) : ref_(0), next_(0) { set(that.ref_); }
|
|
|
|
|
~REF() { clr(); }
|
|
|
|
|
private:
|
|
|
|
|
NetExpr*ref_;
|
|
|
|
|
REF*next_;
|
|
|
|
|
private:// not implemented
|
|
|
|
|
REF& operator=(const REF&);
|
|
|
|
|
};
|
|
|
|
|
friend class NetExpr::REF;
|
|
|
|
|
|
|
|
|
|
/* This method causes every item that references this object
|
|
|
|
|
to reference that object instead. When this complete,
|
|
|
|
|
no references to me will remain. */
|
|
|
|
|
void substitute(NetExpr*that);
|
|
|
|
|
|
|
|
|
|
bool is_referenced() const { return reflist_ != 0; }
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void expr_width(unsigned w) { width_ = w; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
unsigned width_;
|
|
|
|
|
|
|
|
|
|
REF*reflist_;
|
|
|
|
|
|
|
|
|
|
private: // not implemented
|
|
|
|
|
NetExpr(const NetExpr&);
|
|
|
|
|
NetExpr& operator=(const NetExpr&);
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* The NetTmp object is a network that is only used momentarily by
|
|
|
|
|
* elaboration to carry links around. A completed netlist cannot have
|
|
|
|
|
* any of these within. This is a kind of wire, so it is NetNet type.
|
|
|
|
|
*/
|
|
|
|
|
class NetTmp : public NetNet {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetTmp(unsigned npins =1)
|
|
|
|
|
: NetNet("@", IMPLICIT, npins) { }
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The NetBUFZ is a magic device that represents the continuous
|
|
|
|
|
* assign, with the output being the target register and the input
|
|
|
|
|
* the logic that feeds it. The netlist preserves the directional
|
|
|
|
|
* nature of that assignment with the BUFZ. The target may elide it if
|
|
|
|
|
* that makes sense for the technology.
|
|
|
|
|
*/
|
|
|
|
|
class NetBUFZ : public NetNode {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetBUFZ(const string&n)
|
1998-12-02 05:37:13 +01:00
|
|
|
: NetNode(n, 2)
|
|
|
|
|
{ pin(0).set_dir(Link::OUTPUT);
|
|
|
|
|
pin(1).set_dir(Link::INPUT);
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
class NetConst : public NetNode {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetConst(const string&n, verinum::V v)
|
1998-12-02 05:37:13 +01:00
|
|
|
: NetNode(n, 1), value_(v) { pin(0).set_dir(Link::OUTPUT); }
|
1998-11-09 19:55:33 +01:00
|
|
|
|
|
|
|
|
verinum::V value() const { return value_; }
|
|
|
|
|
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
verinum::V value_;
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
1998-12-02 05:37:13 +01:00
|
|
|
* This class represents all manner of logic gates. Pin 0 is OUTPUT and
|
|
|
|
|
* all the remaining pins are INPUT
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
class NetLogic : public NetNode {
|
|
|
|
|
|
|
|
|
|
public:
|
1999-02-15 03:06:15 +01:00
|
|
|
enum TYPE { AND, BUF, BUFIF0, BUFIF1, NAND, NOR, NOT, OR, XNOR,
|
|
|
|
|
XOR };
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-12-02 05:37:13 +01:00
|
|
|
explicit NetLogic(const string&n, unsigned pins, TYPE t);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
TYPE type() const { return type_; }
|
|
|
|
|
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const TYPE type_;
|
|
|
|
|
};
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
/*
|
|
|
|
|
* The UDP is a User Defined Primitive from the Verilog source. Do not
|
|
|
|
|
* expand it out any further then this in the netlist, as this can be
|
|
|
|
|
* used to represent target device primitives.
|
1998-12-14 03:01:34 +01:00
|
|
|
*
|
|
|
|
|
* The UDP can be combinational or sequential. The sequentianl UDP
|
|
|
|
|
* includes the current output in the truth table, and supports edges,
|
|
|
|
|
* whereas the combinational does not and is entirely level sensitive.
|
|
|
|
|
* In any case, pin 0 is an output, and all the remaining pins are
|
|
|
|
|
* inputs.
|
|
|
|
|
*
|
|
|
|
|
* The truth table is canonically represented as a finite state
|
|
|
|
|
* machine with the current state representing the inputs and the
|
|
|
|
|
* current output, and the next state carrying the new output value to
|
|
|
|
|
* use. All the outgoing transitions from a state represent a single
|
|
|
|
|
* edge.
|
|
|
|
|
*
|
|
|
|
|
* Set_table takes as input a string with one letter per pin. The
|
1998-12-18 06:16:25 +01:00
|
|
|
* parser translates the written sequences to one of these. The
|
1998-12-14 03:01:34 +01:00
|
|
|
* valid characters are:
|
|
|
|
|
*
|
|
|
|
|
* 0, 1, x -- The levels
|
|
|
|
|
* r -- (01)
|
|
|
|
|
* R -- (x1)
|
|
|
|
|
* f -- (10)
|
|
|
|
|
* F -- (x0)
|
|
|
|
|
* P -- (0x)
|
|
|
|
|
* N -- (1x)
|
|
|
|
|
*
|
1998-12-18 06:16:25 +01:00
|
|
|
* It also takes one of the following glob letters to represent more
|
|
|
|
|
* then one item.
|
|
|
|
|
*
|
|
|
|
|
* p -- 01, 0x or x1
|
|
|
|
|
* n -- 10, 1x or x0
|
|
|
|
|
* ? -- 0, 1, or x
|
|
|
|
|
* * -- any edge
|
|
|
|
|
* + -- 01 or x1
|
|
|
|
|
* _ -- 10 or x0 (Note that this is not the output '-'.)
|
|
|
|
|
* % -- 0x or 1x
|
|
|
|
|
*
|
1998-12-14 03:01:34 +01:00
|
|
|
* COMBINATIONAL
|
|
|
|
|
* The logic table is a map between the input levels and the
|
|
|
|
|
* output. Each input pin can have the value 0, 1 or x and the output
|
|
|
|
|
* can have the values 0 or 1. If the input matches nothing, the
|
|
|
|
|
* output is x. In canonical form, only the entries that generate 0 or
|
|
|
|
|
* 1 are listed.
|
|
|
|
|
*
|
|
|
|
|
* SEQUENTIAL
|
|
|
|
|
* These objects have a single bit of memory. The logic table includes
|
|
|
|
|
* an entry for the current value, and allows edges on the inputs. In
|
|
|
|
|
* canonical form, inly then entries that generate 0, 1 or - (no change)
|
|
|
|
|
* are listed.
|
|
|
|
|
*
|
1998-12-01 01:42:13 +01:00
|
|
|
*/
|
|
|
|
|
class NetUDP : public NetNode {
|
|
|
|
|
|
|
|
|
|
public:
|
1998-12-14 03:01:34 +01:00
|
|
|
explicit NetUDP(const string&n, unsigned pins, bool sequ =false);
|
1998-12-01 01:42:13 +01:00
|
|
|
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
1998-12-14 03:01:34 +01:00
|
|
|
|
|
|
|
|
/* return false if the entry conflicts with an existing
|
|
|
|
|
entry. In any case, the new output overrides. */
|
|
|
|
|
bool set_table(const string&input, char output);
|
|
|
|
|
void cleanup_table();
|
|
|
|
|
|
1998-12-18 00:54:58 +01:00
|
|
|
/* Return the next output from the passed state. Each letter
|
|
|
|
|
of the input string represents the pin of the same
|
|
|
|
|
position. */
|
|
|
|
|
char table_lookup(const string&from, char to, unsigned pin) const;
|
|
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
void set_initial(char);
|
1998-12-18 00:54:58 +01:00
|
|
|
char get_initial() const { return init_; }
|
1998-12-14 03:01:34 +01:00
|
|
|
|
|
|
|
|
bool is_sequential() const { return sequential_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const bool sequential_;
|
|
|
|
|
char init_;
|
|
|
|
|
|
|
|
|
|
struct state_t_;
|
|
|
|
|
struct pin_t_ {
|
|
|
|
|
state_t_*zer;
|
|
|
|
|
state_t_*one;
|
|
|
|
|
state_t_*xxx;
|
|
|
|
|
|
|
|
|
|
explicit pin_t_() : zer(0), one(0), xxx(0) { }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct state_t_ {
|
|
|
|
|
char out;
|
|
|
|
|
pin_t_*pins;
|
|
|
|
|
|
|
|
|
|
state_t_(unsigned n) : out(0), pins(new pin_t_[n]) {}
|
|
|
|
|
~state_t_() { delete[]pins; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef map<string,state_t_*> FSM_;
|
|
|
|
|
FSM_ fsm_;
|
|
|
|
|
bool set_sequ_(const string&in, char out);
|
|
|
|
|
bool sequ_glob_(string, char out);
|
|
|
|
|
|
|
|
|
|
state_t_*find_state_(const string&);
|
|
|
|
|
|
|
|
|
|
void dump_sequ_(ostream&o, unsigned ind) const;
|
|
|
|
|
void dump_comb_(ostream&o, unsigned ind) const;
|
1998-12-01 01:42:13 +01:00
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/* =========
|
|
|
|
|
* A process is a behavioral-model description. A process is a
|
|
|
|
|
* statement that may be compound. the various statement types may
|
|
|
|
|
* refer to places in a netlist (by pointing to nodes) but is not
|
|
|
|
|
* linked into the netlist. However, elaborating a process may cause
|
|
|
|
|
* special nodes to be created to handle things like events.
|
|
|
|
|
*/
|
|
|
|
|
class NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit NetProc() : next_(0) { }
|
|
|
|
|
virtual ~NetProc();
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class NetBlock;
|
|
|
|
|
NetProc*next_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-15 03:43:32 +01:00
|
|
|
/*
|
|
|
|
|
* This is a procedural assignment. The lval is a register, and the
|
|
|
|
|
* assignment happens when the code is executed by the design. The
|
|
|
|
|
* node part of the NetAssign has as many pins as the width of the
|
|
|
|
|
* lvalue object and represents the elaborated lvalue. Thus, this
|
|
|
|
|
* appears as a procedural statement AND a structural node. The
|
|
|
|
|
* LineInfo is the location of the assignment statement in the source.
|
|
|
|
|
*/
|
|
|
|
|
class NetAssign : public NetProc, public NetNode, public LineInfo {
|
1998-11-04 00:28:49 +01:00
|
|
|
public:
|
|
|
|
|
explicit NetAssign(NetNet*lv, NetExpr*rv);
|
|
|
|
|
~NetAssign();
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr*rval() const { return rval_.ref(); }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
void find_lval_range(const NetNet*&net, unsigned&msb,
|
|
|
|
|
unsigned&lsb) const;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF rval_;
|
1998-11-04 00:28:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* A block is stuff line begin-end blocks, that contain and ordered
|
|
|
|
|
list of NetProc statements.
|
|
|
|
|
|
|
|
|
|
NOTE: The emit method calls the target->proc_block function but
|
|
|
|
|
does not recurse. It is up to the target-supplied proc_block
|
|
|
|
|
function to call emit_recurse. */
|
|
|
|
|
class NetBlock : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum Type { SEQU, PARA };
|
|
|
|
|
|
|
|
|
|
NetBlock(Type t) : type_(t), last_(0) { }
|
|
|
|
|
~NetBlock();
|
|
|
|
|
|
|
|
|
|
const Type type() const { return type_; }
|
|
|
|
|
|
|
|
|
|
void append(NetProc*);
|
|
|
|
|
|
|
|
|
|
void emit_recurse(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const Type type_;
|
|
|
|
|
|
|
|
|
|
NetProc*last_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-02-03 05:20:11 +01:00
|
|
|
/* A CASE statement in the verilog source leads, eventually, to one of
|
|
|
|
|
these. This is different from a simple conditional because of the
|
|
|
|
|
way the comparisons are performed. Also, it is likely that the
|
|
|
|
|
target may be able to optimize differently. */
|
|
|
|
|
class NetCase : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetCase(NetExpr*ex, unsigned cnt);
|
|
|
|
|
~NetCase();
|
|
|
|
|
|
|
|
|
|
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr*expr() const { return expr_.ref(); }
|
1999-02-08 03:49:56 +01:00
|
|
|
unsigned nitems() const { return nitems_; }
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr*expr(unsigned idx) const { return items_[idx].guard.ref();}
|
1999-02-08 03:49:56 +01:00
|
|
|
const NetProc*stat(unsigned idx) const { return items_[idx].statement; }
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
1999-02-03 05:20:11 +01:00
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
struct Item {
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF guard;
|
1999-02-03 05:20:11 +01:00
|
|
|
NetProc*statement;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF expr_;
|
1999-02-03 05:20:11 +01:00
|
|
|
unsigned nitems_;
|
|
|
|
|
Item*items_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
/* A condit represents a conditional. It has an expression to test,
|
|
|
|
|
and a pair of statements to select from. */
|
|
|
|
|
class NetCondit : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetCondit(NetExpr*ex, NetProc*i, NetProc*e)
|
|
|
|
|
: expr_(ex), if_(i), else_(e) { }
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr*expr() const { return expr_.ref(); }
|
1998-11-07 18:05:05 +01:00
|
|
|
void emit_recurse_if(ostream&, struct target_t*) const;
|
|
|
|
|
void emit_recurse_else(ostream&, struct target_t*) const;
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF expr_;
|
1998-11-07 18:05:05 +01:00
|
|
|
NetProc*if_;
|
|
|
|
|
NetProc*else_;
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
class NetPDelay : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetPDelay(unsigned long d, NetProc*st)
|
|
|
|
|
: delay_(d), statement_(st) { }
|
|
|
|
|
|
|
|
|
|
unsigned long delay() const { return delay_; }
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
void emit_proc_recurse(ostream&, struct target_t*) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
unsigned long delay_;
|
|
|
|
|
NetProc*statement_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The NetPEvent is a NetNode that connects to the structural part of
|
|
|
|
|
* the design. It has only inputs, which cause the side effect of
|
|
|
|
|
* triggering an event that the procedural part of the design can use.
|
|
|
|
|
*/
|
|
|
|
|
class NetPEvent : public NetProc, public NetNode {
|
|
|
|
|
|
|
|
|
|
public:
|
1998-11-09 19:55:33 +01:00
|
|
|
enum Type { ANYEDGE, POSEDGE, NEGEDGE, POSITIVE };
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetPEvent(const string&ev, Type ed, NetProc*st)
|
|
|
|
|
: NetNode(ev, 1), edge_(ed), statement_(st) { }
|
|
|
|
|
|
|
|
|
|
Type edge() const { return edge_; }
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
void emit_proc_recurse(ostream&, struct target_t*) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Type edge_;
|
|
|
|
|
NetProc*statement_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The elaborator should expand all the user defined tasks in line, so
|
|
|
|
|
this leaves the NetTask to represent activations of system tasks,
|
|
|
|
|
or external tasks that are not known at compile time. */
|
|
|
|
|
class NetTask : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetTask(const string&na, unsigned np)
|
|
|
|
|
: name_(na), nparms_(np)
|
1999-03-01 04:27:53 +01:00
|
|
|
{ parms_ = new NetExpr::REF[nparms_]; }
|
1998-11-04 00:28:49 +01:00
|
|
|
~NetTask();
|
|
|
|
|
|
|
|
|
|
const string& name() const { return name_; }
|
|
|
|
|
|
|
|
|
|
unsigned nparms() const { return nparms_; }
|
|
|
|
|
|
|
|
|
|
void parm(unsigned idx, NetExpr*p)
|
|
|
|
|
{ assert(idx < nparms_);
|
|
|
|
|
parms_[idx] = p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* parm(unsigned idx) const
|
|
|
|
|
{ assert(idx < nparms_);
|
1999-03-01 04:27:53 +01:00
|
|
|
return parms_[idx].ref();
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
string name_;
|
|
|
|
|
unsigned nparms_;
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF*parms_;
|
1998-11-04 00:28:49 +01:00
|
|
|
};
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
/*
|
|
|
|
|
* The while statement is a condition that is tested in the front of
|
|
|
|
|
* each iteration, and a statement (a NetProc) that is executed as
|
|
|
|
|
* long as the condition is true.
|
|
|
|
|
*/
|
|
|
|
|
class NetWhile : public NetProc {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetWhile(NetExpr*c, NetProc*p)
|
|
|
|
|
: cond_(c), proc_(p) { }
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr*expr() const { return cond_.ref(); }
|
1998-11-09 19:55:33 +01:00
|
|
|
|
|
|
|
|
void emit_proc_recurse(ostream&, struct target_t*) const;
|
|
|
|
|
|
|
|
|
|
virtual void emit_proc(ostream&, struct target_t*) const;
|
|
|
|
|
virtual void dump(ostream&, unsigned ind) const;
|
|
|
|
|
|
|
|
|
|
private:
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF cond_;
|
1998-11-09 19:55:33 +01:00
|
|
|
NetProc*proc_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/* The is the top of any process. It carries the type (initial or
|
|
|
|
|
always) and a pointer to the statement, probably a block, that
|
|
|
|
|
makes up the process. */
|
1999-02-01 01:26:48 +01:00
|
|
|
class NetProcTop : public LineInfo {
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
enum Type { KINITIAL, KALWAYS };
|
|
|
|
|
|
|
|
|
|
NetProcTop(Type t, NetProc*st) : type_(t), statement_(st) { }
|
|
|
|
|
|
|
|
|
|
Type type() const { return type_; }
|
|
|
|
|
const NetProc*statement() const { return statement_; }
|
|
|
|
|
|
|
|
|
|
void dump(ostream&, unsigned ind) const;
|
|
|
|
|
void emit(ostream&, struct target_t*tgt) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const Type type_;
|
|
|
|
|
NetProc*const statement_;
|
|
|
|
|
|
|
|
|
|
friend class Design;
|
|
|
|
|
NetProcTop*next_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-15 03:43:32 +01:00
|
|
|
/*
|
|
|
|
|
* This class represents a binary operator, with the left and right
|
|
|
|
|
* operands and a single character for the operator. The operator
|
|
|
|
|
* values are:
|
|
|
|
|
*
|
|
|
|
|
* ^ -- Bit-wise exclusive OR
|
|
|
|
|
* + -- Arithmetic add
|
|
|
|
|
* - -- Arighmetic minus
|
|
|
|
|
* & -- Bit-wise AND
|
|
|
|
|
* | -- Bit-wise OR
|
|
|
|
|
* e -- Logical equality (==)
|
|
|
|
|
* E -- Case equality (===)
|
|
|
|
|
* n -- Logical inequality (!=)
|
|
|
|
|
* N -- Case inequality (!==)
|
|
|
|
|
* a -- Logical AND (&&)
|
|
|
|
|
* o -- Logical OR (||)
|
|
|
|
|
*/
|
1998-11-07 18:05:05 +01:00
|
|
|
class NetEBinary : public NetExpr {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetEBinary(char op, NetExpr*l, NetExpr*r);
|
|
|
|
|
~NetEBinary();
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr*left() const { return left_.ref(); }
|
|
|
|
|
const NetExpr*right() const { return right_.ref(); }
|
1998-11-07 18:05:05 +01:00
|
|
|
|
|
|
|
|
char op() const { return op_; }
|
|
|
|
|
|
1998-11-07 20:17:10 +01:00
|
|
|
void set_width(unsigned w);
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
char op_;
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF left_;
|
|
|
|
|
NetExpr::REF right_;
|
1998-11-07 18:05:05 +01:00
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
class NetEConst : public NetExpr {
|
|
|
|
|
|
|
|
|
|
public:
|
1998-11-07 18:05:05 +01:00
|
|
|
NetEConst(const verinum&val)
|
|
|
|
|
: NetExpr(val.len()), value_(val) { }
|
1998-11-04 00:28:49 +01:00
|
|
|
~NetEConst();
|
|
|
|
|
|
|
|
|
|
const verinum&value() const { return value_; }
|
|
|
|
|
|
1998-11-07 20:17:10 +01:00
|
|
|
virtual void set_width(unsigned w);
|
1998-11-04 00:28:49 +01:00
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
verinum value_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-15 03:43:32 +01:00
|
|
|
/*
|
|
|
|
|
* This class represents a unaru operator, with the single operand
|
|
|
|
|
* and a single character for the operator. The operator values are:
|
|
|
|
|
*
|
|
|
|
|
* ~ -- Bit-wise negation
|
|
|
|
|
* ! -- Logical negation
|
|
|
|
|
* & -- Reduction AND
|
|
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
class NetEUnary : public NetExpr {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetEUnary(char op, NetExpr*ex)
|
1998-11-07 20:17:10 +01:00
|
|
|
: NetExpr(ex->expr_width()), op_(op), expr_(ex) { }
|
|
|
|
|
~NetEUnary();
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
char op() const { return op_; }
|
1999-03-01 04:27:53 +01:00
|
|
|
const NetExpr* expr() const { return expr_.ref(); }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-11-07 20:17:10 +01:00
|
|
|
void set_width(unsigned w);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
char op_;
|
1999-03-01 04:27:53 +01:00
|
|
|
NetExpr::REF expr_;
|
1998-11-04 00:28:49 +01:00
|
|
|
};
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
/* System identifiers are represented here. */
|
1998-11-04 00:28:49 +01:00
|
|
|
class NetEIdent : public NetExpr {
|
|
|
|
|
|
|
|
|
|
public:
|
1998-11-07 18:05:05 +01:00
|
|
|
NetEIdent(const string&n, unsigned w)
|
|
|
|
|
: NetExpr(w), name_(n) { }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
const string& name() const { return name_; }
|
|
|
|
|
|
|
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
string name_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
/*
|
|
|
|
|
* A reference to a memory is represented by this expression.
|
|
|
|
|
*/
|
|
|
|
|
class NetEMemory : public NetExpr {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
NetEMemory(NetMemory*mem, NetExpr*idx);
|
|
|
|
|
virtual ~NetEMemory();
|
|
|
|
|
|
|
|
|
|
virtual void set_width(unsigned);
|
|
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
|
|
|
|
virtual void dump(ostream&) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
NetMemory*mem_;
|
|
|
|
|
NetExpr::REF idx_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
/*
|
|
|
|
|
* When a signal shows up in an expression, this type represents
|
|
|
|
|
* it. From this the expression can get any kind of access to the
|
|
|
|
|
* structural signal.
|
|
|
|
|
*
|
|
|
|
|
* A signal shows up as a node in the netlist so that structural
|
|
|
|
|
* activity can invoke the expression.
|
|
|
|
|
*/
|
1999-02-08 03:49:56 +01:00
|
|
|
class NetESignal : public NetExpr, public NetNode {
|
1998-11-07 18:05:05 +01:00
|
|
|
|
|
|
|
|
public:
|
1999-02-08 03:49:56 +01:00
|
|
|
NetESignal(NetNet*n);
|
1998-11-07 20:17:10 +01:00
|
|
|
~NetESignal();
|
1998-11-07 18:05:05 +01:00
|
|
|
|
1999-02-08 03:49:56 +01:00
|
|
|
const string& name() const { return NetNode::name(); }
|
1998-11-07 18:05:05 +01:00
|
|
|
|
1998-11-07 20:17:10 +01:00
|
|
|
virtual void set_width(unsigned);
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
virtual void expr_scan(struct expr_scan_t*) const;
|
1999-02-08 03:49:56 +01:00
|
|
|
virtual void emit_node(ostream&, struct target_t*) const;
|
1998-11-07 18:05:05 +01:00
|
|
|
virtual void dump(ostream&) const;
|
1999-02-08 03:49:56 +01:00
|
|
|
virtual void dump_node(ostream&, unsigned ind) const;
|
1998-11-07 18:05:05 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* This class contains an entire design. It includes processes and a
|
|
|
|
|
* netlist, and can be passed around from function to function.
|
|
|
|
|
*/
|
|
|
|
|
class Design {
|
|
|
|
|
|
|
|
|
|
public:
|
1999-02-01 01:26:48 +01:00
|
|
|
Design() : errors(0), signals_(0), nodes_(0), procs_(0), lcounter_(0) { }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-11-18 05:25:22 +01:00
|
|
|
/* The flags are a generic way of accepting command line
|
|
|
|
|
parameters/flags and passing them to the processing steps
|
|
|
|
|
that deal with the design. The compilation driver sets the
|
|
|
|
|
entire flags map after elaboration is done. Subsequent
|
|
|
|
|
steps can then use the get_flag() function to get the value
|
|
|
|
|
of an interesting key. */
|
|
|
|
|
|
|
|
|
|
void set_flags(const map<string,string>&f) { flags_ = f; }
|
|
|
|
|
|
|
|
|
|
string get_flag(const string&key) const;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-02-21 18:01:57 +01:00
|
|
|
// PARAMETERS
|
|
|
|
|
void set_parameter(const string&, NetExpr*);
|
|
|
|
|
NetExpr*get_parameter(const string&name) const;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// SIGNALS
|
|
|
|
|
void add_signal(NetNet*);
|
|
|
|
|
void del_signal(NetNet*);
|
|
|
|
|
NetNet*find_signal(const string&name);
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
// Memories
|
|
|
|
|
void add_memory(NetMemory*);
|
|
|
|
|
NetMemory* find_memory(const string&name);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// NODES
|
|
|
|
|
void add_node(NetNode*);
|
|
|
|
|
void del_node(NetNode*);
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
// ESIGNALS
|
|
|
|
|
NetESignal* get_esignal(NetNet*net);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// PROCESSES
|
|
|
|
|
void add_process(NetProcTop*);
|
|
|
|
|
|
|
|
|
|
// Iterate over the design...
|
|
|
|
|
void dump(ostream&) const;
|
|
|
|
|
void emit(ostream&, struct target_t*) const;
|
|
|
|
|
|
1998-11-13 07:23:17 +01:00
|
|
|
void clear_node_marks();
|
|
|
|
|
NetNode*find_node(bool (*test)(const NetNode*));
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-11-16 06:03:52 +01:00
|
|
|
void clear_signal_marks();
|
|
|
|
|
NetNet*find_signal(bool (*test)(const NetNet*));
|
|
|
|
|
|
1999-02-01 01:26:48 +01:00
|
|
|
// This is incremented by elaboration when an error is
|
|
|
|
|
// detected. It prevents code being emitted.
|
|
|
|
|
unsigned errors;
|
1998-12-07 05:53:16 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
string local_symbol(const string&path);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
private:
|
1999-03-01 04:27:53 +01:00
|
|
|
// List all the parameters in the design. This table includes
|
|
|
|
|
// the parameters of instantiated modules in canonical names.
|
|
|
|
|
map<string,NetExpr::REF> parameters_;
|
1999-02-21 18:01:57 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// List all the signals in the design.
|
|
|
|
|
NetNet*signals_;
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
map<string,NetMemory*> memories_;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// List the nodes in the design
|
|
|
|
|
NetNode*nodes_;
|
|
|
|
|
|
|
|
|
|
// List the processes in the design.
|
|
|
|
|
NetProcTop*procs_;
|
|
|
|
|
|
1998-11-18 05:25:22 +01:00
|
|
|
map<string,string> flags_;
|
|
|
|
|
|
1999-03-01 04:27:53 +01:00
|
|
|
// Use this map to prevent duplicate signals.
|
|
|
|
|
map<string,NetESignal*> esigs_;
|
|
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
unsigned lcounter_;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
private: // not implemented
|
|
|
|
|
Design(const Design&);
|
|
|
|
|
Design& operator= (const Design&);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* =======
|
|
|
|
|
*/
|
|
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
inline bool operator == (const NetObj::Link&l, const NetObj::Link&r)
|
|
|
|
|
{ return l.is_equal(r); }
|
|
|
|
|
|
|
|
|
|
inline bool operator != (const NetObj::Link&l, const NetObj::Link&r)
|
|
|
|
|
{ return ! l.is_equal(r); }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
/* Connect the pins of two nodes together. Either may already be
|
|
|
|
|
connected to other things, connect is transitive. */
|
|
|
|
|
extern void connect(NetObj::Link&, NetObj::Link&);
|
|
|
|
|
|
1998-12-02 05:37:13 +01:00
|
|
|
/* Return true if l and r are connected. */
|
1998-11-23 01:20:22 +01:00
|
|
|
inline bool connected(const NetObj::Link&l, const NetObj::Link&r)
|
|
|
|
|
{ return l.is_linked(r); }
|
|
|
|
|
|
|
|
|
|
/* Return true if l is fully connected to r. This means, every pin in
|
|
|
|
|
l is connected to a pin in r. This is expecially useful for
|
|
|
|
|
checking signal vectors. */
|
|
|
|
|
extern bool connected(const NetObj&l, const NetObj&r);
|
|
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
/* return the number of links in the ring that are of the specified
|
|
|
|
|
type. */
|
1998-12-02 05:37:13 +01:00
|
|
|
extern unsigned count_inputs(const NetObj::Link&pin);
|
|
|
|
|
extern unsigned count_outputs(const NetObj::Link&pin);
|
1998-12-07 05:53:16 +01:00
|
|
|
extern unsigned count_signals(const NetObj::Link&pin);
|
1998-12-02 05:37:13 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/* Find the signal connected to the given node pin. There should
|
|
|
|
|
always be exactly one signal. The bidx parameter get filled with
|
|
|
|
|
the signal index of the Net, in case it is a vector. */
|
|
|
|
|
const NetNet* find_link_signal(const NetObj*net, unsigned pin,
|
|
|
|
|
unsigned&bidx);
|
|
|
|
|
|
|
|
|
|
inline ostream& operator << (ostream&o, const NetExpr&exp)
|
|
|
|
|
{ exp.dump(o); return o; }
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
extern ostream& operator << (ostream&, NetNet::Type);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: netlist.h,v $
|
1999-04-19 03:59:36 +02:00
|
|
|
* Revision 1.23 1999/04/19 01:59:36 steve
|
|
|
|
|
* Add memories to the parse and elaboration phases.
|
|
|
|
|
*
|
1999-03-15 03:43:32 +01:00
|
|
|
* Revision 1.22 1999/03/15 02:43:32 steve
|
|
|
|
|
* Support more operators, especially logical.
|
|
|
|
|
*
|
1999-03-01 04:27:53 +01:00
|
|
|
* Revision 1.21 1999/03/01 03:27:53 steve
|
|
|
|
|
* Prevent the duplicate allocation of ESignal objects.
|
|
|
|
|
*
|
1999-02-21 18:01:57 +01:00
|
|
|
* Revision 1.20 1999/02/21 17:01:57 steve
|
|
|
|
|
* Add support for module parameters.
|
|
|
|
|
*
|
1999-02-15 03:06:15 +01:00
|
|
|
* Revision 1.19 1999/02/15 02:06:15 steve
|
|
|
|
|
* Elaborate gate ranges.
|
|
|
|
|
*
|
1999-02-08 03:49:56 +01:00
|
|
|
* Revision 1.18 1999/02/08 02:49:56 steve
|
|
|
|
|
* Turn the NetESignal into a NetNode so
|
|
|
|
|
* that it can connect to the netlist.
|
|
|
|
|
* Implement the case statement.
|
|
|
|
|
* Convince t-vvm to output code for
|
|
|
|
|
* the case statement.
|
|
|
|
|
*
|
1999-02-03 05:20:11 +01:00
|
|
|
* Revision 1.17 1999/02/03 04:20:11 steve
|
|
|
|
|
* Parse and elaborate the Verilog CASE statement.
|
|
|
|
|
*
|
1999-02-01 01:26:48 +01:00
|
|
|
* Revision 1.16 1999/02/01 00:26:49 steve
|
|
|
|
|
* Carry some line info to the netlist,
|
|
|
|
|
* Dump line numbers for processes.
|
|
|
|
|
* Elaborate prints errors about port vector
|
|
|
|
|
* width mismatch
|
|
|
|
|
* Emit better handles null statements.
|
|
|
|
|
*
|
1998-12-20 03:05:41 +01:00
|
|
|
* Revision 1.15 1998/12/20 02:05:41 steve
|
|
|
|
|
* Function to calculate wire initial value.
|
|
|
|
|
*
|
1998-12-18 06:16:25 +01:00
|
|
|
* Revision 1.14 1998/12/18 05:16:25 steve
|
|
|
|
|
* Parse more UDP input edge descriptions.
|
|
|
|
|
*
|
1998-12-18 00:54:58 +01:00
|
|
|
* Revision 1.13 1998/12/17 23:54:58 steve
|
|
|
|
|
* VVM support for small sequential UDP objects.
|
|
|
|
|
*
|
1998-12-14 03:01:34 +01:00
|
|
|
* Revision 1.12 1998/12/14 02:01:35 steve
|
|
|
|
|
* Fully elaborate Sequential UDP behavior.
|
|
|
|
|
*
|
1998-12-07 05:53:16 +01:00
|
|
|
* Revision 1.11 1998/12/07 04:53:17 steve
|
|
|
|
|
* Generate OBUF or IBUF attributes (and the gates
|
|
|
|
|
* to garry them) where a wire is a pad. This involved
|
|
|
|
|
* figuring out enough of the netlist to know when such
|
|
|
|
|
* was needed, and to generate new gates and signales
|
|
|
|
|
* to handle what's missing.
|
|
|
|
|
*
|
1998-12-02 05:37:13 +01:00
|
|
|
* Revision 1.10 1998/12/02 04:37:13 steve
|
|
|
|
|
* Add the nobufz function to eliminate bufz objects,
|
|
|
|
|
* Object links are marked with direction,
|
|
|
|
|
* constant propagation is more careful will wide links,
|
|
|
|
|
* Signal folding is aware of attributes, and
|
|
|
|
|
* the XNF target can dump UDP objects based on LCA
|
|
|
|
|
* attributes.
|
|
|
|
|
*
|
1998-12-01 01:42:13 +01:00
|
|
|
* Revision 1.9 1998/12/01 00:42:14 steve
|
|
|
|
|
* Elaborate UDP devices,
|
|
|
|
|
* Support UDP type attributes, and
|
|
|
|
|
* pass those attributes to nodes that
|
|
|
|
|
* are instantiated by elaboration,
|
|
|
|
|
* Put modules into a map instead of
|
|
|
|
|
* a simple list.
|
|
|
|
|
*
|
1998-11-23 01:20:22 +01:00
|
|
|
* Revision 1.8 1998/11/23 00:20:23 steve
|
|
|
|
|
* NetAssign handles lvalues as pin links
|
|
|
|
|
* instead of a signal pointer,
|
|
|
|
|
* Wire attributes added,
|
|
|
|
|
* Ability to parse UDP descriptions added,
|
|
|
|
|
* XNF generates EXT records for signals with
|
|
|
|
|
* the PAD attribute.
|
|
|
|
|
*
|
1998-11-18 05:25:22 +01:00
|
|
|
* Revision 1.7 1998/11/18 04:25:22 steve
|
|
|
|
|
* Add -f flags for generic flag key/values.
|
|
|
|
|
*
|
1998-11-16 06:03:52 +01:00
|
|
|
* Revision 1.6 1998/11/16 05:03:53 steve
|
|
|
|
|
* Add the sigfold function that unlinks excess
|
|
|
|
|
* signal nodes, and add the XNF target.
|
|
|
|
|
*
|
1998-11-13 07:23:17 +01:00
|
|
|
* Revision 1.5 1998/11/13 06:23:17 steve
|
|
|
|
|
* Introduce netlist optimizations with the
|
|
|
|
|
* cprop function to do constant propogation.
|
|
|
|
|
*
|
1998-11-09 19:55:33 +01:00
|
|
|
* Revision 1.4 1998/11/09 18:55:34 steve
|
|
|
|
|
* Add procedural while loops,
|
|
|
|
|
* Parse procedural for loops,
|
|
|
|
|
* Add procedural wait statements,
|
|
|
|
|
* Add constant nodes,
|
|
|
|
|
* Add XNOR logic gate,
|
|
|
|
|
* Make vvm output look a bit prettier.
|
|
|
|
|
*
|
1998-11-07 20:17:10 +01:00
|
|
|
* Revision 1.3 1998/11/07 19:17:10 steve
|
|
|
|
|
* Calculate expression widths at elaboration time.
|
|
|
|
|
*
|
1998-11-07 18:05:05 +01:00
|
|
|
* Revision 1.2 1998/11/07 17:05:05 steve
|
|
|
|
|
* Handle procedural conditional, and some
|
|
|
|
|
* of the conditional expressions.
|
|
|
|
|
*
|
|
|
|
|
* Elaborate signals and identifiers differently,
|
|
|
|
|
* allowing the netlist to hold signal information.
|
|
|
|
|
*
|
1998-11-04 00:28:49 +01:00
|
|
|
* Revision 1.1 1998/11/03 23:29:01 steve
|
|
|
|
|
* Introduce verilog to CVS.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#endif
|