Introduce verilog to CVS.
This commit is contained in:
commit
3fb7a053be
|
|
@ -0,0 +1,5 @@
|
|||
parse.h
|
||||
parse.cc
|
||||
parse.cc.output
|
||||
lexor.cc
|
||||
vl
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
CXXFLAGS = -O -g -Wall -Wno-uninitialized
|
||||
|
||||
%.o dep/%.d: %.cc
|
||||
$(CXX) $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
#TT = t-debug.o t-vvm.o
|
||||
TT = t-verilog.o t-vvm.o
|
||||
|
||||
O = main.o design_dump.o elaborate.o emit.o eval.o lexor.o mangle.o \
|
||||
netlist.o parse.o parse_misc.o pform.o pform_dump.o stupid.o verinum.o \
|
||||
target.o targets.o Module.o PExpr.o Statement.o $(TT)
|
||||
|
||||
vl: $O
|
||||
$(CXX) $(CXXFLAGS) -o vl $O
|
||||
|
||||
clean:
|
||||
rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc
|
||||
|
||||
lexor.o dep/lexor.d: lexor.cc parse.h
|
||||
|
||||
parse.h parse.cc: parse.y
|
||||
bison --verbose -t -p VL -d parse.y -o parse.cc
|
||||
mv parse.cc.h parse.h
|
||||
|
||||
lexor.cc: lexor.lex
|
||||
flex -PVL -s -olexor.cc lexor.lex
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: Module.cc,v 1.1 1998/11/03 23:28:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
# include "PWire.h"
|
||||
|
||||
void Module::add_gate(PGate*gate)
|
||||
{
|
||||
gates_.push_back(gate);
|
||||
}
|
||||
|
||||
void Module::add_wire(PWire*wire)
|
||||
{
|
||||
wires_.push_back(wire);
|
||||
}
|
||||
|
||||
void Module::add_behavior(PProcess*b)
|
||||
{
|
||||
behaviors_.push_back(b);
|
||||
}
|
||||
|
||||
PWire* Module::get_wire(const string&name)
|
||||
{
|
||||
for (list<PWire*>::iterator cur = wires_.begin()
|
||||
; cur != wires_.end()
|
||||
; cur ++ ) {
|
||||
|
||||
if ((*cur)->name == name)
|
||||
return *cur;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: Module.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:51 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef __Module_H
|
||||
#define __Module_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)
|
||||
#ident "$Id: Module.h,v 1.1 1998/11/03 23:28:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
# include <vector>
|
||||
# include <string>
|
||||
class PGate;
|
||||
class PWire;
|
||||
class PProcess;
|
||||
class Design;
|
||||
|
||||
/*
|
||||
* A module is a named container and scope. A module holds a bunch of
|
||||
* semantic quantities such as wires and gates. The module is
|
||||
* therefore the handle for grasping the described circuit.
|
||||
*/
|
||||
|
||||
class Module {
|
||||
public:
|
||||
explicit Module(const string&name, unsigned nports)
|
||||
: ports(nports), name_(name) { }
|
||||
|
||||
vector<PWire*> ports;
|
||||
|
||||
const string&get_name() const { return name_; }
|
||||
|
||||
void add_gate(PGate*gate);
|
||||
void add_wire(PWire*wire);
|
||||
void add_behavior(PProcess*behave);
|
||||
|
||||
// Find a wire by name. This is used for connecting gates to
|
||||
// existing wires, etc.
|
||||
PWire* get_wire(const string&name);
|
||||
|
||||
const list<PWire*>& get_wires() const { return wires_; }
|
||||
const list<PGate*>& get_gates() const { return gates_; }
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
|
||||
void elaborate(Design*, const string&path) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
|
||||
list<PWire*> wires_;
|
||||
list<PGate*> gates_;
|
||||
list<PProcess*> behaviors_;
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
Module& operator= (const Module&);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: Module.h,v $
|
||||
* Revision 1.1 1998/11/03 23:28:52 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: PExpr.cc,v 1.1 1998/11/03 23:28:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
|
||||
PExpr::~PExpr()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:53 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
#ifndef __PExpr_H
|
||||
#define __PExpr_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)
|
||||
#ident "$Id: PExpr.h,v 1.1 1998/11/03 23:28:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include "verinum.h"
|
||||
|
||||
class Design;
|
||||
class NetNet;
|
||||
class NetExpr;
|
||||
|
||||
/*
|
||||
* The PExpr class hierarchy supports the description of
|
||||
* expressions. The parser can generate expression objects from the
|
||||
* source, possibly reducing things that it knows how to reduce.
|
||||
*
|
||||
* The elaborate_net method is used by structural elaboration to build
|
||||
* up a netlist interpretation of the expression.
|
||||
*/
|
||||
|
||||
class PExpr {
|
||||
public:
|
||||
virtual ~PExpr();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
// This attempts to evaluate a constant expression, and return
|
||||
// a verinum as a result. If the expression cannot be
|
||||
// evaluated, return 0.
|
||||
virtual verinum* eval_const() const;
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&, const PExpr&);
|
||||
|
||||
class PEIdent : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEIdent(const string&s)
|
||||
: text_(s), msb_(0), lsb_(0) { }
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
|
||||
private:
|
||||
string text_;
|
||||
|
||||
public:
|
||||
// Use these to support bit- and part-select operators.
|
||||
PExpr*msb_;
|
||||
PExpr*lsb_;
|
||||
};
|
||||
|
||||
class PENumber : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PENumber(verinum*vp)
|
||||
: value_(vp) { assert(vp); }
|
||||
~PENumber() { delete value_; }
|
||||
|
||||
const verinum& value() const { return *value_; }
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
virtual verinum* eval_const() const;
|
||||
|
||||
private:
|
||||
verinum*const value_;
|
||||
};
|
||||
|
||||
class PEString : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEString(const string&s)
|
||||
: text_(s) { }
|
||||
|
||||
string value() const { return text_; }
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
const string text_;
|
||||
};
|
||||
|
||||
class PEUnary : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEUnary(char op, PExpr*ex)
|
||||
: op_(op), expr_(ex) { }
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
PExpr*expr_;
|
||||
};
|
||||
|
||||
class PEBinary : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PEBinary(char op, PExpr*l, PExpr*r)
|
||||
: op_(op), left_(l), right_(r) { }
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
PExpr*left_;
|
||||
PExpr*right_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.1 1998/11/03 23:28:54 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
#ifndef __PGate_H
|
||||
#define __PGate_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)
|
||||
#ident "$Id: PGate.h,v 1.1 1998/11/03 23:28:54 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <vector>
|
||||
class PExpr;
|
||||
class Design;
|
||||
|
||||
/*
|
||||
* A PGate represents a Verilog gate. The gate has a name and other
|
||||
* properties, and a set of pins that connect to wires. It is known at
|
||||
* the time a gate is constructed how many pins the gate has.
|
||||
*
|
||||
* This pins of a gate are connected to expressions. The elaboration
|
||||
* step will need to convert expressions to a network of gates in
|
||||
* order to elaborate expression inputs, but that can easily be done.
|
||||
*/
|
||||
class PGate {
|
||||
|
||||
public:
|
||||
explicit PGate(const string&name, const vector<PExpr*>&pins, long del)
|
||||
: name_(name), delay_(del), pins_(pins) { }
|
||||
|
||||
virtual ~PGate() { }
|
||||
|
||||
const string& get_name() const { return name_; }
|
||||
|
||||
long get_delay() const { return delay_; }
|
||||
|
||||
unsigned pin_count() const { return pins_.size(); }
|
||||
const PExpr*pin(unsigned idx) const { return pins_[idx]; }
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
|
||||
protected:
|
||||
void dump_pins(ostream&out) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
const unsigned long delay_;
|
||||
const vector<PExpr*> pins_;
|
||||
|
||||
private: // not implemented
|
||||
PGate(const PGate&);
|
||||
PGate& operator= (const PGate&);
|
||||
};
|
||||
|
||||
/* A continuous assignment has a single output and a single input. The
|
||||
input is passed directly to the output. This is different from a
|
||||
BUF because elaboration may need to turn this into a vector of
|
||||
gates. */
|
||||
class PGAssign : public PGate {
|
||||
|
||||
public:
|
||||
explicit PGAssign(const vector<PExpr*>&pins)
|
||||
: PGate("", pins, 0) { assert(pins.size() == 2); }
|
||||
|
||||
void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
/* The Builtin class is specifically a gate with one of the builtin
|
||||
types. The parser recognizes these types during parse. These types
|
||||
have special properties that allow them to be treated specially. */
|
||||
class PGBuiltin : public PGate {
|
||||
|
||||
public:
|
||||
enum Type { AND, NAND, OR, NOR, XOR, XNOR, BUF, BUFIF0, BUFIF1,
|
||||
NOT, NOTIF0, NOTIF1, PULLDOWN, PULLUP, NMOS, RNMOS,
|
||||
PMOS, RPMOS, CMOS, RCMOS, TRAN, RTRAN, TRANIF0,
|
||||
TRANIF1, RTRANIF0, RTRANIF1 };
|
||||
|
||||
public:
|
||||
explicit PGBuiltin(Type t, const string&name,
|
||||
const vector<PExpr*>&pins, long del = 0)
|
||||
: PGate(name, pins, del), type_(t)
|
||||
{ }
|
||||
|
||||
Type type() const { return type_; }
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*, const string&path) const;
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This kind of gate is an instantiation of a module. The stored type
|
||||
* is the name of a module definition somewhere in the pform.
|
||||
*/
|
||||
class PGModule : public PGate {
|
||||
|
||||
public:
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
const vector<PExpr*>&pins)
|
||||
: PGate(name, pins, 0), type_(type) { }
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
virtual void elaborate(Design*, const string&path) const;
|
||||
|
||||
private:
|
||||
string type_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PGate.h,v $
|
||||
* Revision 1.1 1998/11/03 23:28:54 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef __PWire_H
|
||||
#define __PWire_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)
|
||||
#ident "$Id: PWire.h,v 1.1 1998/11/03 23:28:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
class ostream;
|
||||
class PExpr;
|
||||
class Design;
|
||||
|
||||
/*
|
||||
* Wires include nets, registers and ports. A net or register becomes
|
||||
* a port by declaration, so ports are not seperate. The module
|
||||
* identifies a port by keeping it in its port list.
|
||||
*/
|
||||
class PWire {
|
||||
|
||||
public:
|
||||
PWire(const string&n, NetNet::Type t =NetNet::IMPLICIT)
|
||||
: name(n), type(t), port_type(NetNet::NOT_A_PORT), msb(0), lsb(0)
|
||||
{ }
|
||||
|
||||
string name;
|
||||
NetNet::Type type;
|
||||
NetNet::PortType port_type;
|
||||
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
|
||||
// Write myself to the specified stream.
|
||||
void dump(ostream&out) const;
|
||||
|
||||
void elaborate(Design*, const string&path) const;
|
||||
|
||||
private: // not implemented
|
||||
PWire(const PWire&);
|
||||
PWire& operator= (const PWire&);
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PWire.h,v $
|
||||
* Revision 1.1 1998/11/03 23:28:55 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: Statement.cc,v 1.1 1998/11/03 23:28:55 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Statement.h"
|
||||
# include "PExpr.h"
|
||||
|
||||
Statement::~Statement()
|
||||
{
|
||||
}
|
||||
|
||||
PBlock::PBlock(BL_TYPE t, const list<Statement*>&st)
|
||||
: bl_type_(t)
|
||||
{
|
||||
nlist_ = st.size();
|
||||
list_ = new Statement*[nlist_];
|
||||
|
||||
list<Statement*>::const_iterator s = st.begin();
|
||||
for (unsigned idx = 0 ; s != st.end() ; s ++, idx += 1 ) {
|
||||
list_[idx] = *s;
|
||||
}
|
||||
}
|
||||
|
||||
PBlock::~PBlock()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nlist_ ; idx += 1)
|
||||
delete list_[idx];
|
||||
|
||||
delete[]list_;
|
||||
}
|
||||
|
||||
PCallTask::PCallTask(const string&n, const list<PExpr*>&p)
|
||||
: name_(n), nparms_(p.size()), parms_(nparms_?new PExpr*[nparms_]:0)
|
||||
{
|
||||
list<PExpr*>::const_iterator s = p.begin();
|
||||
for (unsigned idx = 0 ; s != p.end() ; s++, idx += 1) {
|
||||
parms_[idx] = *s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: Statement.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:55 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
#ifndef __Statement_H
|
||||
#define __Statement_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)
|
||||
#ident "$Id: Statement.h,v 1.1 1998/11/03 23:28:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include <list>
|
||||
# include "netlist.h"
|
||||
class PExpr;
|
||||
class Statement;
|
||||
|
||||
/*
|
||||
* The PProcess is the root of a behavioral process. Each process gets
|
||||
* one of these, which contains its type (initial or always) and a
|
||||
* pointer to the single statement that is the process. A module may
|
||||
* have several concurrent processes.
|
||||
*/
|
||||
class PProcess {
|
||||
|
||||
public:
|
||||
enum Type { PR_INITIAL, PR_ALWAYS };
|
||||
|
||||
PProcess(Type t, Statement*st)
|
||||
: type_(t), statement_(st) { }
|
||||
|
||||
Type type() const { return type_; }
|
||||
Statement*statement() { return statement_; }
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The PProcess is a process, the Statement is the actual action. In
|
||||
* fact, the Statement class is abstract and represents all the
|
||||
* possible kinds of statements that exist in Verilog.
|
||||
*/
|
||||
class Statement {
|
||||
|
||||
public:
|
||||
Statement() { }
|
||||
virtual ~Statement() =0;
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Assignment statements of the various forms are handled by this
|
||||
* type. The rvalue is an expression. The lvalue needs to be figured
|
||||
* out by the parser as much as possible.
|
||||
*/
|
||||
class PAssign : public Statement {
|
||||
|
||||
public:
|
||||
explicit PAssign(const string&name, PExpr*ex)
|
||||
: to_name_(name), expr_(ex) { }
|
||||
|
||||
string lval() const { return to_name_; }
|
||||
const PExpr* get_expr() const { return expr_; }
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
const string to_name_;
|
||||
PExpr*const expr_;
|
||||
};
|
||||
|
||||
/*
|
||||
* A block statement is an ordered list of statements that make up the
|
||||
* block. The block can be sequential or parallel, which only affects
|
||||
* how the block is interpreted. The parser collects the list of
|
||||
* statements before constructing this object, so it knows a priori
|
||||
* what is contained.
|
||||
*/
|
||||
class PBlock : public Statement {
|
||||
|
||||
public:
|
||||
enum BL_TYPE { BL_SEQ, BL_PAR };
|
||||
|
||||
explicit PBlock(BL_TYPE t, const list<Statement*>&st);
|
||||
~PBlock();
|
||||
|
||||
BL_TYPE bl_type() const { return bl_type_; }
|
||||
|
||||
unsigned size() const { return nlist_; }
|
||||
const Statement*stat(unsigned idx) const { return list_[idx]; }
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
const BL_TYPE bl_type_;
|
||||
unsigned nlist_;
|
||||
Statement**list_;
|
||||
};
|
||||
|
||||
class PCallTask : public Statement {
|
||||
|
||||
public:
|
||||
explicit PCallTask(const string&n, const list<PExpr*>&parms);
|
||||
|
||||
string name() const { return name_; }
|
||||
|
||||
unsigned nparms() const { return nparms_; }
|
||||
|
||||
PExpr*&parm(unsigned idx)
|
||||
{ assert(idx < nparms_);
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
PExpr* parm(unsigned idx) const
|
||||
{ assert(idx < nparms_);
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
const unsigned nparms_;
|
||||
PExpr**const parms_;
|
||||
};
|
||||
|
||||
class PDelayStatement : public Statement {
|
||||
|
||||
public:
|
||||
PDelayStatement(PExpr*d, Statement*st)
|
||||
: delay_(d), statement_(st) { }
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
PExpr*delay_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
class PEventStatement : public Statement {
|
||||
|
||||
public:
|
||||
|
||||
PEventStatement(NetPEvent::Type t, PExpr*ee)
|
||||
: type_(t), expr_(ee), statement_(0) { }
|
||||
|
||||
void set_statement(Statement*st) { statement_ = st; }
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
NetPEvent::Type type_;
|
||||
PExpr*expr_;
|
||||
Statement*statement_;
|
||||
};
|
||||
|
||||
class PNoop : public Statement {
|
||||
|
||||
public:
|
||||
PNoop() { }
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.1 1998/11/03 23:28:56 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: design_dump.cc,v 1.1 1998/11/03 23:28:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains all the dump methods of the netlist classes.
|
||||
*/
|
||||
# include <typeinfo>
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include "netlist.h"
|
||||
|
||||
static ostream& operator<< (ostream&o, NetNet::Type t)
|
||||
{
|
||||
switch (t) {
|
||||
case NetNet::IMPLICIT:
|
||||
o << "implicit wire";
|
||||
break;
|
||||
case NetNet::WIRE:
|
||||
o << "wire";
|
||||
break;
|
||||
case NetNet::REG:
|
||||
o << "reg";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static ostream& operator<< (ostream&o, NetBlock::Type t)
|
||||
{
|
||||
switch (t) {
|
||||
case NetBlock::SEQU:
|
||||
o << "begin";
|
||||
break;
|
||||
case NetBlock::PARA:
|
||||
o << "fork";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/* Dump a net. This can be a wire or register. */
|
||||
void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type() << ": " << name() << "[" <<
|
||||
pin_count() << "]";
|
||||
if (local_flag_)
|
||||
o << " (local)";
|
||||
o << " #(" << delay1() << "," << delay2() << "," << delay3() <<
|
||||
")" << endl;
|
||||
}
|
||||
|
||||
|
||||
/* Dump a NetNode and its pins. Dump what I know about the netnode on
|
||||
the first line, then list all the pins, with the name of the
|
||||
connected signal. */
|
||||
void NetNode::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "node: ";
|
||||
o << typeid(*this).name() << " #(" << delay1()
|
||||
<< "," << delay2() << "," << delay3() << ") " << name()
|
||||
<< endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
/* This is the generic dumping of all the signals connected to each
|
||||
pin of the object. The "this" object is not printed, only the
|
||||
signals connected to this. */
|
||||
void NetObj::dump_node_pins(ostream&o, unsigned ind) const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
o << setw(ind) << "" << idx << ":";
|
||||
|
||||
unsigned cpin;
|
||||
const NetObj*cur;
|
||||
for (pin(idx).next_link(cur, cpin)
|
||||
; (cur != this) || (cpin != idx)
|
||||
; cur->pin(cpin).next_link(cur, cpin)) {
|
||||
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(cur);
|
||||
if (sig) o << " " << sig->name() << "[" << cpin << "]";
|
||||
}
|
||||
o << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void NetAssign::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Procedural assign: " << *rval_ << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetBUFZ::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "BUFZ: " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetLogic::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "logic: ";
|
||||
switch (type_) {
|
||||
case AND:
|
||||
o << "and";
|
||||
break;
|
||||
case NAND:
|
||||
o << "nand";
|
||||
break;
|
||||
case NOR:
|
||||
o << "nor";
|
||||
break;
|
||||
case NOT:
|
||||
o << "not";
|
||||
break;
|
||||
case OR:
|
||||
o << "or";
|
||||
break;
|
||||
case XOR:
|
||||
o << "xor";
|
||||
break;
|
||||
}
|
||||
o << " #(" << delay1()
|
||||
<< "," << delay2() << "," << delay3() << ") " << name()
|
||||
<< endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetPEvent::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "event: ";
|
||||
switch (edge_) {
|
||||
case ANYEDGE:
|
||||
break;
|
||||
case POSEDGE:
|
||||
o << "posedge ";
|
||||
break;
|
||||
case NEGEDGE:
|
||||
o << "negedge ";
|
||||
break;
|
||||
}
|
||||
|
||||
o << name() << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetProcTop::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
switch (type_) {
|
||||
case NetProcTop::KINITIAL:
|
||||
o << "initial" << endl;
|
||||
break;
|
||||
case NetProcTop::KALWAYS:
|
||||
o << "always" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
/* Dump an assignment statement */
|
||||
void NetAssign::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << lval_->name() << " = ";
|
||||
rval_->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
/* Dump a block statement */
|
||||
void NetBlock::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type_ << endl;
|
||||
|
||||
if (last_) {
|
||||
const NetProc*cur = last_;
|
||||
do {
|
||||
cur = cur->next_;
|
||||
cur->dump(o, ind+4);
|
||||
} while (cur != last_);
|
||||
}
|
||||
|
||||
o << setw(ind) << "" << "end" << endl;
|
||||
}
|
||||
|
||||
void NetPDelay::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "#" << delay_ << endl;
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetPEvent::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "@";
|
||||
switch (edge_) {
|
||||
case NEGEDGE:
|
||||
o << "(negedge " << name() << ")";
|
||||
break;
|
||||
case POSEDGE:
|
||||
o << "(posedge " << name() << ")";
|
||||
break;
|
||||
case ANYEDGE:
|
||||
o << name();
|
||||
break;
|
||||
}
|
||||
o << endl;
|
||||
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NetTask::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << name_;
|
||||
|
||||
if (nparms_ > 0) {
|
||||
o << "(";
|
||||
if (parms_[0])
|
||||
parms_[0]->dump(o);
|
||||
|
||||
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
|
||||
o << ", ";
|
||||
if (parms_[idx])
|
||||
parms_[idx]->dump(o);
|
||||
}
|
||||
|
||||
o << ")";
|
||||
}
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
/* Dump a statement type that someone didn't write a dump for. */
|
||||
void NetProc::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "// " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
/* Dump an expression that noone wrote a dump method for. */
|
||||
void NetExpr::dump(ostream&o) const
|
||||
{
|
||||
o << "(?)";
|
||||
}
|
||||
|
||||
void NetEConst::dump(ostream&o) const
|
||||
{
|
||||
if (value_.is_string())
|
||||
o << "\"" << value_.as_string() << "\"";
|
||||
else
|
||||
o << value_;
|
||||
}
|
||||
|
||||
void NetEIdent::dump(ostream&o) const
|
||||
{
|
||||
o << name_;
|
||||
}
|
||||
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
o << op_ << "(";
|
||||
expr_->dump(o);
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void Design::dump(ostream&o) const
|
||||
{
|
||||
|
||||
o << "ELABORATED SIGNALS:" << endl;
|
||||
|
||||
// Dump the signals,
|
||||
{
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
cur->dump_net(o, 0);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
o << "ELABORATED NODES:" << endl;
|
||||
|
||||
// dump the nodes,
|
||||
{
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
cur->dump_node(o, 0);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
|
||||
o << "ELABORATED PROCESSES:" << endl;
|
||||
|
||||
// Dump the processes.
|
||||
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
|
||||
idx->dump(o, 0);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: design_dump.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:56 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: elaborate.cc,v 1.1 1998/11/03 23:28:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Elaboration takes as input a complete parse tree and the name of a
|
||||
* root module, and generates as output the elaborated design. This
|
||||
* elaborated design is presented as a Module, which does not
|
||||
* reference any other modules. It is entirely self contained.
|
||||
*/
|
||||
|
||||
# include <typeinfo>
|
||||
# include <strstream>
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
|
||||
static string local_symbol(const string&path)
|
||||
{
|
||||
static unsigned counter = 0;
|
||||
string result = "_L";
|
||||
|
||||
strstream res;
|
||||
res << "_L" << (counter++) << ends;
|
||||
return path + "." + res.str();
|
||||
}
|
||||
|
||||
static void do_assign(Design*des, const string&path,
|
||||
NetNet*lval, NetNet*rval)
|
||||
{
|
||||
assert(lval->pin_count() == rval->pin_count());
|
||||
const unsigned pin_count = lval->pin_count();
|
||||
|
||||
if (NetTmp* tmp = dynamic_cast<NetTmp*>(rval)) {
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
||||
connect(lval->pin(idx), tmp->pin(idx));
|
||||
delete tmp;
|
||||
|
||||
if (tmp = dynamic_cast<NetTmp*>(lval))
|
||||
delete tmp;
|
||||
|
||||
} else if (NetTmp* tmp = dynamic_cast<NetTmp*>(lval)) {
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
||||
connect(tmp->pin(idx), rval->pin(idx));
|
||||
delete tmp;
|
||||
|
||||
} else if (rval->local_flag()) {
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
||||
connect(lval->pin(idx), rval->pin(idx));
|
||||
delete rval;
|
||||
|
||||
} else if (lval->local_flag()) {
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
||||
connect(lval->pin(idx), rval->pin(idx));
|
||||
delete lval;
|
||||
|
||||
} else for (unsigned idx = 0 ; idx < pin_count ; idx += 1) {
|
||||
NetBUFZ*cur = new NetBUFZ(local_symbol(path));
|
||||
|
||||
connect(cur->pin(0), lval->pin(idx));
|
||||
connect(cur->pin(1), rval->pin(idx));
|
||||
|
||||
des->add_node(cur);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Urff, I don't like this global variable. I *will* figure out a
|
||||
// way to get rid of it. But, for now the PGModule::elaborate method
|
||||
// needs it to find the module definition.
|
||||
static const list<Module*>* modlist = 0;
|
||||
|
||||
/* Elaborate a source wire. Generally pretty easy. */
|
||||
void PWire::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetNet::Type wtype = type;
|
||||
if (wtype == NetNet::IMPLICIT)
|
||||
wtype = NetNet::WIRE;
|
||||
|
||||
unsigned wid = 1;
|
||||
|
||||
if (msb && lsb) {
|
||||
verinum*mval = msb->eval_const();
|
||||
assert(mval);
|
||||
verinum*lval = lsb->eval_const();
|
||||
assert(lval);
|
||||
|
||||
long mnum = mval->as_long();
|
||||
long lnum = lval->as_long();
|
||||
delete mval;
|
||||
delete lval;
|
||||
|
||||
if (mnum > lnum)
|
||||
wid = mnum - lnum + 1;
|
||||
else
|
||||
wid = lnum - mnum + 1;
|
||||
|
||||
} else if (msb) {
|
||||
verinum*val = msb->eval_const();
|
||||
assert(val);
|
||||
assert(val->as_ulong() > 0);
|
||||
wid = val->as_ulong();
|
||||
}
|
||||
|
||||
NetNet*sig = new NetNet(path + "." + name, wtype, wid);
|
||||
sig->port_type(port_type);
|
||||
des->add_signal(sig);
|
||||
}
|
||||
|
||||
void PGate::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
cerr << "what kind of gate? " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
/* Elaborate the continuous assign. (This is *not* the procedural
|
||||
assign.) Elaborate the lvalue and rvalue, and do the assignment. */
|
||||
void PGAssign::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*lval = pin(0)->elaborate_net(des, path);
|
||||
NetNet*rval = pin(1)->elaborate_net(des, path);
|
||||
assert(lval && rval);
|
||||
|
||||
do_assign(des, path, lval, rval);
|
||||
}
|
||||
|
||||
/* Elaborate a Builtin gate. These normally get translated into
|
||||
NetLogic nodes that reflect the particular logic function. */
|
||||
void PGBuiltin::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetLogic*cur = 0;
|
||||
|
||||
switch (type()) {
|
||||
case AND:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::AND);
|
||||
break;
|
||||
case NAND:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::NAND);
|
||||
break;
|
||||
case NOR:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::NOR);
|
||||
break;
|
||||
case NOT:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::NOT);
|
||||
break;
|
||||
case OR:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::OR);
|
||||
break;
|
||||
case XOR:
|
||||
cur = new NetLogic(get_name(), pin_count(), NetLogic::XOR);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(cur);
|
||||
cur->delay1(get_delay());
|
||||
cur->delay2(get_delay());
|
||||
cur->delay3(get_delay());
|
||||
des->add_node(cur);
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
const PExpr*ex = pin(idx);
|
||||
NetNet*sig = ex->elaborate_net(des, path);
|
||||
assert(sig);
|
||||
connect(cur->pin(idx), sig->pin(0));
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a module by recursively elaborating it. Set the path of
|
||||
* the recursive elaboration so that signal names get properly
|
||||
* set. Connect the ports of the instantiated module to the signals of
|
||||
* the parameters. This is done with BUFZ gates so that they look just
|
||||
* like continuous assignment connections.
|
||||
*/
|
||||
void PGModule::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
// Look for the module type
|
||||
Module*rmod = 0;
|
||||
for (list<Module*>::const_iterator mod = modlist->begin()
|
||||
; mod != modlist->end()
|
||||
; mod ++ ) {
|
||||
|
||||
if ((*mod)->get_name() == type_) {
|
||||
rmod = *mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rmod == 0) {
|
||||
cerr << "Unknown module: " << type_ << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Elaborate this instance of the module. The recursive
|
||||
// elaboration causes the module to generate a netlist with
|
||||
// the ports represented by NetNet objects. I will find them
|
||||
// later.
|
||||
rmod->elaborate(des, path + "." + get_name());
|
||||
|
||||
// Now connect the ports of the newly elaborated designs to
|
||||
// the expressions that are the instantiation parameters.
|
||||
|
||||
assert(pin_count() == rmod->ports.size());
|
||||
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
NetNet*sig = pin(idx)->elaborate_net(des, path);
|
||||
if (sig == 0) {
|
||||
cerr << "Expression too complicated for elaboration." << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
NetNet*prt = des->find_signal(path + "." + get_name() + "." +
|
||||
rmod->ports[idx]->name);
|
||||
assert(prt);
|
||||
|
||||
assert(prt->pin_count() == sig->pin_count());
|
||||
switch (prt->port_type()) {
|
||||
case NetNet::PINPUT:
|
||||
do_assign(des, path, prt, sig);
|
||||
break;
|
||||
case NetNet::POUTPUT:
|
||||
do_assign(des, path, sig, prt);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path) const
|
||||
{
|
||||
cerr << "Don't know how to elaborate `" << *this << "' as gates." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborating binary operations generally involves elaborating the
|
||||
* left and right expressions, then making an output wire and
|
||||
* connecting the lot together with the right kind of gate.
|
||||
*/
|
||||
NetNet* PEBinary::elaborate_net(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*lsig = left_->elaborate_net(des, path),
|
||||
*rsig = right_->elaborate_net(des, path);
|
||||
if (lsig == 0) {
|
||||
cerr << "Cannot elaborate ";
|
||||
left_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
if (rsig == 0) {
|
||||
cerr << "Cannot elaborate ";
|
||||
right_->dump(cerr);
|
||||
cerr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*osig;
|
||||
NetLogic*gate;
|
||||
|
||||
switch (op_) {
|
||||
case '^': // XOR
|
||||
assert(lsig->pin_count() == 1);
|
||||
assert(rsig->pin_count() == 1);
|
||||
gate = new NetLogic(local_symbol(path), 3, NetLogic::XOR);
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
osig = new NetNet(local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
des->add_signal(osig);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case '&': // AND
|
||||
assert(lsig->pin_count() == 1);
|
||||
assert(rsig->pin_count() == 1);
|
||||
gate = new NetLogic(local_symbol(path), 3, NetLogic::AND);
|
||||
connect(gate->pin(1), lsig->pin(0));
|
||||
connect(gate->pin(2), rsig->pin(0));
|
||||
osig = new NetNet(local_symbol(path), NetNet::WIRE);
|
||||
osig->local_flag(true);
|
||||
connect(gate->pin(0), osig->pin(0));
|
||||
des->add_signal(osig);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << "Unhandled BINARY '" << op_ << "'" << endl;
|
||||
osig = 0;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
||||
delete tmp;
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
||||
delete tmp;
|
||||
|
||||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_net(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*sig = des->find_signal(path+"."+text_);
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
verinum*mval = msb_->eval_const();
|
||||
assert(mval);
|
||||
verinum*lval = lsb_->eval_const();
|
||||
assert(lval);
|
||||
unsigned midx = sig->sb_to_idx(mval->as_long());
|
||||
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
||||
|
||||
if (midx >= lidx) {
|
||||
NetTmp*tmp = new NetTmp(midx-lidx+1);
|
||||
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
||||
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
|
||||
} else {
|
||||
NetTmp*tmp = new NetTmp(lidx-midx+1);
|
||||
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
||||
connect(tmp->pin(idx-midx), sig->pin(idx));
|
||||
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
} else if (msb_) {
|
||||
verinum*mval = msb_->eval_const();
|
||||
assert(mval);
|
||||
unsigned idx = sig->sb_to_idx(mval->as_long());
|
||||
NetTmp*tmp = new NetTmp(1);
|
||||
connect(tmp->pin(0), sig->pin(idx));
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
NetNet* PEUnary::elaborate_net(Design*des, const string&path) const
|
||||
{
|
||||
NetNet* sub_sig = expr_->elaborate_net(des, path);
|
||||
assert(sub_sig);
|
||||
|
||||
NetNet* sig;
|
||||
NetLogic*gate;
|
||||
switch (op_) {
|
||||
case '~': // Bitwise NOT
|
||||
assert(sub_sig->pin_count() == 1);
|
||||
sig = new NetNet(local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(local_symbol(path), 2, NetLogic::NOT);
|
||||
connect(gate->pin(0), sig->pin(0));
|
||||
connect(gate->pin(1), sub_sig->pin(0));
|
||||
des->add_signal(sig);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
case '&': // Reduction AND
|
||||
sig = new NetNet(local_symbol(path), NetNet::WIRE);
|
||||
sig->local_flag(true);
|
||||
gate = new NetLogic(local_symbol(path),
|
||||
1+sub_sig->pin_count(),
|
||||
NetLogic::AND);
|
||||
connect(gate->pin(0), sig->pin(0));
|
||||
for (unsigned idx = 0 ; idx < sub_sig->pin_count() ; idx += 1)
|
||||
connect(gate->pin(idx+1), sub_sig->pin(idx));
|
||||
|
||||
des->add_signal(sig);
|
||||
des->add_node(gate);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << "Unhandled UNARY '" << op_ << "'" << endl;
|
||||
sig = 0;
|
||||
}
|
||||
|
||||
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sub_sig))
|
||||
delete tmp;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
NetExpr* PENumber::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
assert(value_);
|
||||
return new NetEConst(*value_);
|
||||
}
|
||||
|
||||
NetExpr* PEString::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
return new NetEConst(value());
|
||||
}
|
||||
|
||||
NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
if (text_[0] == '$')
|
||||
return new NetEIdent(text_);
|
||||
else
|
||||
return new NetEIdent(path+"."+text_);
|
||||
}
|
||||
|
||||
NetExpr* PExpr::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
cerr << "Cannot elaborate expression: " << *this << endl;
|
||||
return new NetEConst(verinum());
|
||||
}
|
||||
|
||||
NetExpr* PEUnary::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
return new NetEUnary(op_, expr_->elaborate_expr(des, path));
|
||||
}
|
||||
|
||||
NetProc* Statement::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
cerr << "What kind of statement? " << typeid(*this).name() << endl;
|
||||
NetProc*cur = new NetProc;
|
||||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PAssign::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetNet*reg = des->find_signal(path+"."+lval());
|
||||
if (reg == 0) {
|
||||
cerr << "Could not match signal: " << lval() << endl;
|
||||
return new NetProc;
|
||||
}
|
||||
assert(reg);
|
||||
assert(reg->type() == NetNet::REG);
|
||||
assert(expr_);
|
||||
|
||||
NetExpr*rval = expr_->elaborate_expr(des, path);
|
||||
assert(rval);
|
||||
|
||||
NetAssign*cur = new NetAssign(reg, rval);
|
||||
des->add_node(cur);
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PBlock::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetBlock*cur = new NetBlock(NetBlock::SEQU);
|
||||
for (unsigned idx = 0 ; idx < size() ; idx += 1) {
|
||||
cur->append(stat(idx)->elaborate(des, path));
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetTask*cur = new NetTask(name(), nparms());
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
cur->parm(idx, ex? ex->elaborate_expr(des, path) : 0);
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PDelayStatement::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
verinum*num = delay_->eval_const();
|
||||
assert(num);
|
||||
|
||||
unsigned long val = num->as_ulong();
|
||||
return new NetPDelay(val, statement_->elaborate(des, path));
|
||||
}
|
||||
|
||||
/*
|
||||
* An event statement gets elaborated as a gate net that drives a
|
||||
* special node, the NetPEvent. The NetPEvent is also a NetProc class
|
||||
* becuase execution flows through it. Thus, the NetPEvent connects
|
||||
* the structural and the behavioral.
|
||||
*/
|
||||
NetProc* PEventStatement::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
NetProc*enet = statement_->elaborate(des, path);
|
||||
NetPEvent*ev = new NetPEvent(local_symbol(path), type_, enet);
|
||||
|
||||
NetNet*expr = expr_->elaborate_net(des, path);
|
||||
if (expr == 0) {
|
||||
cerr << "Failed to elaborate expression: ";
|
||||
expr_->dump(cerr);
|
||||
cerr << endl;
|
||||
exit(1);
|
||||
}
|
||||
assert(expr);
|
||||
connect(ev->pin(0), expr->pin(0));
|
||||
|
||||
des->add_node(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
void Module::elaborate(Design*des, const string&path) const
|
||||
{
|
||||
// Get all the explicitly declared wires of the module and
|
||||
// start the signals list with them.
|
||||
const list<PWire*>&wl = get_wires();
|
||||
|
||||
for (list<PWire*>::const_iterator wt = wl.begin()
|
||||
; wt != wl.end()
|
||||
; wt ++ ) {
|
||||
|
||||
(*wt)->elaborate(des, path);
|
||||
}
|
||||
|
||||
// Get all the gates of the module and elaborate them by
|
||||
// connecting them to the signals. The gate may be simple or
|
||||
// complex.
|
||||
const list<PGate*>&gl = get_gates();
|
||||
|
||||
for (list<PGate*>::const_iterator gt = gl.begin()
|
||||
; gt != gl.end()
|
||||
; gt ++ ) {
|
||||
|
||||
(*gt)->elaborate(des, path);
|
||||
}
|
||||
|
||||
// Elaborate the behaviors, making processes out of them.
|
||||
const list<PProcess*>&sl = get_behaviors();
|
||||
|
||||
for (list<PProcess*>::const_iterator st = sl.begin()
|
||||
; st != sl.end()
|
||||
; st ++ ) {
|
||||
|
||||
NetProc*cur = (*st)->statement()->elaborate(des, path);
|
||||
NetProcTop*top;
|
||||
switch ((*st)->type()) {
|
||||
case PProcess::PR_INITIAL:
|
||||
top = new NetProcTop(NetProcTop::KINITIAL, cur);
|
||||
break;
|
||||
case PProcess::PR_ALWAYS:
|
||||
top = new NetProcTop(NetProcTop::KALWAYS, cur);
|
||||
break;
|
||||
}
|
||||
|
||||
des->add_process(top);
|
||||
}
|
||||
}
|
||||
|
||||
Design* elaborate(const list<Module*>&modules, const string&root)
|
||||
{
|
||||
// Look for the root module in the list.
|
||||
Module*rmod = 0;
|
||||
for (list<Module*>::const_iterator mod = modules.begin()
|
||||
; mod != modules.end()
|
||||
; mod ++ ) {
|
||||
|
||||
if ((*mod)->get_name() == root) {
|
||||
rmod = *mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rmod == 0)
|
||||
return 0;
|
||||
|
||||
// This is the output design. I fill it in as I scan the root
|
||||
// module and elaborate what I find.
|
||||
Design*des = new Design;
|
||||
|
||||
modlist = &modules;
|
||||
rmod->elaborate(des, root);
|
||||
modlist = 0;
|
||||
|
||||
return des;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: elaborate.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:56 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: emit.cc,v 1.1 1998/11/03 23:28:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The emit function is called to generate the output required of the
|
||||
* target.
|
||||
*/
|
||||
# include "target.h"
|
||||
# include "netlist.h"
|
||||
# include <iostream>
|
||||
# include <typeinfo>
|
||||
# include <cassert>
|
||||
|
||||
void NetNode::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
cerr << "EMIT: Gate type? " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void NetLogic::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->logic(o, this);
|
||||
}
|
||||
|
||||
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_assign(o, this);
|
||||
}
|
||||
|
||||
void NetPEvent::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_pevent(o, this);
|
||||
}
|
||||
|
||||
void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->bufz(o, this);
|
||||
}
|
||||
|
||||
void NetProcTop::emit(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->start_process(o, this);
|
||||
|
||||
statement_->emit_proc(o, tgt);
|
||||
|
||||
tgt->end_process(o, this);
|
||||
}
|
||||
|
||||
void NetProc::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
|
||||
}
|
||||
|
||||
void NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign(o, this);
|
||||
}
|
||||
|
||||
void NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_block(o, this);
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_delay(o, this);
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_event(o, this);
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_task(o, this);
|
||||
}
|
||||
|
||||
void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
if (last_ == 0)
|
||||
return;
|
||||
|
||||
NetProc*cur = last_;
|
||||
do {
|
||||
cur = cur->next_;
|
||||
cur->emit_proc(o, tgt);
|
||||
} while (cur != last_);
|
||||
}
|
||||
|
||||
void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->start_design(o, this);
|
||||
|
||||
// emit signals
|
||||
{
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
tgt->signal(o, cur);
|
||||
cur = cur->sig_next_;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
|
||||
// emit nodes
|
||||
{
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
cur->emit_node(o, tgt);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
|
||||
|
||||
// emit the processes
|
||||
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
|
||||
idx->emit(o, tgt);
|
||||
|
||||
tgt->end_design(o, this);
|
||||
}
|
||||
|
||||
void NetEConst::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_const(this);
|
||||
}
|
||||
|
||||
void NetEIdent::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_ident(this);
|
||||
}
|
||||
|
||||
void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_unary(this);
|
||||
}
|
||||
|
||||
void emit(ostream&o, const Design*des, const char*type)
|
||||
{
|
||||
for (unsigned idx = 0 ; target_table[idx] ; idx += 1) {
|
||||
const struct target*tgt = target_table[idx];
|
||||
if (tgt->name == type) {
|
||||
des->emit(o, tgt->meth);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:57 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: eval.cc,v 1.1 1998/11/03 23:28:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
|
||||
verinum* PExpr::eval_const() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
verinum* PENumber::eval_const() const
|
||||
{
|
||||
return new verinum(value());
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: eval.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:58 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,426 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* 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)
|
||||
#ident "$Id: lexor.lex,v 1.1 1998/11/03 23:28:59 steve Exp $"
|
||||
#endif
|
||||
|
||||
//# define YYSTYPE lexval
|
||||
|
||||
# include <iostream.h>
|
||||
# include "parse_misc.h"
|
||||
# include "parse.h"
|
||||
# include <ctype.h>
|
||||
|
||||
extern FILE*vl_input;
|
||||
extern const char*vl_file;
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
# define yylval VLlval
|
||||
extern YYLTYPE yylloc;
|
||||
|
||||
static void reset_lexor();
|
||||
static int check_identifier(const char*name);
|
||||
static verinum*make_sized_binary(const char*txt);
|
||||
static verinum*make_sized_octal(const char*txt);
|
||||
static verinum*make_sized_hex(const char*txt);
|
||||
|
||||
%}
|
||||
|
||||
%option noyywrap
|
||||
|
||||
%x CCOMMENT
|
||||
%x CSTRING
|
||||
|
||||
%%
|
||||
|
||||
[ \t\b\f\r] { ; }
|
||||
\n { yylloc.first_line += 1; }
|
||||
|
||||
"//".* { ; }
|
||||
|
||||
"/*" { BEGIN(CCOMMENT); }
|
||||
<CCOMMENT>. { yymore(); }
|
||||
<CCOMMENT>\n { yylloc.first_line += 1; yymore(); }
|
||||
<CCOMMENT>"*/" { BEGIN(0); }
|
||||
|
||||
"<=" { return K_LE; }
|
||||
">=" { return K_GE; }
|
||||
|
||||
[;:\[\],()#=.@&!<|^~+-] { return yytext[0]; }
|
||||
|
||||
\" { BEGIN(CSTRING); }
|
||||
<CSTRING>\\\" { yymore(); }
|
||||
<CSTRING>\n { BEGIN(0);
|
||||
yylval.text = new string(yytext, strlen(yytext));
|
||||
VLerror(yylloc, "Missing close quote of string.");
|
||||
return STRING; }
|
||||
<CSTRING>\" { BEGIN(0);
|
||||
yylval.text = new string(yytext, strlen(yytext)-1);
|
||||
return STRING; }
|
||||
<CSTRING>. { yymore(); }
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
int rc = check_identifier(yytext);
|
||||
if (rc == IDENTIFIER)
|
||||
yylval.text = new string(yytext);
|
||||
else
|
||||
yylval.text = 0;
|
||||
|
||||
return rc; }
|
||||
|
||||
\\[^ \t\b\f\r]+ {
|
||||
yylval.text = new string(yytext);
|
||||
return IDENTIFIER; }
|
||||
|
||||
\$([a-zA-Z0-9$_]+) {
|
||||
yylval.text = new string(yytext);
|
||||
return SYSTEM_IDENTIFIER; }
|
||||
|
||||
([0-9][0-9_])?\'d[0-9][0-9_]* { yylval.number = 0;
|
||||
return NUMBER; }
|
||||
([0-9][0-9_])?\'[bB][0-1xz_]+ { yylval.number = make_sized_binary(yytext);
|
||||
return NUMBER; }
|
||||
([0-9][0-9_])?\'[oO][0-7xz_]+ { yylval.number = make_sized_octal(yytext);
|
||||
return NUMBER; }
|
||||
([0-9][0-9_])?\'[hH][0-9a-fA-Fxz_]+ { yylval.number = make_sized_hex(yytext);
|
||||
return NUMBER; }
|
||||
|
||||
[0-9][0-9_]* {
|
||||
/* Handle the special case of the unsized decimal number. */
|
||||
unsigned long value = 0;
|
||||
for (const char*cp = yytext ; *cp ; cp += 1) {
|
||||
if (*cp != '_')
|
||||
value = 10 * value + (*cp - '0');
|
||||
}
|
||||
|
||||
unsigned nbits = 8 * sizeof value;
|
||||
verinum::V*bits = new verinum::V[8 * sizeof value];
|
||||
|
||||
for (unsigned idx = 0 ; idx < nbits ; idx += 1, value >>= 1) {
|
||||
bits[idx] = (value&1) ? verinum::V1 : verinum::V0;
|
||||
}
|
||||
|
||||
yylval.number = new verinum(bits, nbits);
|
||||
delete[]bits;
|
||||
return NUMBER; }
|
||||
|
||||
. { cerr << yylloc.first_line << ": unmatched character (";
|
||||
if (isgraph(yytext[0]))
|
||||
cerr << yytext[0];
|
||||
else
|
||||
cerr << (unsigned)yytext[0];
|
||||
|
||||
cerr << ")" << endl; }
|
||||
|
||||
%%
|
||||
|
||||
static const struct { const char*name; int code; } key_table[] = {
|
||||
{ "always", K_always },
|
||||
{ "and", K_and },
|
||||
{ "assign", K_assign },
|
||||
{ "begin", K_begin },
|
||||
{ "buf", K_buf },
|
||||
{ "bufif0", K_bufif0 },
|
||||
{ "bufif1", K_bufif1 },
|
||||
{ "case", K_case },
|
||||
{ "casex", K_casex },
|
||||
{ "casez", K_casez },
|
||||
{ "cmos", K_cmos },
|
||||
{ "deassign", K_deassign },
|
||||
{ "default", K_default },
|
||||
{ "defparam", K_defparam },
|
||||
{ "disable", K_disable },
|
||||
{ "edge", K_edge },
|
||||
{ "else", K_else },
|
||||
{ "end", K_end },
|
||||
{ "endcase", K_endcase },
|
||||
{ "endfunction", K_endfunction },
|
||||
{ "endmodule", K_endmodule },
|
||||
{ "endprimitive", K_endprimitive },
|
||||
{ "endspecify", K_endspecify },
|
||||
{ "endtable", K_endtable },
|
||||
{ "event", K_event },
|
||||
{ "for", K_for },
|
||||
{ "force", K_force },
|
||||
{ "forever", K_forever },
|
||||
{ "fork", K_fork },
|
||||
{ "function", K_function },
|
||||
{ "highz0", K_highz0 },
|
||||
{ "highz1", K_highz1 },
|
||||
{ "if", K_if },
|
||||
{ "initial", K_initial },
|
||||
{ "inout", K_inout },
|
||||
{ "input", K_input },
|
||||
{ "integer", K_integer },
|
||||
{ "join", K_join },
|
||||
{ "large", K_large },
|
||||
{ "macromodule", K_macromodule },
|
||||
{ "medium", K_medium },
|
||||
{ "module", K_module },
|
||||
{ "nand", K_nand },
|
||||
{ "negedge", K_negedge },
|
||||
{ "nmos", K_nmos },
|
||||
{ "nor", K_nor },
|
||||
{ "not", K_not },
|
||||
{ "notif0", K_notif0 },
|
||||
{ "notif1", K_notif1 },
|
||||
{ "or", K_or },
|
||||
{ "output", K_output },
|
||||
{ "pmos", K_pmos },
|
||||
{ "posedge", K_posedge },
|
||||
{ "primitive", K_primitive },
|
||||
{ "pull0", K_pull0 },
|
||||
{ "pull1", K_pull1 },
|
||||
{ "pulldown", K_pulldown },
|
||||
{ "pullup", K_pullup },
|
||||
{ "rcmos", K_rcmos },
|
||||
{ "reg", K_reg },
|
||||
{ "release", K_release },
|
||||
{ "repeat", K_repeat },
|
||||
{ "rnmos", K_rnmos },
|
||||
{ "rpmos", K_rpmos },
|
||||
{ "rtran", K_rtran },
|
||||
{ "rtranif0", K_rtranif0 },
|
||||
{ "rtranif1", K_rtranif1 },
|
||||
{ "scalered", K_scalered },
|
||||
{ "small", K_small },
|
||||
{ "specify", K_specify },
|
||||
{ "specparam", K_specparam },
|
||||
{ "strong0", K_strong0 },
|
||||
{ "strong1", K_strong1 },
|
||||
{ "supply0", K_supply0 },
|
||||
{ "supply1", K_supply1 },
|
||||
{ "table", K_table },
|
||||
{ "task", K_task },
|
||||
{ "time", K_time },
|
||||
{ "tran", K_tran },
|
||||
{ "tranif0", K_tranif0 },
|
||||
{ "tranif1", K_tranif1 },
|
||||
{ "tri", K_tri },
|
||||
{ "tri0", K_tri0 },
|
||||
{ "tri1", K_tri1 },
|
||||
{ "triand", K_triand },
|
||||
{ "trior", K_trior },
|
||||
{ "vectored", K_vectored },
|
||||
{ "wait", K_wait },
|
||||
{ "wand", K_wand },
|
||||
{ "weak0", K_weak0 },
|
||||
{ "weak1", K_weak1 },
|
||||
{ "while", K_while },
|
||||
{ "wire", K_wire },
|
||||
{ "wor", K_wor },
|
||||
{ "xnor", K_xnor },
|
||||
{ "xor", K_xor },
|
||||
{ 0, IDENTIFIER }
|
||||
};
|
||||
|
||||
static int check_identifier(const char*name)
|
||||
{
|
||||
for (unsigned idx = 0 ; key_table[idx].name ; idx += 1)
|
||||
if (strcmp(key_table[idx].name, name) == 0)
|
||||
return key_table[idx].code;
|
||||
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static verinum*make_sized_binary(const char*txt)
|
||||
{
|
||||
char*ptr;
|
||||
unsigned size = strtoul(txt,&ptr,10);
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'b');
|
||||
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
unsigned idx = size;
|
||||
char*eptr = ptr + strlen(ptr) - 1;
|
||||
while ((eptr > ptr) && (idx < size)) {
|
||||
|
||||
if (*eptr == '_') {
|
||||
eptr -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (*eptr) {
|
||||
case '0':
|
||||
bits[idx++] = verinum::V0;
|
||||
break;
|
||||
case '1':
|
||||
bits[idx++] = verinum::V1;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
eptr -= 1;
|
||||
}
|
||||
|
||||
// Zero-extend binary number, except that z or x is extended
|
||||
// if it is the highest supplied digit.
|
||||
while (idx > 0) {
|
||||
switch (ptr[1]) {
|
||||
case '0':
|
||||
case '1':
|
||||
bits[idx++] = verinum::V0;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
}
|
||||
|
||||
static verinum*make_sized_octal(const char*txt)
|
||||
{
|
||||
char*ptr;
|
||||
unsigned size = strtoul(txt,&ptr,10);
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'o');
|
||||
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
unsigned idx = size;
|
||||
char*eptr = ptr + strlen(ptr);
|
||||
|
||||
while ((eptr > ptr) && (idx < (size-3))) {
|
||||
switch (*eptr) {
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
default: {
|
||||
unsigned val = *eptr - '0';
|
||||
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
eptr -= 1;
|
||||
}
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx > 0) switch (ptr[1]) {
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
}
|
||||
|
||||
static verinum*make_sized_hex(const char*txt)
|
||||
{
|
||||
char*ptr;
|
||||
unsigned size = strtoul(txt,&ptr,10);
|
||||
assert(*ptr == '\'');
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'h');
|
||||
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
unsigned idx = size;
|
||||
char*eptr = ptr + strlen(ptr);
|
||||
|
||||
while ((eptr > ptr) && (idx < (size-4))) {
|
||||
switch (*eptr) {
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
{
|
||||
unsigned val = tolower(*eptr) - 'a' + 10;
|
||||
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&8)? verinum::V1 : verinum::V0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
unsigned val = *eptr - '0';
|
||||
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&8)? verinum::V1 : verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
eptr -= 1;
|
||||
}
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx > 0) switch (ptr[1]) {
|
||||
case 'x':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
}
|
||||
|
||||
return new verinum(bits, size);
|
||||
}
|
||||
|
||||
static void reset_lexor()
|
||||
{
|
||||
yyrestart(vl_input);
|
||||
yylloc.first_line = 1;
|
||||
yylloc.text = vl_file;
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: main.cc,v 1.1 1998/11/03 23:28:59 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
# include <iostream.h>
|
||||
# include <fstream>
|
||||
# include <unistd.h>
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
|
||||
extern void pform_parse();
|
||||
|
||||
const char*vl_file = "";
|
||||
const char*target = "verilog";
|
||||
string start_module = "";
|
||||
|
||||
extern Design* elaborate(const list<Module*>&modules, const string&root);
|
||||
extern void emit(ostream&o, const Design*, const char*);
|
||||
extern void stupid(Design*des);
|
||||
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
bool dump_flag = false;
|
||||
bool optimize_flag = false;
|
||||
const char* out_path = 0;
|
||||
int opt;
|
||||
unsigned flag_errors = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "DOo:s:t:")) != EOF) switch (opt) {
|
||||
case 'D':
|
||||
dump_flag = true;
|
||||
break;
|
||||
case 'O':
|
||||
optimize_flag = true;
|
||||
break;
|
||||
case 'o':
|
||||
out_path = optarg;
|
||||
break;
|
||||
case 's':
|
||||
start_module = optarg;
|
||||
break;
|
||||
case 't':
|
||||
target = optarg;
|
||||
break;
|
||||
default:
|
||||
flag_errors += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flag_errors)
|
||||
return flag_errors;
|
||||
|
||||
if (optind == argc) {
|
||||
cerr << "No input files." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open the input (source) file. */
|
||||
vl_file = argv[optind];
|
||||
FILE*input = fopen(vl_file, "r");
|
||||
if (input == 0) {
|
||||
cerr << "Unable to open " <<vl_file << "." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the input. Make the pform. */
|
||||
list<Module*>modules;
|
||||
int rc = pform_parse(input, modules);
|
||||
|
||||
if (rc) {
|
||||
cerr << "I give up." << endl;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dump_flag) {
|
||||
ofstream out ("a.pf");
|
||||
out << "PFORM DUMP:" << endl;
|
||||
for (list<Module*>::iterator mod = modules.begin()
|
||||
; mod != modules.end()
|
||||
; mod ++ ) {
|
||||
pform_dump(out, *mod);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Select a root module, and elaborate the design. */
|
||||
if ((start_module == "") && (modules.size() == 1)) {
|
||||
Module*mod = modules.front();
|
||||
start_module = mod->get_name();
|
||||
}
|
||||
|
||||
Design*des = elaborate(modules, start_module);
|
||||
if (des == 0) {
|
||||
cerr << "Unable to elaborate design." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (optimize_flag) {
|
||||
stupid(des);
|
||||
}
|
||||
|
||||
if (dump_flag) {
|
||||
ofstream out ("a.net");
|
||||
des->dump(out);
|
||||
}
|
||||
|
||||
|
||||
if (out_path) {
|
||||
ofstream out;
|
||||
out.open(out_path);
|
||||
if (! out.is_open()) {
|
||||
cerr << "Unable to open " << out_path << " for writing."
|
||||
<< endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
emit(out, des, target);
|
||||
|
||||
} else {
|
||||
emit(cout, des, target);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:28:59 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: mangle.cc,v 1.1 1998/11/03 23:29:00 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
# include <strstream>
|
||||
|
||||
string mangle(const string&str)
|
||||
{
|
||||
if (str[0] == '$')
|
||||
return str;
|
||||
|
||||
ostrstream res;
|
||||
string tmp = str;
|
||||
|
||||
res << "X";
|
||||
|
||||
for (;;) {
|
||||
size_t pos = tmp.find('.');
|
||||
if (pos > tmp.length())
|
||||
pos = tmp.length();
|
||||
|
||||
res << pos << tmp.substr(0, pos);
|
||||
if (pos >= tmp.length())
|
||||
break;
|
||||
|
||||
tmp = tmp.substr(pos+1);
|
||||
}
|
||||
res << ends;
|
||||
return res.str();
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: mangle.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:00 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: netlist.cc,v 1.1 1998/11/03 23:29:00 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <cassert>
|
||||
# include "netlist.h"
|
||||
|
||||
void connect(NetObj::Link&l, NetObj::Link&r)
|
||||
{
|
||||
NetObj::Link* cur = &l;
|
||||
do {
|
||||
NetObj::Link*tmp = cur->next_;
|
||||
// Pull cur out of left list...
|
||||
cur->prev_->next_ = cur->next_;
|
||||
cur->next_->prev_ = cur->prev_;
|
||||
|
||||
// Put cur in right list
|
||||
cur->next_ = r.next_;
|
||||
cur->prev_ = &r;
|
||||
cur->next_->prev_ = cur;
|
||||
cur->prev_->next_ = cur;
|
||||
|
||||
// Go to the next item in the left list.
|
||||
cur = tmp;
|
||||
} while (cur != &l);
|
||||
}
|
||||
|
||||
const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx)
|
||||
{
|
||||
const NetObj*cur;
|
||||
unsigned cpin;
|
||||
net->pin(pin).next_link(cur, cpin);
|
||||
|
||||
while (cur != net) {
|
||||
const NetNet*sig = dynamic_cast<const NetNet*>(cur);
|
||||
if (sig) {
|
||||
bidx = cpin;
|
||||
return sig;
|
||||
}
|
||||
cur->pin(cpin).next_link(cur, cpin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetObj::NetObj(const string&n, unsigned np)
|
||||
: name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0)
|
||||
{
|
||||
pins_ = new Link[npins_];
|
||||
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
|
||||
pins_[idx].node_ = this;
|
||||
pins_[idx].pin_ = idx;
|
||||
}
|
||||
}
|
||||
|
||||
NetObj::~NetObj()
|
||||
{
|
||||
delete[]pins_;
|
||||
}
|
||||
|
||||
NetNode::~NetNode()
|
||||
{
|
||||
if (design_)
|
||||
design_->del_node(this);
|
||||
}
|
||||
|
||||
NetNet::~NetNet()
|
||||
{
|
||||
if (design_)
|
||||
design_->del_signal(this);
|
||||
}
|
||||
|
||||
NetProc::~NetProc()
|
||||
{
|
||||
}
|
||||
|
||||
NetAssign::NetAssign(NetNet*lv, NetExpr*rv)
|
||||
: NetNode("@assign", lv->pin_count()), lval_(lv), rval_(rv)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||
connect(pin(idx), lv->pin(idx));
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign::~NetAssign()
|
||||
{
|
||||
}
|
||||
|
||||
NetBlock::~NetBlock()
|
||||
{
|
||||
}
|
||||
|
||||
void NetBlock::append(NetProc*cur)
|
||||
{
|
||||
if (last_ == 0) {
|
||||
last_ = cur;
|
||||
cur->next_ = cur;
|
||||
} else {
|
||||
cur->next_ = last_->next_;
|
||||
last_->next_ = cur;
|
||||
last_ = cur;
|
||||
}
|
||||
}
|
||||
|
||||
NetTask::~NetTask()
|
||||
{
|
||||
delete[]parms_;
|
||||
}
|
||||
|
||||
NetExpr::~NetExpr()
|
||||
{
|
||||
}
|
||||
|
||||
NetEConst::~NetEConst()
|
||||
{
|
||||
}
|
||||
|
||||
void Design::add_signal(NetNet*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
if (signals_ == 0) {
|
||||
net->sig_next_ = net;
|
||||
net->sig_prev_ = net;
|
||||
} else {
|
||||
net->sig_next_ = signals_->sig_next_;
|
||||
net->sig_prev_ = signals_;
|
||||
net->sig_next_->sig_prev_ = net;
|
||||
net->sig_prev_->sig_next_ = net;
|
||||
}
|
||||
signals_ = net;
|
||||
net->design_ = this;
|
||||
}
|
||||
|
||||
void Design::del_signal(NetNet*net)
|
||||
{
|
||||
assert(net->design_ == this);
|
||||
if (signals_ == net)
|
||||
signals_ = net->sig_prev_;
|
||||
|
||||
if (signals_ == net) {
|
||||
signals_ = 0;
|
||||
} else {
|
||||
net->sig_prev_->sig_next_ = net->sig_next_;
|
||||
net->sig_next_->sig_prev_ = net->sig_prev_;
|
||||
}
|
||||
net->design_ = 0;
|
||||
}
|
||||
|
||||
NetNet* Design::find_signal(const string&name)
|
||||
{
|
||||
if (signals_ == 0)
|
||||
return 0;
|
||||
|
||||
NetNet*cur = signals_;
|
||||
do {
|
||||
if (cur->name() == name)
|
||||
return cur;
|
||||
|
||||
cur = cur->sig_prev_;
|
||||
} while (cur != signals_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::scan_signals(SigFunctor*fun)
|
||||
{
|
||||
if (signals_ == 0)
|
||||
return;
|
||||
|
||||
NetNet*cur = signals_->sig_next_;
|
||||
do {
|
||||
NetNet*next = cur->sig_next_;
|
||||
fun->sig_function(cur);
|
||||
cur = next;
|
||||
} while (cur != signals_->sig_next_);
|
||||
}
|
||||
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
if (nodes_ == 0) {
|
||||
net->node_next_ = net;
|
||||
net->node_prev_ = net;
|
||||
} else {
|
||||
net->node_next_ = nodes_->node_next_;
|
||||
net->node_prev_ = nodes_;
|
||||
net->node_next_->node_prev_ = net;
|
||||
net->node_prev_->node_next_ = net;
|
||||
}
|
||||
nodes_ = net;
|
||||
net->design_ = this;
|
||||
}
|
||||
|
||||
void Design::del_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == this);
|
||||
if (nodes_ == net)
|
||||
nodes_ = net->node_prev_;
|
||||
|
||||
if (nodes_ == net) {
|
||||
nodes_ = 0;
|
||||
} else {
|
||||
net->node_next_->node_prev_ = net->node_prev_;
|
||||
net->node_prev_->node_next_ = net->node_next_;
|
||||
}
|
||||
|
||||
net->design_ = 0;
|
||||
}
|
||||
|
||||
void Design::add_process(NetProcTop*pro)
|
||||
{
|
||||
pro->next_ = procs_;
|
||||
procs_ = pro;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: netlist.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:00 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,594 @@
|
|||
#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)
|
||||
#ident "$Id: netlist.h,v 1.1 1998/11/03 23:29:01 steve Exp $"
|
||||
#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>
|
||||
# include "verinum.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
class NetObj {
|
||||
|
||||
public:
|
||||
class Link {
|
||||
friend void connect(Link&, Link&);
|
||||
friend class NetObj;
|
||||
|
||||
public:
|
||||
Link() : next_(this), prev_(this) { }
|
||||
~Link() { unlink(); }
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
// 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; }
|
||||
|
||||
private:
|
||||
// The NetNode manages these. They point back to the
|
||||
// NetNode so that following the links can get me here.
|
||||
NetObj *node_;
|
||||
unsigned pin_;
|
||||
|
||||
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; }
|
||||
|
||||
Link&pin(unsigned idx) { return pins_[idx]; }
|
||||
const Link&pin(unsigned idx) const { return pins_[idx]; }
|
||||
|
||||
void dump_node_pins(ostream&, unsigned) const;
|
||||
|
||||
|
||||
private:
|
||||
string name_;
|
||||
Link*pins_;
|
||||
const unsigned npins_;
|
||||
unsigned delay1_;
|
||||
unsigned delay2_;
|
||||
unsigned delay3_;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 };
|
||||
|
||||
explicit NetNet(const string&n, Type t, unsigned npins =1)
|
||||
: NetObj(n, npins), sig_next_(0), sig_prev_(0), design_(0),
|
||||
type_(t), port_type_(NOT_A_PORT), msb_(npins-1), lsb_(0),
|
||||
local_flag_(false) { }
|
||||
|
||||
explicit NetNet(const string&n, Type t, long ms, long ls)
|
||||
: NetObj(n, ((ms>ls)?ms-ls:ls-ms) + 1), sig_next_(0),
|
||||
sig_prev_(0), design_(0), type_(t), port_type_(NOT_A_PORT),
|
||||
msb_(ms), lsb_(ls), local_flag_(false) { }
|
||||
|
||||
virtual ~NetNet();
|
||||
|
||||
// Every signal has a name, even if it is null.
|
||||
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; }
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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)
|
||||
: NetNode(n, 2) { }
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents all manner of logic gates.
|
||||
*/
|
||||
class NetLogic : public NetNode {
|
||||
|
||||
public:
|
||||
enum TYPE { AND, NAND, NOR, NOT, OR, XOR };
|
||||
|
||||
explicit NetLogic(const string&n, unsigned pins, TYPE t)
|
||||
: NetNode(n, pins), type_(t) { }
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
/* =========
|
||||
* 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_;
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
class NetAssign : public NetProc, public NetNode {
|
||||
public:
|
||||
explicit NetAssign(NetNet*lv, NetExpr*rv);
|
||||
~NetAssign();
|
||||
|
||||
const NetNet* lval() const { return lval_; }
|
||||
const NetExpr*rval() const { return rval_; }
|
||||
|
||||
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:
|
||||
NetNet*const lval_;
|
||||
NetExpr*const rval_;
|
||||
};
|
||||
|
||||
/* 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_;
|
||||
};
|
||||
|
||||
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:
|
||||
enum Type { ANYEDGE, POSEDGE, NEGEDGE };
|
||||
|
||||
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)
|
||||
{ parms_ = new NetExpr*[nparms_];
|
||||
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
|
||||
parms_[idx] = 0;
|
||||
}
|
||||
~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_);
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
unsigned nparms_;
|
||||
NetExpr**parms_;
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
class NetProcTop {
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
/* =========
|
||||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a heirarchy that serves that purpose.
|
||||
*/
|
||||
class NetExpr {
|
||||
public:
|
||||
NetExpr() { }
|
||||
virtual ~NetExpr() =0;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const =0;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private: // not implemented
|
||||
NetExpr(const NetExpr&);
|
||||
NetExpr& operator=(const NetExpr&);
|
||||
};
|
||||
|
||||
class NetEConst : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConst(const verinum&val) : value_(val) { }
|
||||
~NetEConst();
|
||||
|
||||
const verinum&value() const { return value_; }
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
verinum value_;
|
||||
};
|
||||
|
||||
class NetEUnary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEUnary(char op, NetExpr*ex)
|
||||
: op_(op), expr_(ex) { }
|
||||
|
||||
char op() const { return op_; }
|
||||
const NetExpr* expr() const { return expr_; }
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
NetExpr*expr_;
|
||||
};
|
||||
|
||||
/* XXXX Note: I do not know what to do about this. Elaboration should
|
||||
expand vectors to scalers, but identifiers identify vectors, and
|
||||
other issues. This class exists for now until I figure out the
|
||||
right way to deal with identifiers. */
|
||||
class NetEIdent : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEIdent(const string&n) : name_(n) { }
|
||||
|
||||
const string& name() const { return name_; }
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class contains an entire design. It includes processes and a
|
||||
* netlist, and can be passed around from function to function.
|
||||
*/
|
||||
class Design {
|
||||
|
||||
public:
|
||||
Design() : signals_(0), nodes_(0), procs_(0) { }
|
||||
|
||||
|
||||
// SIGNALS
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void del_signal(NetNet*);
|
||||
NetNet*find_signal(const string&name);
|
||||
|
||||
// NODES
|
||||
void add_node(NetNode*);
|
||||
void del_node(NetNode*);
|
||||
|
||||
// PROCESSES
|
||||
void add_process(NetProcTop*);
|
||||
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
void emit(ostream&, struct target_t*) const;
|
||||
|
||||
class SigFunctor {
|
||||
public:
|
||||
virtual void sig_function(NetNet*) =0;
|
||||
};
|
||||
|
||||
void scan_signals(SigFunctor*);
|
||||
|
||||
private:
|
||||
// List all the signals in the design.
|
||||
NetNet*signals_;
|
||||
|
||||
// List the nodes in the design
|
||||
NetNode*nodes_;
|
||||
|
||||
// List the processes in the design.
|
||||
NetProcTop*procs_;
|
||||
|
||||
private: // not implemented
|
||||
Design(const Design&);
|
||||
Design& operator= (const Design&);
|
||||
};
|
||||
|
||||
|
||||
/* =======
|
||||
*/
|
||||
|
||||
|
||||
/* 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&);
|
||||
|
||||
/* 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; }
|
||||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.1 1998/11/03 23:29:01 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,548 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* 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)
|
||||
#ident "$Id: parse.y,v 1.1 1998/11/03 23:29:01 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
# include "pform.h"
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
string*text;
|
||||
list<string>*strings;
|
||||
|
||||
lgate*gate;
|
||||
list<lgate>*gates;
|
||||
|
||||
PExpr*expr;
|
||||
list<PExpr*>*exprs;
|
||||
|
||||
NetNet::Type nettype;
|
||||
PGBuiltin::Type gatetype;
|
||||
NetNet::PortType porttype;
|
||||
|
||||
PWire*wire;
|
||||
list<PWire*>*wires;
|
||||
|
||||
PEventStatement*event_statement;
|
||||
Statement*statement;
|
||||
list<Statement*>*statement_list;
|
||||
|
||||
verinum* number;
|
||||
};
|
||||
|
||||
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
|
||||
%token <number> NUMBER
|
||||
%token K_LE K_GE
|
||||
%token K_always K_and K_assign K_begin K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable
|
||||
%token K_edge K_else K_end K_endcase K_endfunction K_endmodule
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for
|
||||
%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_macromodule
|
||||
%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_pmos K_posedge K_primitive K_pull0
|
||||
%token K_pull1 K_pulldown K_pullup K_rcmos K_reg K_release K_repeat
|
||||
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalered
|
||||
%token K_small K_specify
|
||||
%token K_specparam K_strong0 K_strong1 K_supply0 K_supply1 K_table K_task
|
||||
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
|
||||
%token K_trior K_vectored K_wait K_wand K_weak0 K_weak1 K_while K_wire
|
||||
%token K_wor K_xnor K_xor
|
||||
|
||||
%type <text> identifier lvalue register_variable
|
||||
%type <strings> list_of_register_variables
|
||||
%type <strings> list_of_variables
|
||||
|
||||
%type <wire> port
|
||||
%type <wires> list_of_ports list_of_ports_opt
|
||||
|
||||
%type <gate> gate_instance
|
||||
%type <gates> gate_instance_list
|
||||
|
||||
%type <expr> bitsel delay delay_opt expression expr_primary const_expression
|
||||
%type <exprs> expression_list
|
||||
|
||||
%type <exprs> range range_opt
|
||||
%type <nettype> net_type
|
||||
%type <gatetype> gatetype
|
||||
%type <porttype> port_type
|
||||
|
||||
%type <event_statement> event_control event_expression
|
||||
%type <statement> statement statement_opt
|
||||
%type <statement_list> statement_list
|
||||
|
||||
%left UNARY_PREC
|
||||
%left '+' '-'
|
||||
%left K_GE K_LE '<' '>'
|
||||
%left '&'
|
||||
%left '^'
|
||||
|
||||
%%
|
||||
|
||||
source_file
|
||||
: description
|
||||
| source_file description
|
||||
;
|
||||
|
||||
bitsel
|
||||
: '[' const_expression ']'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
const_expression
|
||||
: NUMBER
|
||||
{ $$ = new PENumber($1);
|
||||
}
|
||||
| STRING
|
||||
{ $$ = new PEString(*$1);
|
||||
delete $1;
|
||||
}
|
||||
;
|
||||
|
||||
delay
|
||||
: '#' NUMBER
|
||||
{ $$ = new PENumber($2);
|
||||
}
|
||||
| '#' IDENTIFIER
|
||||
{ $$ = new PEIdent(*$2);
|
||||
delete $2;
|
||||
}
|
||||
;
|
||||
|
||||
delay_opt
|
||||
: delay { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
description
|
||||
: module
|
||||
| primitive
|
||||
;
|
||||
|
||||
event_control
|
||||
: '@' IDENTIFIER
|
||||
{ yyerror(@1, "Sorry, event control not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| '@' '(' event_expression ')'
|
||||
{ $$ = $3;
|
||||
}
|
||||
;
|
||||
|
||||
event_expression
|
||||
: K_posedge expression
|
||||
{ $$ = new PEventStatement(NetPEvent::POSEDGE, $2);
|
||||
}
|
||||
| K_negedge expression
|
||||
{ $$ = new PEventStatement(NetPEvent::NEGEDGE, $2);
|
||||
}
|
||||
;
|
||||
|
||||
expression
|
||||
: expr_primary
|
||||
{ $$ = $1; }
|
||||
| '(' expression ')'
|
||||
{ $$ = $2; }
|
||||
| '~' expression %prec UNARY_PREC
|
||||
{ $$ = new PEUnary('~', $2);
|
||||
}
|
||||
| '&' expression %prec UNARY_PREC
|
||||
{ $$ = new PEUnary('&', $2);
|
||||
}
|
||||
| expression '^' expression
|
||||
{ $$ = new PEBinary('^', $1, $3);
|
||||
}
|
||||
| expression '+' expression
|
||||
{ $$ = new PEBinary('+', $1, $3);
|
||||
}
|
||||
| expression '&' expression
|
||||
{ $$ = new PEBinary('&', $1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
expression_list
|
||||
: expression_list ',' expression
|
||||
{ list<PExpr*>*tmp = $1;
|
||||
tmp->push_back($3);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression
|
||||
{ list<PExpr*>*tmp = new list<PExpr*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression_list ','
|
||||
{ list<PExpr*>*tmp = $1;
|
||||
tmp->push_back(0);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
expr_primary
|
||||
: NUMBER
|
||||
{ $$ = new PENumber($1);
|
||||
}
|
||||
| STRING
|
||||
{ $$ = new PEString(*$1);
|
||||
delete $1;
|
||||
}
|
||||
| identifier
|
||||
{ $$ = new PEIdent(*$1);
|
||||
delete $1;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER
|
||||
{ $$ = new PEIdent(*$1);
|
||||
delete $1;
|
||||
}
|
||||
| identifier '[' expression ']'
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
tmp->msb_ = $3;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier '[' expression ':' expression ']'
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
tmp->msb_ = $3;
|
||||
tmp->lsb_ = $5;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
gate_instance
|
||||
: IDENTIFIER '(' expression_list ')'
|
||||
{ lgate*tmp = new lgate;
|
||||
tmp->name = *$1;
|
||||
tmp->parms = $3;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| '(' expression_list ')'
|
||||
{ lgate*tmp = new lgate;
|
||||
tmp->name = "";
|
||||
tmp->parms = $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
gate_instance_list
|
||||
: gate_instance_list ',' gate_instance
|
||||
{ list<lgate>*tmp = $1;
|
||||
tmp->push_back(*$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| gate_instance
|
||||
{ list<lgate>*tmp = new list<lgate>;
|
||||
tmp->push_back(*$1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
gatetype
|
||||
: K_and { $$ = PGBuiltin::AND; }
|
||||
| K_nand { $$ = PGBuiltin::NAND; }
|
||||
| K_or { $$ = PGBuiltin::OR; }
|
||||
| K_nor { $$ = PGBuiltin::NOR; }
|
||||
| K_xor { $$ = PGBuiltin::XOR; }
|
||||
| K_xnor { $$ = PGBuiltin::XNOR; }
|
||||
| K_buf { $$ = PGBuiltin::BUF; }
|
||||
| K_bufif0 { $$ = PGBuiltin::BUFIF0; }
|
||||
| K_bufif1 { $$ = PGBuiltin::BUFIF1; }
|
||||
| K_not { $$ = PGBuiltin::NOT; }
|
||||
| K_notif0 { $$ = PGBuiltin::NOTIF0; }
|
||||
| K_notif1 { $$ = PGBuiltin::NOTIF1; }
|
||||
| K_pulldown { $$ = PGBuiltin::PULLDOWN; }
|
||||
| K_pullup { $$ = PGBuiltin::PULLUP; }
|
||||
| K_nmos { $$ = PGBuiltin::NMOS; }
|
||||
| K_rnmos { $$ = PGBuiltin::RNMOS; }
|
||||
| K_pmos { $$ = PGBuiltin::PMOS; }
|
||||
| K_rpmos { $$ = PGBuiltin::RPMOS; }
|
||||
| K_cmos { $$ = PGBuiltin::CMOS; }
|
||||
| K_rcmos { $$ = PGBuiltin::RCMOS; }
|
||||
| K_tran { $$ = PGBuiltin::TRAN; }
|
||||
| K_rtran { $$ = PGBuiltin::RTRAN; }
|
||||
| K_tranif0 { $$ = PGBuiltin::TRANIF0; }
|
||||
| K_tranif1 { $$ = PGBuiltin::TRANIF1; }
|
||||
| K_rtranif0 { $$ = PGBuiltin::RTRANIF0; }
|
||||
| K_rtranif1 { $$ = PGBuiltin::RTRANIF1; }
|
||||
;
|
||||
|
||||
identifier
|
||||
: identifier '.' IDENTIFIER
|
||||
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
|
||||
$$ = $3;
|
||||
delete $1;
|
||||
}
|
||||
| IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
list_of_ports
|
||||
: port
|
||||
{ list<PWire*>*tmp = new list<PWire*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_ports ',' port
|
||||
{ list<PWire*>*tmp = $1;
|
||||
tmp->push_back($3);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
list_of_ports_opt
|
||||
: '(' list_of_ports ')' { $$ = $2; }
|
||||
| '(' ')' { $$ = 0; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
list_of_register_variables
|
||||
: register_variable
|
||||
{ list<string>*tmp = new list<string>;
|
||||
tmp->push_back(*$1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_register_variables ',' register_variable
|
||||
{ list<string>*tmp = $1;
|
||||
tmp->push_back(*$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
list_of_variables
|
||||
: IDENTIFIER
|
||||
{ list<string>*tmp = new list<string>;
|
||||
tmp->push_back(*$1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_variables ',' IDENTIFIER
|
||||
{ list<string>*tmp = $1;
|
||||
tmp->push_back(*$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
lvalue
|
||||
: identifier { $$ = $1; }
|
||||
;
|
||||
|
||||
module
|
||||
: K_module IDENTIFIER list_of_ports_opt ';'
|
||||
{ pform_startmodule(*$2, $3);
|
||||
}
|
||||
module_item_list
|
||||
K_endmodule
|
||||
{ pform_endmodule(*$2);
|
||||
delete $2;
|
||||
}
|
||||
;
|
||||
|
||||
module_item
|
||||
: net_type range_opt list_of_variables ';'
|
||||
{ pform_makewire($3, $1);
|
||||
if ($2) {
|
||||
pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| port_type range_opt list_of_variables ';'
|
||||
{ pform_set_port_type($3, $1);
|
||||
if ($2) {
|
||||
pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| K_reg range_opt list_of_register_variables ';'
|
||||
{ pform_makewire($3, NetNet::REG);
|
||||
if ($2) {
|
||||
pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| gatetype delay_opt gate_instance_list ';'
|
||||
{ pform_makegates($1, $2, $3);
|
||||
}
|
||||
| IDENTIFIER gate_instance_list ';'
|
||||
{ pform_make_modgates(*$1, $2);
|
||||
delete $1;
|
||||
}
|
||||
| K_assign IDENTIFIER '=' expression ';'
|
||||
{ pform_make_pgassign(*$2, $4);
|
||||
delete $2;
|
||||
}
|
||||
| K_assign IDENTIFIER bitsel '=' expression ';'
|
||||
{ pform_make_pgassign(*$2, $3, $5);
|
||||
delete $2;
|
||||
}
|
||||
| K_assign IDENTIFIER range '=' expression ';'
|
||||
{ pform_make_pgassign(*$2, $5);
|
||||
yyerror(@3, "Sorry, lvalue bit range not supported.");
|
||||
delete $2;
|
||||
delete $3;
|
||||
}
|
||||
| K_always statement
|
||||
{ pform_make_behavior(PProcess::PR_ALWAYS, $2);
|
||||
}
|
||||
| K_initial statement
|
||||
{ pform_make_behavior(PProcess::PR_INITIAL, $2);
|
||||
}
|
||||
;
|
||||
|
||||
module_item_list
|
||||
: module_item_list module_item
|
||||
| module_item
|
||||
;
|
||||
|
||||
net_type
|
||||
: K_wire { $$ = NetNet::WIRE; }
|
||||
| K_tri { $$ = NetNet::TRI; }
|
||||
| K_tri1 { $$ = NetNet::TRI1; }
|
||||
| K_supply0 { $$ = NetNet::SUPPLY0; }
|
||||
| K_wand { $$ = NetNet::WAND; }
|
||||
| K_triand { $$ = NetNet::TRIAND; }
|
||||
| K_tri0 { $$ = NetNet::TRI0; }
|
||||
| K_supply1 { $$ = NetNet::SUPPLY1; }
|
||||
| K_wor { $$ = NetNet::WOR; }
|
||||
| K_trior { $$ = NetNet::TRIOR; }
|
||||
;
|
||||
|
||||
port
|
||||
: IDENTIFIER
|
||||
{ $$ = new PWire(*$1, NetNet::IMPLICIT);
|
||||
$$->port_type = NetNet::PIMPLICIT;
|
||||
delete $1;
|
||||
}
|
||||
| IDENTIFIER '[' const_expression ':' const_expression ']'
|
||||
{ $$ = new PWire(*$1, NetNet::IMPLICIT);
|
||||
$$->port_type = NetNet::PIMPLICIT;
|
||||
$$->msb = $3;
|
||||
$$->lsb = $5;
|
||||
delete $1;
|
||||
}
|
||||
| IDENTIFIER '[' error ']'
|
||||
{ yyerror(@1, "invalid port bit select");
|
||||
$$ = new PWire(*$1, NetNet::IMPLICIT);
|
||||
$$->port_type = NetNet::PIMPLICIT;
|
||||
delete $1;
|
||||
}
|
||||
;
|
||||
|
||||
port_type
|
||||
: K_input { $$ = NetNet::PINPUT; }
|
||||
| K_output { $$ = NetNet::POUTPUT; }
|
||||
| K_inout { $$ = NetNet::PINOUT; }
|
||||
;
|
||||
|
||||
primitive
|
||||
: K_primitive IDENTIFIER '(' error ')' ';' K_endprimitive
|
||||
{ yyerror(@1, "Sorry, primitives not supported."); }
|
||||
;
|
||||
|
||||
range
|
||||
: '[' NUMBER ':' NUMBER ']'
|
||||
{ list<PExpr*>*tmp = new list<PExpr*>;
|
||||
tmp->push_back(new PENumber($2));
|
||||
tmp->push_back(new PENumber($4));
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
range_opt
|
||||
: range
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
register_variable
|
||||
: IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
| IDENTIFIER '[' error ']'
|
||||
{ yyerror(@1, "Sorry, register regions not implemented.");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
statement
|
||||
: K_begin statement_list K_end
|
||||
{ $$ = pform_make_block(PBlock::BL_SEQ, $2); }
|
||||
| K_fork statement_list K_join
|
||||
{ $$ = pform_make_block(PBlock::BL_PAR, $2); }
|
||||
| K_begin K_end
|
||||
{ $$ = pform_make_block(PBlock::BL_SEQ, 0); }
|
||||
| K_fork K_join
|
||||
{ $$ = pform_make_block(PBlock::BL_PAR, 0); }
|
||||
| delay statement_opt
|
||||
{ PDelayStatement*tmp = new PDelayStatement($1, $2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| event_control statement_opt
|
||||
{ PEventStatement*tmp = $1;
|
||||
tmp->set_statement($2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lvalue '=' expression ';'
|
||||
{ $$ = pform_make_assignment($1, $3);
|
||||
}
|
||||
| lvalue K_LE expression ';'
|
||||
{ $$ = pform_make_assignment($1, $3);
|
||||
yyerror(@1, "Sorry, non-blocking assignment not implemented.");
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list ')' ';'
|
||||
{ $$ = pform_make_calltask($1, $3);
|
||||
}
|
||||
| SYSTEM_IDENTIFIER ';'
|
||||
{ $$ = pform_make_calltask($1);
|
||||
}
|
||||
| error ';'
|
||||
{ yyerror(@1, "malformed statement");
|
||||
$$ = new PNoop;
|
||||
}
|
||||
;
|
||||
|
||||
statement_list
|
||||
: statement_list statement
|
||||
{ list<Statement*>*tmp = $1;
|
||||
tmp->push_back($2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| statement
|
||||
{ list<Statement*>*tmp = new list<Statement*>();
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
statement_opt
|
||||
: statement
|
||||
| ';' { $$ = 0; }
|
||||
;
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: parse_misc.cc,v 1.1 1998/11/03 23:29:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
# include <iostream.h>
|
||||
|
||||
extern const char*vl_file;
|
||||
|
||||
void VLerror(const char*msg)
|
||||
{
|
||||
cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl;
|
||||
}
|
||||
|
||||
void VLerror(const YYLTYPE&loc, const char*msg)
|
||||
{
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": " << msg << endl;
|
||||
}
|
||||
|
||||
void yywarn(const YYLTYPE&loc, const char*msg)
|
||||
{
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": warning -- " << msg << endl;
|
||||
}
|
||||
|
||||
int VLwrap()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:02 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef __parse_misc_H
|
||||
#define __parse_misc_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)
|
||||
#ident "$Id: parse_misc.h,v 1.1 1998/11/03 23:29:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include <list>
|
||||
# include "pform.h"
|
||||
|
||||
/*
|
||||
* The vlltype supports the passing of detailed source file location
|
||||
* information between the lexical analyzer and the parser. Defining
|
||||
* YYLTYPE compels the lexor to use this type and not something other.
|
||||
*/
|
||||
struct vlltype {
|
||||
unsigned first_line;
|
||||
unsigned first_column;
|
||||
unsigned last_line;
|
||||
unsigned last_column;
|
||||
const char*text;
|
||||
};
|
||||
# define YYLTYPE vlltype
|
||||
extern YYLTYPE yylloc;
|
||||
|
||||
/*
|
||||
* Interface into the lexical analyzer. ...
|
||||
*/
|
||||
extern int VLlex();
|
||||
extern void VLerror(const char*msg);
|
||||
extern void VLerror(const YYLTYPE&loc, const char*msg);
|
||||
#define yywarn VLwarn
|
||||
extern void VLwarn(const YYLTYPE&loc, const char*msg);
|
||||
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.h,v $
|
||||
* Revision 1.1 1998/11/03 23:29:03 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: pform.cc,v 1.1 1998/11/03 23:29:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include <list>
|
||||
# include <assert.h>
|
||||
# include <typeinfo>
|
||||
|
||||
extern int VLparse();
|
||||
|
||||
static Module*cur_module = 0;
|
||||
|
||||
static list<Module*>*vl_modules = 0;
|
||||
|
||||
/*
|
||||
* This function evaluates delay expressions. The result should be a
|
||||
* simple constant that I can interpret as an unsigned number.
|
||||
*/
|
||||
static unsigned long evaluate_delay(PExpr*delay)
|
||||
{
|
||||
PENumber*pp = dynamic_cast<PENumber*>(delay);
|
||||
if (pp == 0) {
|
||||
VLerror("Sorry, delay expression is too complicated.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pp->value().as_ulong();
|
||||
}
|
||||
|
||||
void pform_startmodule(const string&name, list<PWire*>*ports)
|
||||
{
|
||||
assert( cur_module == 0 );
|
||||
cur_module = new Module(name, ports? ports->size() : 0);
|
||||
|
||||
vl_modules->push_back(cur_module);
|
||||
|
||||
if (ports) {
|
||||
unsigned idx = 0;
|
||||
for (list<PWire*>::iterator cur = ports->begin()
|
||||
; cur != ports->end()
|
||||
; cur ++ ) {
|
||||
cur_module->add_wire(*cur);
|
||||
cur_module->ports[idx++] = *cur;
|
||||
}
|
||||
|
||||
delete ports;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_endmodule(const string&name)
|
||||
{
|
||||
assert(cur_module);
|
||||
assert(name == cur_module->get_name());
|
||||
cur_module = 0;
|
||||
}
|
||||
|
||||
void pform_makegate(PGBuiltin::Type type,
|
||||
const string&name,
|
||||
const vector<PExpr*>&wires,
|
||||
unsigned long delay_val)
|
||||
{
|
||||
PGate*cur = new PGBuiltin(type, name, wires, delay_val);
|
||||
cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_makegates(PGBuiltin::Type type,
|
||||
PExpr*delay, list<lgate>*gates)
|
||||
{
|
||||
unsigned long delay_val = evaluate_delay(delay);
|
||||
delete delay;
|
||||
|
||||
while (! gates->empty()) {
|
||||
lgate cur = gates->front();
|
||||
gates->pop_front();
|
||||
|
||||
vector<PExpr*>wires (cur.parms->size());
|
||||
for (unsigned idx = 0 ; idx < wires.size() ; idx += 1) {
|
||||
PExpr*ep = cur.parms->front();
|
||||
cur.parms->pop_front();
|
||||
|
||||
wires[idx] = ep;
|
||||
}
|
||||
|
||||
pform_makegate(type, cur.name, wires, delay_val);
|
||||
}
|
||||
|
||||
delete gates;
|
||||
}
|
||||
|
||||
void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
const vector<PExpr*>&wires)
|
||||
{
|
||||
PGate*cur = new PGModule(type, name, wires);
|
||||
cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_modgates(const string&type, list<lgate>*gates)
|
||||
{
|
||||
while (! gates->empty()) {
|
||||
lgate cur = gates->front();
|
||||
gates->pop_front();
|
||||
|
||||
vector<PExpr*>wires (cur.parms->size());
|
||||
for (unsigned idx = 0 ; idx < wires.size() ; idx += 1) {
|
||||
PExpr*ep = cur.parms->front();
|
||||
cur.parms->pop_front();
|
||||
|
||||
wires[idx] = ep;
|
||||
}
|
||||
|
||||
pform_make_modgate(type, cur.name, wires);
|
||||
}
|
||||
|
||||
delete gates;
|
||||
}
|
||||
|
||||
void pform_make_pgassign(const string&lval, PExpr*rval)
|
||||
{
|
||||
vector<PExpr*> wires (2);
|
||||
wires[0] = new PEIdent(lval);
|
||||
wires[1] = rval;
|
||||
PGAssign*cur = new PGAssign(wires);
|
||||
cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_pgassign(const string&lval, PExpr*sel, PExpr*rval)
|
||||
{
|
||||
vector<PExpr*> wires (2);
|
||||
PEIdent*tmp = new PEIdent(lval);
|
||||
tmp->msb_ = sel;
|
||||
wires[0] = tmp;
|
||||
wires[1] = rval;
|
||||
PGAssign*cur = new PGAssign(wires);
|
||||
cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_makewire(const string&name, NetNet::Type type)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
if (cur) {
|
||||
if (cur->type != NetNet::IMPLICIT)
|
||||
VLerror("Extra definition of wire.");
|
||||
|
||||
cur->type = type;
|
||||
return;
|
||||
}
|
||||
|
||||
cur = new PWire(name, type);
|
||||
cur_module->add_wire(cur);
|
||||
}
|
||||
|
||||
void pform_makewire(const list<string>*names, NetNet::Type type)
|
||||
{
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
; cur != names->end()
|
||||
; cur ++ )
|
||||
pform_makewire(*cur, type);
|
||||
|
||||
}
|
||||
|
||||
void pform_set_port_type(const string&name, NetNet::PortType pt)
|
||||
{
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a port.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cur->port_type != NetNet::PIMPLICIT) {
|
||||
VLerror("error setting port direction.");
|
||||
return;
|
||||
}
|
||||
|
||||
cur->port_type = pt;
|
||||
}
|
||||
|
||||
static void pform_set_net_range(const string&name, list<PExpr*>*range)
|
||||
{
|
||||
assert(range->size() == 2);
|
||||
|
||||
PWire*cur = cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cur->msb == 0) && (cur->lsb == 0)){
|
||||
list<PExpr*>::const_iterator idx = range->begin();
|
||||
cur->msb = *idx;
|
||||
idx ++;
|
||||
cur->lsb = *idx;
|
||||
} else {
|
||||
VLwarn(yylloc, "net ranges not checked.");
|
||||
}
|
||||
}
|
||||
|
||||
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
{
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
; cur != names->end()
|
||||
; cur ++ ) {
|
||||
pform_set_port_type(*cur, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void pform_set_net_range(list<string>*names, list<PExpr*>*range)
|
||||
{
|
||||
assert(range->size() == 2);
|
||||
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
; cur != names->end()
|
||||
; cur ++ ) {
|
||||
pform_set_net_range(*cur, range);
|
||||
}
|
||||
}
|
||||
|
||||
void pform_make_behavior(PProcess::Type type, Statement*st)
|
||||
{
|
||||
PProcess*pp = new PProcess(type, st);
|
||||
cur_module->add_behavior(pp);
|
||||
}
|
||||
|
||||
Statement* pform_make_block(PBlock::BL_TYPE type, list<Statement*>*sl)
|
||||
{
|
||||
if (sl == 0)
|
||||
sl = new list<Statement*>;
|
||||
|
||||
PBlock*bl = new PBlock(type, *sl);
|
||||
delete sl;
|
||||
return bl;
|
||||
}
|
||||
|
||||
Statement* pform_make_assignment(string*text, PExpr*ex)
|
||||
{
|
||||
PAssign*st = new PAssign (*text, ex);
|
||||
delete text;
|
||||
return st;
|
||||
}
|
||||
|
||||
Statement* pform_make_calltask(string*name, list<PExpr*>*parms)
|
||||
{
|
||||
if (parms == 0)
|
||||
parms = new list<PExpr*>;
|
||||
|
||||
PCallTask*ct = new PCallTask(*name, *parms);
|
||||
delete name;
|
||||
delete parms;
|
||||
return ct;
|
||||
}
|
||||
|
||||
FILE*vl_input = 0;
|
||||
int pform_parse(FILE*input, list<Module*>&modules)
|
||||
{
|
||||
vl_input = input;
|
||||
vl_modules = &modules;
|
||||
int rc = VLparse();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: pform.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:03 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef __pform_H
|
||||
#define __pform_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)
|
||||
#ident "$Id: pform.h,v 1.1 1998/11/03 23:29:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "Module.h"
|
||||
# include "Statement.h"
|
||||
# include "PGate.h"
|
||||
# include "PExpr.h"
|
||||
# include "PWire.h"
|
||||
# include "verinum.h"
|
||||
# include <iostream.h>
|
||||
# include <string>
|
||||
# include <list>
|
||||
# include <vector>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
* These classes implement the parsed form (P-form for short) of the
|
||||
* original verilog source. the parser generates the pform for the
|
||||
* convenience of later processing steps.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Wire objects represent the named wires (of various flavor) declared
|
||||
* in the source.
|
||||
*
|
||||
* Gate objects are the functional modules that are connected together
|
||||
* by wires.
|
||||
*
|
||||
* Wires and gates, connected by joints, represent a netlist. The
|
||||
* netlist is therefore a representation of the desired circuit.
|
||||
*/
|
||||
class PGate;
|
||||
class PExpr;
|
||||
|
||||
/*
|
||||
* These type are lexical types -- that is, types that are used as
|
||||
* lexical values to decorate the parse tree during parsing. They are
|
||||
* not in any way preserved once parsing is done.
|
||||
*/
|
||||
|
||||
struct lgate {
|
||||
string name;
|
||||
list<PExpr*>*parms;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The parser uses startmodule and endmodule together to build up a
|
||||
* module as it parses it. The startmodule tells the pform code that a
|
||||
* module has been noticed in the source file and the following events
|
||||
* are to apply to the scope of that module. The endmodule causes the
|
||||
* pform to close up and finish the named module.
|
||||
*/
|
||||
extern void pform_startmodule(const string&, list<PWire*>*ports);
|
||||
extern void pform_endmodule(const string&);
|
||||
|
||||
/*
|
||||
* The makewire functions announce to the pform code new wires. These
|
||||
* go into a module that is currently opened.
|
||||
*/
|
||||
extern void pform_makewire(const string&name, NetNet::Type type);
|
||||
extern void pform_makewire(const list<string>*names, NetNet::Type type);
|
||||
extern void pform_set_port_type(list<string>*names, NetNet::PortType);
|
||||
extern void pform_set_net_range(list<string>*names, list<PExpr*>*);
|
||||
extern void pform_make_behavior(PProcess::Type, Statement*);
|
||||
extern Statement* pform_make_block(PBlock::BL_TYPE, list<Statement*>*);
|
||||
extern Statement* pform_make_assignment(string*t, PExpr*e);
|
||||
extern Statement* pform_make_calltask(string*t, list<PExpr*>* =0);
|
||||
|
||||
/*
|
||||
* The makegate function creates a new gate (which need not have a
|
||||
* name) and connects it to the specified wires.
|
||||
*/
|
||||
extern void pform_makegate(PGBuiltin::Type type,
|
||||
const string&name,
|
||||
const vector<string>&wires,
|
||||
unsigned long delay_value);
|
||||
|
||||
extern void pform_makegates(PGBuiltin::Type type,
|
||||
PExpr*delay,
|
||||
list<lgate>*gates);
|
||||
|
||||
extern void pform_make_modgates(const string&type, list<lgate>*gates);
|
||||
|
||||
/* Make a continuous assignment node, with optional bit- or part- select. */
|
||||
extern void pform_make_pgassign(const string&lval, PExpr*rval);
|
||||
extern void pform_make_pgassign(const string&lval, PExpr*sel, PExpr*rval);
|
||||
|
||||
/*
|
||||
* These are functions that the outside-the-parser code uses the do
|
||||
* interesting things to the verilog. The parse function reads and
|
||||
* parses the source file and places all the modules it finds into the
|
||||
* mod list. The dump function dumps a module to the output stream.
|
||||
*/
|
||||
extern int pform_parse(FILE*, list<Module*>&mod);
|
||||
extern void pform_dump(ostream&out, Module*mod);
|
||||
|
||||
/*
|
||||
* $Log: pform.h,v $
|
||||
* Revision 1.1 1998/11/03 23:29:04 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: pform_dump.cc,v 1.1 1998/11/03 23:29:04 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file provides the pform_dump function, that dumps the module
|
||||
* passed as a parameter. The dump is as much as possible in Verilog
|
||||
* syntax, so that a human can tell that it really does describe the
|
||||
* module in question.
|
||||
*/
|
||||
# include "pform.h"
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <typeinfo>
|
||||
|
||||
ostream& operator << (ostream&out, const PExpr&obj)
|
||||
{
|
||||
obj.dump(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
}
|
||||
|
||||
void PENumber::dump(ostream&out) const
|
||||
{
|
||||
out << value();
|
||||
}
|
||||
|
||||
void PEIdent::dump(ostream&out) const
|
||||
{
|
||||
out << text_;
|
||||
if (msb_) {
|
||||
out << "[" << *msb_;
|
||||
if (lsb_) {
|
||||
out << ":" << *lsb_;
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
}
|
||||
|
||||
void PEString::dump(ostream&out) const
|
||||
{
|
||||
out << "\"" << text_ << "\"";
|
||||
}
|
||||
|
||||
void PEUnary::dump(ostream&out) const
|
||||
{
|
||||
out << op_ << "(" << *expr_ << ")";
|
||||
}
|
||||
|
||||
void PEBinary::dump(ostream&out) const
|
||||
{
|
||||
out << "(" << *left_ << ")" << op_ << "(" << *right_ << ")";
|
||||
}
|
||||
|
||||
|
||||
void PWire::dump(ostream&out) const
|
||||
{
|
||||
switch (type) {
|
||||
case NetNet::IMPLICIT:
|
||||
out << " implicit wire ";
|
||||
break;
|
||||
case NetNet::WIRE:
|
||||
out << " wire ";
|
||||
break;
|
||||
case NetNet::REG:
|
||||
out << " reg ";
|
||||
break;
|
||||
default:
|
||||
out << " (" << type << ") ";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (port_type) {
|
||||
case NetNet::PIMPLICIT:
|
||||
out << "(implicit input) ";
|
||||
break;
|
||||
case NetNet::PINPUT:
|
||||
out << "(input) ";
|
||||
break;
|
||||
case NetNet::POUTPUT:
|
||||
out << "(output) ";
|
||||
break;
|
||||
case NetNet::PINOUT:
|
||||
out << "(input output) ";
|
||||
break;
|
||||
case NetNet::NOT_A_PORT:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lsb || msb) {
|
||||
assert(lsb && msb);
|
||||
out << "[" << *msb << ":" << *lsb << "] ";
|
||||
}
|
||||
|
||||
out << name << ";" << endl;
|
||||
}
|
||||
|
||||
void PGate::dump_pins(ostream&out) const
|
||||
{
|
||||
if (pin_count()) {
|
||||
out << *pin(0);
|
||||
|
||||
for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) {
|
||||
out << ", " << *pin(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PGate::dump(ostream&out) const
|
||||
{
|
||||
out << " " << typeid(*this).name() << " #"
|
||||
<< get_delay() << " " << get_name() << "(";
|
||||
dump_pins(out);
|
||||
out << ");" << endl;
|
||||
|
||||
}
|
||||
|
||||
void PGAssign::dump(ostream&out) const
|
||||
{
|
||||
out << " assign " << *pin(0) << " = " << *pin(1) << ";" << endl;
|
||||
}
|
||||
|
||||
void PGBuiltin::dump(ostream&out) const
|
||||
{
|
||||
switch (type()) {
|
||||
case PGBuiltin::NAND:
|
||||
out << " nand #";
|
||||
break;
|
||||
default:
|
||||
out << " builtin gate #";
|
||||
}
|
||||
|
||||
out << get_delay() << " " << get_name() << "(";
|
||||
dump_pins(out);
|
||||
out << ");" << endl;
|
||||
}
|
||||
|
||||
void PGModule::dump(ostream&out) const
|
||||
{
|
||||
out << " " << type_ << " " << get_name() << "(";
|
||||
dump_pins(out);
|
||||
out << ");" << endl;
|
||||
}
|
||||
|
||||
void Statement::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
/* I give up. I don't know what type this statement is,
|
||||
so just print the C++ typeid and let the user figure
|
||||
it out. */
|
||||
out << setw(ind) << "";
|
||||
out << "/* " << typeid(*this) .name() << " */ ;" << endl;
|
||||
}
|
||||
|
||||
void PAssign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "";
|
||||
out << to_name_ << " = " << *expr_ << ";" << endl;
|
||||
}
|
||||
|
||||
void PBlock::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "begin" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < size() ; idx += 1) {
|
||||
stat(idx)->dump(out, ind+2);
|
||||
}
|
||||
|
||||
out << setw(ind) << "" << "end" << endl;
|
||||
}
|
||||
|
||||
void PCallTask::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << name_;
|
||||
|
||||
if (nparms_) {
|
||||
out << "(";
|
||||
if (parms_[0])
|
||||
out << *parms_[0];
|
||||
|
||||
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
|
||||
out << ", ";
|
||||
if (parms_[idx])
|
||||
out << *parms_[idx];
|
||||
}
|
||||
out << ")";
|
||||
}
|
||||
|
||||
out << ";" << endl;
|
||||
}
|
||||
|
||||
|
||||
void PDelayStatement::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "#" << *delay_ << endl;
|
||||
statement_->dump(out, ind+2);
|
||||
}
|
||||
|
||||
void PEventStatement::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "@(";
|
||||
switch (type_) {
|
||||
case NetPEvent::ANYEDGE:
|
||||
break;
|
||||
case NetPEvent::POSEDGE:
|
||||
out << "posedge ";
|
||||
break;
|
||||
case NetPEvent::NEGEDGE:
|
||||
out << "negedge ";
|
||||
break;
|
||||
}
|
||||
out << *expr_ << ")" << endl;
|
||||
|
||||
statement_->dump(out, ind+2);
|
||||
}
|
||||
|
||||
void PProcess::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
switch (type_) {
|
||||
case PProcess::PR_INITIAL:
|
||||
out << setw(ind) << "" << "initial" << endl;
|
||||
break;
|
||||
case PProcess::PR_ALWAYS:
|
||||
out << setw(ind) << "" << "always" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
statement_->dump(out, ind+2);
|
||||
}
|
||||
|
||||
void pform_dump(ostream&out, Module*mod)
|
||||
{
|
||||
out << "module " << mod->get_name() << ";" << endl;
|
||||
|
||||
// Iterate through and display all the wires.
|
||||
const list<PWire*>&wires = mod->get_wires();
|
||||
for (list<PWire*>::const_iterator wire = wires.begin()
|
||||
; wire != wires.end()
|
||||
; wire ++ ) {
|
||||
|
||||
(*wire)->dump(out);
|
||||
}
|
||||
|
||||
|
||||
// Iterate through and display all the gates
|
||||
const list<PGate*>&gates = mod->get_gates();
|
||||
for (list<PGate*>::const_iterator gate = gates.begin()
|
||||
; gate != gates.end()
|
||||
; gate ++ ) {
|
||||
|
||||
(*gate)->dump(out);
|
||||
}
|
||||
|
||||
|
||||
const list<PProcess*>&behaves = mod->get_behaviors();
|
||||
for (list<PProcess*>::const_iterator behav = behaves.begin()
|
||||
; behav != behaves.end()
|
||||
; behav ++ ) {
|
||||
|
||||
(*behav)->dump(out, 4);
|
||||
}
|
||||
|
||||
out << "endmodule" << endl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:04 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: stupid.cc,v 1.1 1998/11/03 23:29:05 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include <vector>
|
||||
|
||||
vector<NetObj::Link*>* list_link_nodes(NetObj::Link&link)
|
||||
{
|
||||
NetObj*net;
|
||||
unsigned npin;
|
||||
vector<NetObj::Link*>*result = new vector<NetObj::Link*>;
|
||||
|
||||
link.cur_link(net, npin);
|
||||
NetObj*cur = net;
|
||||
unsigned cpin = npin;
|
||||
do {
|
||||
if (dynamic_cast<NetNode*>(cur))
|
||||
result->push_back(&cur->pin(cpin));
|
||||
|
||||
cur->pin(cpin).next_link(cur, cpin);
|
||||
} while ((cur != net) || (cpin != npin));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function scans a design and removes artifacts from the
|
||||
* elaboration step, and maybe a few other stupid inefficiencies.
|
||||
*/
|
||||
|
||||
class Functor : public Design::SigFunctor {
|
||||
|
||||
public:
|
||||
virtual void sig_function(NetNet*);
|
||||
};
|
||||
|
||||
|
||||
void Functor::sig_function(NetNet*net)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
||||
vector<NetObj::Link*>*nodes = list_link_nodes(net->pin(idx));
|
||||
#if 0
|
||||
cerr << "XXXX " << net->name() << "[" << idx << "] "
|
||||
"nodes->size() == " << nodes->size() << endl;
|
||||
#endif
|
||||
delete nodes;
|
||||
}
|
||||
}
|
||||
|
||||
void stupid(Design*des)
|
||||
{
|
||||
Functor fun;
|
||||
des->scan_signals(&fun);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: stupid.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:05 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: t-verilog.cc,v 1.1 1998/11/03 23:29:05 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This rather interesting target generates Verilog from the
|
||||
* design. This is interesting since by the time I get here,
|
||||
* elaboration and generic optimizations have been performed. This is
|
||||
* useful for feeding optimized designs to other tools, or the human
|
||||
* for debugging.
|
||||
*/
|
||||
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <strstream>
|
||||
# include <typeinfo>
|
||||
# include "target.h"
|
||||
|
||||
extern const struct target tgt_verilog;
|
||||
|
||||
class target_verilog : public target_t {
|
||||
public:
|
||||
virtual void start_design(ostream&os, const Design*);
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
virtual void end_design(ostream&os, const Design*);
|
||||
private:
|
||||
unsigned indent_;
|
||||
|
||||
void emit_expr_(ostream&os, const NetExpr*);
|
||||
};
|
||||
|
||||
|
||||
static ostream& operator<< (ostream&o, NetNet::Type t)
|
||||
{
|
||||
switch (t) {
|
||||
case NetNet::WIRE:
|
||||
o << "wire";
|
||||
break;
|
||||
case NetNet::REG:
|
||||
o << "reg";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
* The output of the design starts here. The emit operation calls the
|
||||
* design_start and design_end target methods around the scan of the
|
||||
* design. Targets can use these hooks to generate header or footer
|
||||
* information if desired.
|
||||
*/
|
||||
void target_verilog::start_design(ostream&os, const Design*)
|
||||
{
|
||||
indent_ = 0;
|
||||
os << "module " << "main" << ";" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit first iterates over all the signals. This gives the target a
|
||||
* chance to declare signal variables before the network is assembled
|
||||
* or behaviors are written.
|
||||
*/
|
||||
void target_verilog::signal(ostream&os, const NetNet*net)
|
||||
{
|
||||
os << " " << net->type();
|
||||
if (net->pin_count() > 1)
|
||||
os << " [" << net->msb() << ":" << net->lsb() << "]";
|
||||
|
||||
if (net->delay1())
|
||||
os << " #" << net->delay1();
|
||||
|
||||
os << " " << mangle(net->name()) << ";" << endl;
|
||||
}
|
||||
|
||||
void target_verilog::logic(ostream&os, const NetLogic*net)
|
||||
{
|
||||
switch (net->type()) {
|
||||
|
||||
case NetLogic::AND:
|
||||
os << " and";
|
||||
break;
|
||||
case NetLogic::NAND:
|
||||
os << " nand";
|
||||
break;
|
||||
case NetLogic::NOR:
|
||||
os << " nor";
|
||||
break;
|
||||
case NetLogic::NOT:
|
||||
os << " not";
|
||||
break;
|
||||
case NetLogic::OR:
|
||||
os << " or";
|
||||
break;
|
||||
case NetLogic::XOR:
|
||||
os << " xor";
|
||||
break;
|
||||
}
|
||||
|
||||
os << " #" << net->delay1() << " " << mangle(net->name()) << "(";
|
||||
|
||||
unsigned sidx;
|
||||
const NetNet*sig = find_link_signal(net, 0, sidx);
|
||||
os << mangle(sig->name()) << "[" << sidx << "]";
|
||||
for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) {
|
||||
sig = find_link_signal(net, idx, sidx);
|
||||
assert(sig);
|
||||
os << ", " << mangle(sig->name()) << "[" << sidx << "]";
|
||||
}
|
||||
os << ");" << endl;
|
||||
}
|
||||
|
||||
void target_verilog::bufz(ostream&os, const NetBUFZ*net)
|
||||
{
|
||||
assert( net->pin_count() == 2 );
|
||||
os << " assign ";
|
||||
|
||||
unsigned sidx;
|
||||
const NetNet*sig = find_link_signal(net, 0, sidx);
|
||||
os << mangle(sig->name()) << "[" << sidx << "] = ";
|
||||
|
||||
sig = find_link_signal(net, 1, sidx);
|
||||
os << mangle(sig->name()) << "[" << sidx << "];" << endl;
|
||||
}
|
||||
|
||||
void target_verilog::start_process(ostream&os, const NetProcTop*proc)
|
||||
{
|
||||
switch (proc->type()) {
|
||||
case NetProcTop::KINITIAL:
|
||||
os << " initial" << endl;
|
||||
break;
|
||||
case NetProcTop::KALWAYS:
|
||||
os << " always" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
indent_ = 6;
|
||||
}
|
||||
|
||||
void target_verilog::proc_assign(ostream&os, const NetAssign*net)
|
||||
{
|
||||
os << setw(indent_) << "";
|
||||
|
||||
const NetNet*lval = net->lval();
|
||||
|
||||
os << mangle(lval->name()) << " = ";
|
||||
|
||||
emit_expr_(os, net->rval());
|
||||
|
||||
os << ";" << endl;
|
||||
}
|
||||
|
||||
void target_verilog::emit_expr_(ostream&os, const NetExpr*expr)
|
||||
{
|
||||
|
||||
if (const NetEConst*pp = dynamic_cast<const NetEConst*>(expr)) {
|
||||
|
||||
os << pp->value();
|
||||
|
||||
} else if (const NetEIdent*pp = dynamic_cast<const NetEIdent*>(expr)) {
|
||||
|
||||
os << mangle(pp->name());
|
||||
|
||||
} else if (const NetEUnary*pp = dynamic_cast<const NetEUnary*>(expr)) {
|
||||
|
||||
os << pp->op() << "(";
|
||||
emit_expr_(os, pp->expr());
|
||||
os << ")";
|
||||
|
||||
} else {
|
||||
os << "(huh?)";
|
||||
}
|
||||
}
|
||||
|
||||
void target_verilog::proc_block(ostream&os, const NetBlock*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "begin" << endl;
|
||||
indent_ += 4;
|
||||
net->emit_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
os << setw(indent_) << "" << "end" << endl;
|
||||
}
|
||||
|
||||
void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "#" << net->delay() << endl;
|
||||
|
||||
indent_ += 4;
|
||||
net->emit_proc_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
}
|
||||
|
||||
void target_verilog::proc_event(ostream&os, const NetPEvent*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "@";
|
||||
|
||||
unsigned sidx;
|
||||
const NetNet*sig = find_link_signal(net, 0, sidx);
|
||||
|
||||
switch (net->edge()) {
|
||||
case NetPEvent::ANYEDGE:
|
||||
os << mangle(sig->name()) << "[" << sidx << "]";
|
||||
break;
|
||||
case NetPEvent::POSEDGE:
|
||||
os << "(posedge " << mangle(sig->name()) << "[" << sidx << "])";
|
||||
break;
|
||||
case NetPEvent::NEGEDGE:
|
||||
os << "(negedge " << mangle(sig->name()) << "[" << sidx << "])";
|
||||
break;
|
||||
}
|
||||
|
||||
os << endl;
|
||||
|
||||
indent_ += 4;
|
||||
net->emit_proc_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
}
|
||||
|
||||
static void vtask_parm(ostream&os, const NetExpr*ex)
|
||||
{
|
||||
if (const NetEConst*pp = dynamic_cast<const NetEConst*>(ex)) {
|
||||
if (pp->value().is_string())
|
||||
os << "\"" << pp->value().as_string() << "\"";
|
||||
else
|
||||
os << pp->value();
|
||||
|
||||
} else if (const NetEIdent*pp = dynamic_cast<const NetEIdent*>(ex)) {
|
||||
os << mangle(pp->name());
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
void target_verilog::proc_task(ostream&os, const NetTask*net)
|
||||
{
|
||||
os << setw(indent_) << "" << net->name();
|
||||
if (net->nparms() > 0) {
|
||||
os << "(";
|
||||
vtask_parm(os, net->parm(0));
|
||||
for (unsigned idx = 1 ; idx < net->nparms() ; idx += 1) {
|
||||
os << ", ";
|
||||
vtask_parm(os, net->parm(idx));
|
||||
}
|
||||
os << ")";
|
||||
}
|
||||
|
||||
os << ";" << endl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* All done with the design. Flush any output that I've been holding
|
||||
* off, and write the footers for the target.
|
||||
*/
|
||||
void target_verilog::end_design(ostream&os, const Design*)
|
||||
{
|
||||
os << "endmodule" << endl;
|
||||
}
|
||||
|
||||
static target_verilog tgt_verilog_obj;
|
||||
|
||||
const struct target tgt_verilog = {
|
||||
"verilog",
|
||||
&tgt_verilog_obj
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: t-verilog.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:05 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: t-vvm.cc,v 1.1 1998/11/03 23:29:05 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <iostream>
|
||||
# include <strstream>
|
||||
# include <string>
|
||||
# include <typeinfo>
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
|
||||
static string make_temp()
|
||||
{
|
||||
static unsigned counter = 0;
|
||||
ostrstream str;
|
||||
str << "TMP" << counter << ends;
|
||||
counter += 1;
|
||||
return str.str();
|
||||
}
|
||||
|
||||
class target_vvm : public target_t {
|
||||
public:
|
||||
virtual void start_design(ostream&os, const Design*);
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void net_pevent(ostream&os, const NetPEvent*);
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
virtual void end_process(ostream&os, const NetProcTop*);
|
||||
virtual void end_design(ostream&os, const Design*);
|
||||
|
||||
private:
|
||||
void emit_gate_outputfun_(const NetNode*);
|
||||
|
||||
ostrstream delayed;
|
||||
unsigned process_counter;
|
||||
unsigned thread_step_;
|
||||
};
|
||||
|
||||
class vvm_proc_rval : public expr_scan_t {
|
||||
|
||||
public:
|
||||
explicit vvm_proc_rval(ostream&os, unsigned width)
|
||||
: result(""), os_(os), width_(width) { }
|
||||
|
||||
string result;
|
||||
|
||||
private:
|
||||
ostream&os_;
|
||||
unsigned width_;
|
||||
|
||||
private:
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_unary(const NetEUnary*);
|
||||
};
|
||||
|
||||
void vvm_proc_rval::expr_const(const NetEConst*expr)
|
||||
{
|
||||
string tname = make_temp();
|
||||
os_ << " vvm_bitset_t<" << width_ << "> " << tname << ";" << endl;
|
||||
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
|
||||
os_ << " " << tname << "[" << idx << "] = ";
|
||||
switch (expr->value().get(idx)) {
|
||||
case verinum::V0:
|
||||
os_ << "V0";
|
||||
break;
|
||||
case verinum::V1:
|
||||
os_ << "V1";
|
||||
break;
|
||||
case verinum::Vx:
|
||||
os_ << "Vx";
|
||||
break;
|
||||
case verinum::Vz:
|
||||
os_ << "Vz";
|
||||
break;
|
||||
}
|
||||
os_ << ";" << endl;
|
||||
}
|
||||
|
||||
result = tname;
|
||||
}
|
||||
|
||||
void vvm_proc_rval::expr_ident(const NetEIdent*expr)
|
||||
{
|
||||
result = mangle(expr->name());
|
||||
}
|
||||
|
||||
void vvm_proc_rval::expr_unary(const NetEUnary*expr)
|
||||
{
|
||||
expr->expr()->expr_scan(this);
|
||||
string tname = make_temp();
|
||||
|
||||
os_ << " vvm_bitset_t<" << width_ << "> " << tname << " = ";
|
||||
switch (expr->op()) {
|
||||
case '~':
|
||||
os_ << "vvm_unop_not(" << result << ");"
|
||||
<< endl;
|
||||
break;
|
||||
default:
|
||||
cerr << "vvm: Unhandled unary op `" << expr->op() << "'"
|
||||
<< endl;
|
||||
os_ << result << ";" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
result = tname;
|
||||
}
|
||||
|
||||
static string emit_proc_rval(ostream&os, unsigned width, const NetExpr*expr)
|
||||
{
|
||||
vvm_proc_rval scan (os, width);
|
||||
expr->expr_scan(&scan);
|
||||
return scan.result;
|
||||
}
|
||||
|
||||
class vvm_parm_rval : public expr_scan_t {
|
||||
|
||||
public:
|
||||
explicit vvm_parm_rval(ostream&os)
|
||||
: result(""), os_(os) { }
|
||||
|
||||
string result;
|
||||
|
||||
private:
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
|
||||
private:
|
||||
ostream&os_;
|
||||
};
|
||||
|
||||
void vvm_parm_rval::expr_const(const NetEConst*expr)
|
||||
{
|
||||
if (expr->value().is_string()) {
|
||||
result = "\"";
|
||||
result = result + expr->value().as_string() + "\"";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void vvm_parm_rval::expr_ident(const NetEIdent*expr)
|
||||
{
|
||||
if (expr->name() == "$time") {
|
||||
string res = make_temp();
|
||||
os_ << " vvm_calltf_parm " << res <<
|
||||
"(vvm_calltf_parm::TIME);" << endl;
|
||||
result = res;
|
||||
} else {
|
||||
string res = make_temp();
|
||||
os_ << " vvm_calltf_parm::SIG " << res << ";" << endl;
|
||||
os_ << " " << res << ".bits = &" <<
|
||||
mangle(expr->name()) << ";" << endl;
|
||||
os_ << " " << res << ".mon = &" <<
|
||||
mangle(expr->name()) << "_mon;" << endl;
|
||||
result = res;
|
||||
}
|
||||
}
|
||||
|
||||
static string emit_parm_rval(ostream&os, const NetExpr*expr)
|
||||
{
|
||||
vvm_parm_rval scan (os);
|
||||
expr->expr_scan(&scan);
|
||||
return scan.result;
|
||||
}
|
||||
|
||||
void target_vvm::start_design(ostream&os, const Design*mod)
|
||||
{
|
||||
os << "# include \"vvm.h\"" << endl;
|
||||
os << "# include \"vvm_gates.h\"" << endl;
|
||||
os << "# include \"vvm_func.h\"" << endl;
|
||||
os << "# include \"vvm_calltf.h\"" << endl;
|
||||
os << "# include \"vvm_thread.h\"" << endl;
|
||||
process_counter = 0;
|
||||
}
|
||||
|
||||
void target_vvm::end_design(ostream&os, const Design*mod)
|
||||
{
|
||||
delayed << ends;
|
||||
os << delayed.str();
|
||||
|
||||
os << "main()" << endl << "{" << endl;
|
||||
os << " vvm_simulation sim;" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < process_counter ; idx += 1)
|
||||
os << " thread" << (idx+1) << "_t thread_" <<
|
||||
(idx+1) << "(&sim);" << endl;
|
||||
|
||||
os << " sim.run();" << endl;
|
||||
os << "}" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::signal(ostream&os, const NetNet*sig)
|
||||
{
|
||||
os << "static vvm_bitset_t<" << sig->pin_count() << "> " <<
|
||||
mangle(sig->name()) << "; /* " << sig->name() << " */" << endl;
|
||||
os << "static vvm_monitor_t " << mangle(sig->name()) << "_mon(\""
|
||||
<< sig->name() << "\");" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method handles writing output functions for gates that have a
|
||||
* single output (at pin 0). This writes the output_fun method into
|
||||
* the delayed stream to be emitted to the output file later.
|
||||
*/
|
||||
void target_vvm::emit_gate_outputfun_(const NetNode*gate)
|
||||
{
|
||||
delayed << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*sim, vvm_bit_t val)" <<
|
||||
endl << "{" << endl;
|
||||
|
||||
/* The output function connects to pin 0 of the netlist part
|
||||
and causes the inputs that it is connected to to be set
|
||||
with the new value. */
|
||||
|
||||
const NetObj*cur;
|
||||
unsigned pin;
|
||||
gate->pin(0).next_link(cur, pin);
|
||||
while (cur != gate) {
|
||||
// Skip signals
|
||||
if (const NetNet*sig = dynamic_cast<const NetNet*>(cur)) {
|
||||
|
||||
delayed << " " << mangle(sig->name()) << "[" <<
|
||||
pin << "] = val;" << endl;
|
||||
delayed << " " << mangle(sig->name()) <<
|
||||
"_mon.trigger(sim);" << endl;
|
||||
|
||||
} else {
|
||||
delayed << " " << mangle(cur->name()) << ".set(sim, "
|
||||
<< pin << ", val);" << endl;
|
||||
}
|
||||
|
||||
cur->pin(pin).next_link(cur, pin);
|
||||
}
|
||||
|
||||
delayed << "}" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::logic(ostream&os, const NetLogic*gate)
|
||||
{
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
|
||||
switch (gate->type()) {
|
||||
case NetLogic::AND:
|
||||
os << "static vvm_and" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->delay1() << "> ";
|
||||
break;
|
||||
case NetLogic::NAND:
|
||||
os << "static vvm_nand" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->delay1() << "> ";
|
||||
break;
|
||||
case NetLogic::NOR:
|
||||
os << "static vvm_nor" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->delay1() << "> ";
|
||||
break;
|
||||
case NetLogic::NOT:
|
||||
os << "static vvm_not" << "<" << gate->delay1() << "> ";
|
||||
break;
|
||||
case NetLogic::OR:
|
||||
os << "static vvm_or" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->delay1() << "> ";
|
||||
break;
|
||||
case NetLogic::XOR:
|
||||
os << "static vvm_xor" << "<" << gate->pin_count()-1 <<
|
||||
"," << gate->delay1() << "> ";
|
||||
break;
|
||||
}
|
||||
|
||||
os << mangle(gate->name()) << "(&" <<
|
||||
mangle(gate->name()) << "_output_fun);" << endl;
|
||||
|
||||
emit_gate_outputfun_(gate);
|
||||
}
|
||||
|
||||
void target_vvm::bufz(ostream&os, const NetBUFZ*gate)
|
||||
{
|
||||
os << "static void " << mangle(gate->name()) <<
|
||||
"_output_fun(vvm_simulation*, vvm_bit_t);" << endl;
|
||||
|
||||
os << "static vvm_bufz " << mangle(gate->name()) << "(&" <<
|
||||
mangle(gate->name()) << "_output_fun);" << endl;
|
||||
|
||||
emit_gate_outputfun_(gate);
|
||||
}
|
||||
|
||||
/*
|
||||
* The net_pevent device is a synthetic device type--a fabrication of
|
||||
* the elaboration phase. An event device receives value changes from
|
||||
* the attached signal. It is an input only device, its only value
|
||||
* being the side-effects that threads waiting on events can be
|
||||
* awakened.
|
||||
*
|
||||
* The proc_event method handles the other half of this, the process
|
||||
* that blocks on the event.
|
||||
*/
|
||||
void target_vvm::net_pevent(ostream&os, const NetPEvent*gate)
|
||||
{
|
||||
os << "static vvm_pevent " << mangle(gate->name()) << ";"
|
||||
" /* " << gate->name() << " */" << endl;
|
||||
}
|
||||
|
||||
void target_vvm::start_process(ostream&os, const NetProcTop*proc)
|
||||
{
|
||||
process_counter += 1;
|
||||
thread_step_ = 0;
|
||||
|
||||
os << "class thread" << process_counter <<
|
||||
"_t : public vvm_thread {" << endl;
|
||||
|
||||
os << " public:" << endl;
|
||||
os << " thread" << process_counter <<
|
||||
"_t(vvm_simulation*sim)" << endl;
|
||||
os << " : vvm_thread(sim), step_(&step_0_)" << endl;
|
||||
os << " { }" << endl;
|
||||
os << " ~thread" << process_counter << "_t() { }" << endl;
|
||||
os << endl;
|
||||
os << " void go() { (this->*step_)(); }" << endl;
|
||||
os << " private:" << endl;
|
||||
os << " void (thread" << process_counter <<
|
||||
"_t::*step_)();" << endl;
|
||||
|
||||
os << " void step_0_() {" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method generates code for a procedural assignment. The lval is
|
||||
* a signal, but the assignment should generate code to go to all the
|
||||
* connected devices/events.
|
||||
*/
|
||||
void target_vvm::proc_assign(ostream&os, const NetAssign*net)
|
||||
{
|
||||
string rval = emit_proc_rval(os, net->lval()->pin_count(), net->rval());
|
||||
|
||||
os << " // " << net->lval()->name() << " = ";
|
||||
net->rval()->dump(os);
|
||||
os << endl;
|
||||
|
||||
os << " " << mangle(net->lval()->name()) << " = " << rval <<
|
||||
";" << endl;
|
||||
|
||||
os << " " << mangle(net->lval()->name()) <<
|
||||
"_mon.trigger(sim_);" << endl;
|
||||
|
||||
|
||||
/* Not only is the lvalue signal assigned to, send the bits to
|
||||
all the other pins that are connected to this signal. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
||||
const NetObj*cur;
|
||||
unsigned pin;
|
||||
for (net->lval()->pin(0).next_link(cur, pin)
|
||||
; cur != net->lval()
|
||||
; cur->pin(pin).next_link(cur, pin)) {
|
||||
|
||||
// Skip NetAssign nodes. They are output-only.
|
||||
if (dynamic_cast<const NetAssign*>(cur))
|
||||
continue;
|
||||
|
||||
if (const NetNet*sig = dynamic_cast<const NetNet*>(cur)) {
|
||||
os << " " << mangle(sig->name()) << "[" <<
|
||||
pin << "] = " << rval << "[" << idx <<
|
||||
"];" << endl;
|
||||
os << " " << mangle(sig->name()) <<
|
||||
"_mon.trigger(sim_);" << endl;
|
||||
|
||||
} else {
|
||||
os << " " << mangle(cur->name()) <<
|
||||
".set(sim_, " << pin << ", " <<
|
||||
rval << "[" << idx << "]);" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void target_vvm::proc_block(ostream&os, const NetBlock*net)
|
||||
{
|
||||
net->emit_recurse(os, this);
|
||||
}
|
||||
|
||||
void target_vvm::proc_task(ostream&os, const NetTask*net)
|
||||
{
|
||||
if (net->name()[0] == '$') {
|
||||
string ptmp = make_temp();
|
||||
os << " struct vvm_calltf_parm " << ptmp << "[" <<
|
||||
net->nparms() << "];" << endl;
|
||||
for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1)
|
||||
if (net->parm(idx)) {
|
||||
string val = emit_parm_rval(os, net->parm(idx));
|
||||
os << " " << ptmp << "[" << idx << "] = " <<
|
||||
val << ";" << endl;
|
||||
}
|
||||
os << " vvm_calltask(sim_, \"" << net->name() << "\", " <<
|
||||
net->nparms() << ", " << ptmp << ");" << endl;
|
||||
} else {
|
||||
os << " // Huh? " << net->name() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Within a process, the proc_event is a statement that is blocked
|
||||
* until the event is signalled.
|
||||
*/
|
||||
void target_vvm::proc_event(ostream&os, const NetPEvent*proc)
|
||||
{
|
||||
thread_step_ += 1;
|
||||
os << " step_ = &step_" << thread_step_ << "_;" << endl;
|
||||
os << " " << mangle(proc->name()) << ".wait(vvm_pevent::";
|
||||
switch (proc->edge()) {
|
||||
case NetPEvent::ANYEDGE:
|
||||
os << "ANYEDGE";
|
||||
break;
|
||||
case NetPEvent::POSEDGE:
|
||||
os << "POSEDGE";
|
||||
break;
|
||||
case NetPEvent::NEGEDGE:
|
||||
os << "NEGEDGE";
|
||||
break;
|
||||
}
|
||||
os << ", this);" << endl;
|
||||
os << " }" << endl;
|
||||
os << " void step_" << thread_step_ << "_()" << endl;
|
||||
os << " {" << endl;
|
||||
|
||||
proc->emit_proc_recurse(os, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* A delay suspends the thread for a period of time.
|
||||
*/
|
||||
void target_vvm::proc_delay(ostream&os, const NetPDelay*proc)
|
||||
{
|
||||
thread_step_ += 1;
|
||||
os << " step_ = &step_" << thread_step_ << "_;" << endl;
|
||||
os << " sim_->thread_delay(" << proc->delay() << ", this);"
|
||||
<< endl;
|
||||
os << " }" << endl;
|
||||
os << " void step_" << thread_step_ << "_()" << endl;
|
||||
os << " {" << endl;
|
||||
|
||||
proc->emit_proc_recurse(os, this);
|
||||
}
|
||||
|
||||
void target_vvm::end_process(ostream&os, const NetProcTop*proc)
|
||||
{
|
||||
if (proc->type() == NetProcTop::KALWAYS) {
|
||||
os << " step_ = &step_0_;" << endl;
|
||||
os << " step_0_(); // XXXX" << endl;
|
||||
} else {
|
||||
os << " step_ = 0;" << endl;
|
||||
}
|
||||
|
||||
os << " }" << endl;
|
||||
os << "};" << endl;
|
||||
}
|
||||
|
||||
|
||||
static target_vvm target_vvm_obj;
|
||||
|
||||
extern const struct target tgt_vvm = {
|
||||
"vvm",
|
||||
&target_vvm_obj
|
||||
};
|
||||
/*
|
||||
* $Log: t-vvm.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:05 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: target.cc,v 1.1 1998/11/03 23:29:06 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
# include <typeinfo>
|
||||
|
||||
target_t::~target_t()
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::start_design(ostream&os, const Design*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::signal(ostream&os, const NetNet*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::logic(ostream&os, const NetLogic*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::bufz(ostream&os, const NetBUFZ*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled continuous assign (BUFZ)." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_assign(ostream&os, const NetAssign*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::net_pevent(ostream&os, const NetPEvent*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled EVENT node." << endl;
|
||||
}
|
||||
|
||||
void target_t::start_process(ostream&os, const NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::proc_assign(ostream&os, const NetAssign*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::proc_block(ostream&os, const NetBlock*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::proc_delay(ostream&os, const NetPDelay*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_delay." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_event." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_task(ostream&os, const NetTask*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::end_process(ostream&os, const NetProcTop*)
|
||||
{
|
||||
}
|
||||
|
||||
void target_t::end_design(ostream&os, const Design*)
|
||||
{
|
||||
}
|
||||
|
||||
expr_scan_t::~expr_scan_t()
|
||||
{
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_const(const NetEConst*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_const." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_ident(const NetEIdent*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_ident." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_unary(const NetEUnary*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_unary." << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: target.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:06 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
#ifndef __target_H
|
||||
#define __target_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)
|
||||
#ident "$Id: target.h,v 1.1 1998/11/03 23:29:06 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
class ostream;
|
||||
|
||||
/*
|
||||
* This header file describes the types and constants used to describe
|
||||
* the possible target output types of the compiler. The backends
|
||||
* provide one of these in order to tell the previous steps what the
|
||||
* backend is able to do.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The backend driver is hooked into the compiler, and given a name,
|
||||
* by creating an instance of the target structure. The structure has
|
||||
* the name that the compiler will use to locate the driver, and a
|
||||
* pointer to a target_t object that is the actual driver.
|
||||
*/
|
||||
struct target {
|
||||
string name;
|
||||
struct target_t* meth;
|
||||
};
|
||||
|
||||
/*
|
||||
* The emit process uses a target_t driver to send the completed
|
||||
* design to a file. It is up to the driver object to follow along in
|
||||
* the iteration through the design, generating output as it can.
|
||||
*/
|
||||
|
||||
struct target_t {
|
||||
virtual ~target_t();
|
||||
|
||||
/* Start the design. */
|
||||
virtual void start_design(ostream&os, const Design*);
|
||||
|
||||
/* Output a signal (called for each signal) */
|
||||
virtual void signal(ostream&os, const NetNet*);
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void net_assign(ostream&os, const NetAssign*);
|
||||
virtual void net_pevent(ostream&os, const NetPEvent*);
|
||||
|
||||
/* Output a process (called for each process) */
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
|
||||
/* Various kinds of process nodes are dispatched through these. */
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_task(ostream&os, const NetTask*);
|
||||
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
|
||||
/* (called for each process) */
|
||||
virtual void end_process(ostream&os, const NetProcTop*);
|
||||
|
||||
/* Done with the design. */
|
||||
virtual void end_design(ostream&os, const Design*);
|
||||
};
|
||||
|
||||
/* This class is used by the NetExpr class to help with the scanning
|
||||
of expressions. */
|
||||
struct expr_scan_t {
|
||||
virtual ~expr_scan_t();
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_ident(const NetEIdent*);
|
||||
virtual void expr_unary(const NetEUnary*);
|
||||
};
|
||||
|
||||
|
||||
/* The emit functions take a design and emit it to the output stream
|
||||
using the specified target. If the target is given by name, it is
|
||||
located in the target_table and used. */
|
||||
extern void emit(ostream&o, const Design*des, const char*type);
|
||||
|
||||
/* This function takes a fully qualified verilog name (which may have,
|
||||
for example, dots in it) and produces a mangled version that can be
|
||||
used by most any language. */
|
||||
extern string mangle(const string&str);
|
||||
|
||||
/* This is the table of supported output targets. It is a null
|
||||
terminated array of pointers to targets. */
|
||||
extern const struct target *target_table[];
|
||||
|
||||
/*
|
||||
* $Log: target.h,v $
|
||||
* Revision 1.1 1998/11/03 23:29:06 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: targets.cc,v 1.1 1998/11/03 23:29:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
|
||||
extern const struct target tgt_verilog;
|
||||
extern const struct target tgt_vvm;
|
||||
const struct target *target_table[] = {
|
||||
&tgt_verilog,
|
||||
&tgt_vvm,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: targets.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:07 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* 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)
|
||||
#ident "$Id: verinum.cc,v 1.1 1998/11/03 23:29:07 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "verinum.h"
|
||||
# include <iostream>
|
||||
# include <cassert>
|
||||
|
||||
verinum::verinum()
|
||||
: bits_(0), nbits_(0), string_flag_(false)
|
||||
{
|
||||
}
|
||||
|
||||
verinum::verinum(const V*bits, unsigned nbits)
|
||||
: string_flag_(false)
|
||||
{
|
||||
nbits_ = nbits;
|
||||
bits_ = new V [nbits];
|
||||
for (unsigned idx = 0 ; idx < nbits ; idx += 1) {
|
||||
bits_[idx] = bits[idx];
|
||||
}
|
||||
}
|
||||
|
||||
verinum::verinum(const string&str)
|
||||
: string_flag_(true)
|
||||
{
|
||||
nbits_ = str.length() * 8;
|
||||
bits_ = new V [nbits_];
|
||||
|
||||
unsigned idx, cp;
|
||||
V*bp = bits_+nbits_;
|
||||
for (idx = nbits_, cp = 0 ; idx > 0 ; idx -= 8, cp += 1) {
|
||||
char ch = str[cp];
|
||||
*(--bp) = (ch&0x80) ? V1 : V0;
|
||||
*(--bp) = (ch&0x40) ? V1 : V0;
|
||||
*(--bp) = (ch&0x20) ? V1 : V0;
|
||||
*(--bp) = (ch&0x10) ? V1 : V0;
|
||||
*(--bp) = (ch&0x08) ? V1 : V0;
|
||||
*(--bp) = (ch&0x04) ? V1 : V0;
|
||||
*(--bp) = (ch&0x02) ? V1 : V0;
|
||||
*(--bp) = (ch&0x01) ? V1 : V0;
|
||||
}
|
||||
}
|
||||
|
||||
verinum::verinum(const verinum&that)
|
||||
{
|
||||
string_flag_ = that.string_flag_;
|
||||
nbits_ = that.nbits_;
|
||||
bits_ = new V[nbits_];
|
||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
|
||||
bits_[idx] = that.bits_[idx];
|
||||
}
|
||||
|
||||
verinum::~verinum()
|
||||
{
|
||||
delete[]bits_;
|
||||
}
|
||||
|
||||
verinum::V verinum::get(unsigned idx) const
|
||||
{
|
||||
return bits_[idx];
|
||||
}
|
||||
|
||||
unsigned long verinum::as_ulong() const
|
||||
{
|
||||
assert(nbits_ <= 8 * sizeof(unsigned long));
|
||||
|
||||
if (nbits_ == 0)
|
||||
return 0;
|
||||
|
||||
unsigned long val = 0;
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
|
||||
val <<= 1;
|
||||
switch (bits_[idx-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
val |= 1;
|
||||
break;
|
||||
case Vx:
|
||||
case Vz:
|
||||
// what should I do here? Throw an exception?
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
signed long verinum::as_long() const
|
||||
{
|
||||
assert(nbits_ <= 8 * sizeof(signed long));
|
||||
|
||||
if (nbits_ == 0)
|
||||
return 0;
|
||||
|
||||
signed long val = 0;
|
||||
|
||||
// Extend the sign bit to fill the long.
|
||||
if (bits_[nbits_-1] == V1)
|
||||
val = -1;
|
||||
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
|
||||
val <<= 1;
|
||||
switch (bits_[idx-1]) {
|
||||
case V0:
|
||||
break;
|
||||
case V1:
|
||||
val |= 1;
|
||||
break;
|
||||
case Vx:
|
||||
case Vz:
|
||||
// what should I do here? Throw an exception?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
string verinum::as_string() const
|
||||
{
|
||||
assert( nbits_%8 == 0 );
|
||||
if (nbits_ == 0)
|
||||
return "";
|
||||
|
||||
char*tmp = new char[nbits_/8+1];
|
||||
char*cp = tmp;
|
||||
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 8, cp += 1) {
|
||||
V*bp = bits_+idx;
|
||||
*cp = 0;
|
||||
if (*(--bp) == V1) *cp |= 0x80;
|
||||
if (*(--bp) == V1) *cp |= 0x40;
|
||||
if (*(--bp) == V1) *cp |= 0x20;
|
||||
if (*(--bp) == V1) *cp |= 0x10;
|
||||
if (*(--bp) == V1) *cp |= 0x08;
|
||||
if (*(--bp) == V1) *cp |= 0x04;
|
||||
if (*(--bp) == V1) *cp |= 0x02;
|
||||
if (*(--bp) == V1) *cp |= 0x01;
|
||||
}
|
||||
|
||||
tmp[nbits_/8] = 0;
|
||||
string result = string(tmp);
|
||||
delete[]tmp;
|
||||
return result;
|
||||
}
|
||||
|
||||
ostream& operator<< (ostream&o, const verinum&v)
|
||||
{
|
||||
o << v.len() << "'b";
|
||||
|
||||
|
||||
verinum::V trim_left = v.get(v.len()-1);
|
||||
unsigned idx;
|
||||
|
||||
for (idx = v.len()-1; idx > 0; idx -= 1)
|
||||
if (trim_left != v.get(idx-1))
|
||||
break;
|
||||
|
||||
switch (trim_left) {
|
||||
case verinum::V0:
|
||||
o << "0";
|
||||
break;
|
||||
case verinum::V1:
|
||||
o << "1";
|
||||
break;
|
||||
case verinum::Vx:
|
||||
o << "x";
|
||||
break;
|
||||
case verinum::Vz:
|
||||
o << "z";
|
||||
break;
|
||||
}
|
||||
|
||||
while (idx > 0) {
|
||||
switch (v.get(idx-1)) {
|
||||
case verinum::V0:
|
||||
o << "0";
|
||||
break;
|
||||
case verinum::V1:
|
||||
o << "1";
|
||||
break;
|
||||
case verinum::Vx:
|
||||
o << "x";
|
||||
break;
|
||||
case verinum::Vz:
|
||||
o << "z";
|
||||
break;
|
||||
}
|
||||
idx -= 1;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: verinum.cc,v $
|
||||
* Revision 1.1 1998/11/03 23:29:07 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
#ifndef __verinum_H
|
||||
#define __verinum_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)
|
||||
#ident "$Id: verinum.h,v 1.1 1998/11/03 23:29:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
||||
/*
|
||||
* Numbers in verlog are multibit strings, where each bit has 4
|
||||
* possible values: 0, 1, x or z. The verinum number is store in
|
||||
* little-endian format. This means that if the long value is 2b'10,
|
||||
* get(0) is 0 and get(1) is 1.
|
||||
*/
|
||||
class verinum {
|
||||
|
||||
public:
|
||||
enum V { V0, V1, Vx, Vz };
|
||||
|
||||
verinum();
|
||||
verinum(const string&str);
|
||||
verinum(const V*v, unsigned nbits);
|
||||
verinum(unsigned long val, unsigned bits);
|
||||
verinum(const verinum&);
|
||||
~verinum();
|
||||
|
||||
// Number of significant bits in this number.
|
||||
unsigned len() const { return nbits_; }
|
||||
|
||||
// Individual bits can be accessed with the get and set
|
||||
// methods.
|
||||
V get(unsigned idx) const;
|
||||
V set(unsigned idx, V val);
|
||||
|
||||
V operator[] (unsigned idx) const { return get(idx); }
|
||||
|
||||
|
||||
unsigned long as_ulong() const;
|
||||
signed long as_long() const;
|
||||
string as_string() const;
|
||||
|
||||
bool is_string() const { return string_flag_; }
|
||||
|
||||
private:
|
||||
V* bits_;
|
||||
unsigned nbits_;
|
||||
|
||||
// These are some convenience flags that help us do a better
|
||||
// job of pretty-printing values.
|
||||
bool string_flag_;
|
||||
|
||||
private: // not implemented
|
||||
verinum& operator= (const verinum&);
|
||||
};
|
||||
|
||||
|
||||
class ostream;
|
||||
ostream& operator<< (ostream&, const verinum&);
|
||||
|
||||
/*
|
||||
* $Log: verinum.h,v $
|
||||
* Revision 1.1 1998/11/03 23:29:08 steve
|
||||
* Introduce verilog to CVS.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
Loading…
Reference in New Issue