Introduce verilog to CVS.

This commit is contained in:
steve 1998-11-03 23:28:49 +00:00
commit 3fb7a053be
33 changed files with 6268 additions and 0 deletions

5
.cvsignore Normal file
View File

@ -0,0 +1,5 @@
parse.h
parse.cc
parse.cc.output
lexor.cc
vl

30
Makefile Normal file
View File

@ -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)

61
Module.cc Normal file
View File

@ -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.
*
*/

81
Module.h Normal file
View File

@ -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

35
PExpr.cc Normal file
View File

@ -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.
*
*/

144
PExpr.h Normal file
View File

@ -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

136
PGate.h Normal file
View File

@ -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

65
PWire.h Normal file
View File

@ -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

67
Statement.cc Normal file
View File

@ -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.
*
*/

193
Statement.h Normal file
View File

@ -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

323
design_dump.cc Normal file
View File

@ -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.
*
*/

605
elaborate.cc Normal file
View File

@ -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.
*
*/

183
emit.cc Normal file
View File

@ -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.
*
*/

41
eval.cc Normal file
View File

@ -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.
*
*/

426
lexor.lex Normal file
View File

@ -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;
}

152
main.cc Normal file
View 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.
*
*/

57
mangle.cc Normal file
View File

@ -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.
*
*/

242
netlist.cc Normal file
View File

@ -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.
*
*/

594
netlist.h Normal file
View File

@ -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

548
parse.y Normal file
View File

@ -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; }
;

60
parse_misc.cc Normal file
View File

@ -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.
*
*/

60
parse_misc.h Normal file
View File

@ -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

288
pform.cc Normal file
View File

@ -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.
*
*/

127
pform.h Normal file
View File

@ -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

294
pform_dump.cc Normal file
View File

@ -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.
*
*/

81
stupid.cc Normal file
View File

@ -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.
*
*/

298
t-verilog.cc Normal file
View File

@ -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.
*
*/

493
t-vvm.cc Normal file
View File

@ -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.
*
*/

122
target.cc Normal file
View File

@ -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.
*
*/

115
target.h Normal file
View File

@ -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

39
targets.cc Normal file
View File

@ -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.
*
*/

219
verinum.cc Normal file
View File

@ -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.
*
*/

84
verinum.h Normal file
View File

@ -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