Add vvm library.

This commit is contained in:
steve 1998-11-09 23:44:10 +00:00
parent d189165ae9
commit 8705aa94c6
15 changed files with 1669 additions and 0 deletions

1
vvm/.cvsignore Normal file
View File

@ -0,0 +1 @@
dep

22
vvm/Makefile Normal file
View File

@ -0,0 +1,22 @@
CXXFLAGS = -g
%.o dep/%.d: %.cc
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep
TF = display.o
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
vvm_simulation.o vvm_thread.o $(TF)
libvvm.a: $O
rm -f $@
ar cvqf $@ $O
sample: sample.o libvvm.a
$(CXX) -o sample sample.o libvvm.a
clean:
rm -f *.o dep/*.d
-include $(patsubst %.o, dep/%.d, $O)

205
vvm/display.cc Normal file
View File

@ -0,0 +1,205 @@
/*
* 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: display.cc,v 1.1 1998/11/09 23:44:10 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_calltf.h"
# include <iostream>
static void format_bit(ostream&os, class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::NONE:
cout << "z";
break;
case vvm_calltf_parm::ULONG:
cout << ((parm->as_ulong()&1) ? "0" : "1");
break;
case vvm_calltf_parm::STRING:
cout << parm->as_string();
break;
case vvm_calltf_parm::BITS:
cout << parm->as_bits()->get_bit(0);
break;
}
}
static void format_dec(ostream&os, class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::NONE:
cout << "0";
break;
case vvm_calltf_parm::ULONG:
cout << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
cout << parm->as_string();
break;
case vvm_calltf_parm::BITS: {
unsigned long val = 0;
unsigned long mask = 1;
const vvm_bits_t*bstr = parm->as_bits();
for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) {
if (bstr->get_bit(idx) == V1) val |= mask;
mask <<= 1;
}
cout << val;
break;
}
}
}
static void format_name(ostream&os, class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
os << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
os << "\"" << parm->as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
os << parm->sig_name();
break;
}
}
static unsigned format(const string&str, unsigned nparms,
class vvm_calltf_parm*parms)
{
char prev = 0;
unsigned next_parm = 0;
unsigned idx = 0;
while (idx < str.length()) {
if (prev == '%') {
switch (str[idx]) {
case 'b':
case 'B':
format_bit(cout, parms+next_parm);
next_parm += 1;
break;
case 'd':
case 'D':
format_dec(cout, parms+next_parm);
next_parm += 1;
break;
case 'm':
case 'M':
format_name(cout, parms+next_parm);
next_parm += 1;
break;
case '%':
cout << str[idx];
break;
}
prev = 0;
} else {
if (str[idx] != '%')
cout << str[idx];
else
prev = '%';
}
idx += 1;
}
return next_parm;
}
void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
cout << " ";
break;
case vvm_calltf_parm::TIME:
cout << sim->get_sim_time();
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
idx += format(parms[idx].as_string(),
nparms-idx-1, parms+idx+1);
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
}
cout << endl;
}
class monitor_event : public vvm_event {
public:
monitor_event(vvm_simulation*sim,
unsigned nparms, class vvm_calltf_parm*parms)
{ sim_ = sim;
nparms_ = nparms;
parms_ = new vvm_calltf_parm[nparms];
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
parms_[idx] = parms[idx];
}
~monitor_event() { delete[]parms_; }
private:
vvm_simulation*sim_;
unsigned nparms_;
vvm_calltf_parm*parms_;
void event_function();
};
void monitor_event::event_function()
{
Sdisplay(sim_, "$display", nparms_, parms_);
}
static monitor_event*mon = 0;
void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
if (mon) delete mon;
mon = new monitor_event(sim, nparms, parms);
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (parms[idx].type() != vvm_calltf_parm::BITS)
continue;
parms[idx].as_mon()->enable(mon);
}
}
/*
* $Log: display.cc,v $
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/

221
vvm/vvm.h Normal file
View File

@ -0,0 +1,221 @@
#ifndef __vvm_H
#define __vvm_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: vvm.h,v 1.1 1998/11/09 23:44:10 steve Exp $"
#endif
# include <vector>
# include <string>
/*
* The Verilog Virtual Machine are definitions for the virtual machine
* that executes models that the simulation generator makes.
*/
class vvm_event;
class vvm_simulation;
class vvm_simulation_cycle;
class vvm_thread;
/* The vvm_bit_t is the basic unit of value for a scalar signal in
Verilog. It represents all the possible values. The vvm_bitstring_t
is a vector of vvm_bit_t and is used when variable-length bit
arrays are needed. */
enum vvm_bit_t { V0 = 0, V1, Vx, Vz };
inline vvm_bit_t operator & (vvm_bit_t l, vvm_bit_t r)
{
if (l == V0) return V0;
if (r == V0) return V0;
if ((l == V1) && (r == V1)) return V1;
return Vx;
}
inline vvm_bit_t operator ^ (vvm_bit_t l, vvm_bit_t r)
{
if (l == Vx) return Vx;
if (l == Vz) return Vx;
if (r == Vx) return Vx;
if (r == Vz) return Vx;
if (l == V0) return r;
return (r == V0)? V1 : V0;
}
extern vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry);
inline vvm_bit_t not(vvm_bit_t l)
{
switch (l) {
case V0:
return V1;
case V1:
return V0;
default:
return Vx;
}
}
class vvm_bits_t {
public:
virtual ~vvm_bits_t() =0;
virtual unsigned get_width() const =0;
virtual vvm_bit_t get_bit(unsigned idx) const =0;
};
extern ostream& operator << (ostream&os, const vvm_bits_t&str);
/*
* The vvm_bitset_t is a fixed width array-like set of vvm_bit_t
* items. A number is often times made up of bit sets instead of
* single bits. The fixed array is used when possible because of the
* more thorough type checking and (hopefully) better optimization.
*/
template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
public:
vvm_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
unsigned get_width() const { return WIDTH; }
vvm_bit_t get_bit(unsigned idx) const { return bits_[idx]; }
private:
vvm_bit_t bits_[WIDTH];
};
/*
* Verilog events (update events and nonblocking assign) are derived
* from this abstract class so that the simulation engine can treat
* all of them identically.
*/
class vvm_event {
friend class vvm_simulation;
public:
vvm_event() { }
virtual ~vvm_event() =0;
virtual void event_function() =0;
private:
vvm_event*next_;
private: // not implemented
vvm_event(const vvm_event&);
vvm_event& operator= (const vvm_event&);
};
/*
* This class is the main simulation engine. Object of this type are
* self-contained simulations. Generally, only one is needed.
*/
class vvm_simulation {
public:
vvm_simulation();
~vvm_simulation();
// Take a simulation that has been primed with some initial
// events, and run it. Continue running it until the
// simulation stops. The sim parameter becomes the new list,
// or 0 if the events run out. The simulation clock is
// advanced for the first cycle in sim.
void run();
// Add an event to an existing simulation cycle list. If there
// is not a cycle for the exact delay of the event, create one
// and insert it into the cycle list. Add the event to the
// list of events for the cycle time.
void insert_event(unsigned long delay, vvm_event*event);
// This puts the event in the current active list. No delay.
void active_event(vvm_event*event);
// These are versions of the *_event methods that take
// vvm_thread objects instead.
void thread_delay(unsigned long delay, vvm_thread*);
void thread_active(vvm_thread*);
// Trigger an event as a monitor event causes it to be
// scheduled and executed when the time cycle is
// complete. Unlike other events, the execution of a event so
// scheduled will not cause the event to be deleted. Also,
// only one event can be a monitor.
void monitor_event(vvm_event*);
unsigned long get_sim_time() const { return time_; }
void s_finish();
private:
bool going_;
vvm_simulation_cycle*sim_;
// Triggered monitor event.
vvm_event*mon_;
unsigned long time_;
private: // not implemented
vvm_simulation(const vvm_simulation&);
vvm_simulation& operator= (const vvm_simulation&);
};
/*
* The vvm_monitor_t is usually associated with a vvm_bitset_t that
* represents a signal. The VVM code generator generates calls to the
* trigger method whenever an assignment or output value is set on
* the associated signal. The trigger, if enabled, then causes the
* monitor event to be scheduled in the simulation.
*
* This object also carries the canonical signal name, for the use of
* %m display patterns.
*/
class vvm_monitor_t {
public:
vvm_monitor_t(const string&);
void trigger(vvm_simulation*sim)
{ if (event_) sim->monitor_event(event_); }
const string& name() const { return name_; }
void enable(vvm_event*e) { event_ = e; }
private:
string name_;
vvm_event*event_;
private: // not implemented
vvm_monitor_t(const vvm_monitor_t&);
vvm_monitor_t& operator= (const vvm_monitor_t&);
};
/*
* $Log: vvm.h,v $
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/
#endif

101
vvm/vvm_bit.cc Normal file
View File

@ -0,0 +1,101 @@
/*
* 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: vvm_bit.cc,v 1.1 1998/11/09 23:44:10 steve Exp $"
#endif
# include "vvm.h"
ostream& operator << (ostream&os, const vvm_bits_t&str)
{
os << str.get_width() << "b'";
for (unsigned idx = str.get_width() ; idx > 0 ; idx -= 1)
switch (str.get_bit(idx)) {
case V0:
os << "0";
break;
case V1:
os << "1";
break;
case Vx:
os << "x";
break;
case Vz:
os << "z";
break;
}
return os;
}
vvm_bits_t::~vvm_bits_t()
{
}
vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry)
{
unsigned li, ri, ci;
switch (l) {
case V0:
li = 0;
break;
case V1:
li = 1;
break;
default:
carry = Vx;
return Vx;
}
switch (r) {
case V0:
ri = 0;
break;
case V1:
ri = 1;
break;
default:
carry = Vx;
return Vx;
}
switch (carry) {
case V0:
ci = 0;
break;
case V1:
ci = 1;
break;
default:
carry = Vx;
return Vx;
}
unsigned sum = li + ri + ci;
carry = (sum & 2)? V1 : V0;
return (sum & 1)? V1 : V0;
}
/*
* $Log: vvm_bit.cc,v $
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/

169
vvm/vvm_calltf.cc Normal file
View File

@ -0,0 +1,169 @@
/*
* 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: vvm_calltf.cc,v 1.1 1998/11/09 23:44:10 steve Exp $"
#endif
# include "vvm_calltf.h"
# include <new>
# include <iostream>
# include <assert.h>
vvm_calltf_parm::vvm_calltf_parm()
: type_(NONE)
{
}
vvm_calltf_parm::vvm_calltf_parm(TYPE t)
: type_(t)
{
assert((t == NONE) || (t == TIME));
}
void vvm_calltf_parm::release_()
{
switch (type_) {
case NONE:
case TIME:
case ULONG:
break;
case STRING:
((string*)string_)->string::~string();
break;
case BITS:
break;
}
type_ = NONE;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val)
{
release_();
type_ = ULONG;
ulong_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val)
{
release_();
type_ = STRING;
new (string_) string (val);
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val)
{
release_();
type_ = BITS;
bits_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that)
{
if (this == &that)
return *this;
release_();
switch (that.type_) {
case NONE:
case TIME:
type_ = that.type_;
break;
case ULONG:
type_ = ULONG;
ulong_ = that.ulong_;
break;
case STRING:
type_ = STRING;
new (string_) string (that.as_string());
break;
case BITS:
type_ = BITS;
bits_ = that.bits_;
break;
}
return *this;
}
vvm_calltf_parm::~vvm_calltf_parm()
{
release_();
}
extern void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
extern void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
static void Sfinish(vvm_simulation*sim, const string&,
unsigned, class vvm_calltf_parm*)
{
sim->s_finish();
}
static struct {
const string name;
void (*func)(vvm_simulation*, const string&,
unsigned, class vvm_calltf_parm*);
} sys_table[] = {
{ "$display", &Sdisplay },
{ "$finish", &Sfinish },
{ "$monitor", &Smonitor },
{ "", 0 }
};
void vvm_calltask(vvm_simulation*sim, const string&fname,
unsigned nparms, class vvm_calltf_parm*parms)
{
for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1)
if (fname == sys_table[idx].name) {
sys_table[idx].func(sim, fname, nparms, parms);
return;
}
cout << "Call " << fname << "(";
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (idx > 0) cout << ", ";
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
cout << "\"" << parms[idx].as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
}
}
cout << ")" << endl;
}
/*
* $Log: vvm_calltf.cc,v $
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/

89
vvm/vvm_calltf.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef __vvm_vvm_calltf_H
#define __vvm_vvm_calltf_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: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include <string>
/*
* The vvm environment supports external calls to C++ by
* vvm_calltask. The code generator generates calls to vvm_calltask
* that corresponds to the system call in the Verilog source. The
* vvm_calltask in turn locates the function (by name) and calls the
* C++ code that implements the task.
*
* The parameters of the task are implemented as an array of
* vvm_calltf_parm objects. Each object represents a paramter from the
* source.
*/
class vvm_calltf_parm {
public:
enum TYPE { NONE, ULONG, STRING, BITS, TIME };
vvm_calltf_parm();
explicit vvm_calltf_parm(TYPE);
vvm_calltf_parm(const vvm_calltf_parm&);
~vvm_calltf_parm();
TYPE type() const { return type_; }
struct SIG {
vvm_bits_t*bits;
vvm_monitor_t*mon;
};
unsigned long as_ulong() const { return ulong_; }
string as_string() const { return *(string*)string_; }
vvm_bits_t* as_bits() const { return bits_.bits; }
vvm_monitor_t* as_mon() const { return bits_.mon; }
const string& sig_name() const { return bits_.mon->name(); }
vvm_calltf_parm& operator= (unsigned long);
vvm_calltf_parm& operator= (const string&);
vvm_calltf_parm& operator= (const SIG&);
vvm_calltf_parm& operator= (const vvm_calltf_parm&);
private:
TYPE type_;
union {
unsigned long ulong_;
char string_[sizeof(string)];
SIG bits_;
};
void release_();
};
extern void vvm_calltask(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
/*
* $Log: vvm_calltf.h,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/
#endif

36
vvm/vvm_event.cc Normal file
View File

@ -0,0 +1,36 @@
/*
* 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: vvm_event.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include <assert.h>
vvm_event::~vvm_event()
{
}
/*
* $Log: vvm_event.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/

172
vvm/vvm_func.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef __vvm_vvm_func_H
#define __vvm_vvm_func_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: vvm_func.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
/*
* Implement the unary NOT operator in the verilog way. This takes a
* vector of a certain width and returns a result of the same width.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_unop_not(const vvm_bitset_t<WIDTH>&p)
{
vvm_bitset_t<WIDTH> result;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) switch (p[idx]) {
case V0:
result[idx] = V1;
break;
case V1:
result[idx] = V0;
break;
default:
result[idx] = Vx;
}
return result;
}
/*
* Implement the binary + operator in the verilog way. This takes
* vectors of identical width and returns another vector of same width
* that contains the arithmetic sum. Z values are converted to X.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_plus(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<WIDTH> result;
vvm_bit_t carry = V0;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
result[idx] = add_with_carry(l[idx], r[idx], carry);
return result;
}
/*
* The binary - operator is turned into + by doing 2's complement
* arithmetic. l-r == l+~r+1. The "+1" is accomplished by adding in a
* carry of 1 to the 0 bit position.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_minus(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<WIDTH> res;
res = vvm_unop_not(r);
vvm_bit_t carry = V1;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
res[idx] = add_with_carry(l[idx], res[idx], carry);
return res;
}
/*
* Tests for equality are a bit tricky, as they allow for the left and
* right subexpressions to have different size. The shorter bitset is
* extended with zeros. Also, if there is Vx or Vz anywhere in either
* vectors, the result is Vx.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
if (LW <= RW) {
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
if ((l[idx] == Vx) || (l[idx] == Vz)) {
result[0] = Vx;
return result;
}
if ((r[idx] == Vx) || (r[idx] == Vz)) {
result[0] = Vx;
return result;
}
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = LW ; idx < RW ; idx += 1)
switch (r[idx]) {
case V0:
break;
case V1:
result[0] = V0;
return result;
case Vx:
case Vz:
result[0] = Vx;
return result;
}
return result;
} else {
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
if ((l[idx] == Vx) || (l[idx] == Vz)) {
result[0] = Vx;
return result;
}
if ((r[idx] == Vx) || (r[idx] == Vz)) {
result[0] = Vx;
return result;
}
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = RW ; idx < LW ; idx += 1)
switch (l[idx]) {
case V0:
break;
case V1:
result[0] = V0;
return result;
case Vx:
case Vz:
result[0] = Vx;
return result;
}
return result;
}
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result = vvm_binop_eq(l,r);
result[0] = not(result[0]);
return result;
}
/*
* $Log: vvm_func.h,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/
#endif

225
vvm/vvm_gates.h Normal file
View File

@ -0,0 +1,225 @@
#ifndef __vvm_gates_H
#define __vvm_gates_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: vvm_gates.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include <assert.h>
/*
* A vvm gate is constructed with an input width and an output
* function. The input width represents all the input signals that go
* into generating a single output value. The output value is passed
* to the output function, which may fan the result however makes
* sense. The output is scheduled as an event.
*/
class vvm_out_event : public vvm_event {
public:
typedef void (*action_t)(vvm_simulation*, vvm_bit_t);
vvm_out_event(vvm_simulation*s, vvm_bit_t v, action_t o)
: output_(o), sim_(s), val_(v) { }
void event_function()
{ output_(sim_, val_); }
private:
const action_t output_;
vvm_simulation*const sim_;
const vvm_bit_t val_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
public:
explicit vvm_and(vvm_out_event::action_t o)
: output_(o) { }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
private:
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_nand {
public:
explicit vvm_nand(vvm_out_event::action_t o)
: output_(o)
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
input_[idx] = V0;
}
// Set an input of the NAND gate causes a new output value to
// be calculated and an event generated to make the output
// happen. The input pins are numbered from 1 - WIDTH.
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
vvm_event*ev = new vvm_out_event(sim, not(outval), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
private:
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
/*
* Simple inverter buffer.
* XXXX The WIDTH parameter is useless?
*/
template <unsigned long DELAY> class vvm_not {
public:
explicit vvm_not(vvm_out_event::action_t o)
: output_(o)
{ }
void set(vvm_simulation*sim, unsigned, vvm_bit_t val)
{ vvm_bit_t outval = not(val);
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
private:
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xnor {
public:
explicit vvm_xnor(vvm_out_event::action_t o)
: output_(o) { }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
outval = not(outval);
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
private:
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
public:
explicit vvm_xor(vvm_out_event::action_t o)
: output_(o) { }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vvm_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
private:
vvm_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
class vvm_bufz {
public:
explicit vvm_bufz(vvm_out_event::action_t o)
: output_(o)
{ }
void set(vvm_simulation*sim, unsigned idx, vvm_bit_t val)
{ output_(sim, val); }
private:
vvm_out_event::action_t output_;
};
class vvm_pevent {
public:
enum EDGE { ANYEDGE, POSEDGE, NEGEDGE };
explicit vvm_pevent();
void wait(EDGE, vvm_thread*);
void set(vvm_simulation*sim, unsigned, vvm_bit_t val);
private:
vvm_bit_t value_;
vvm_thread*hold_;
EDGE hold_edge_;
private: // not implemented
vvm_pevent(const vvm_pevent&);
vvm_pevent& operator= (const vvm_pevent&);
};
/*
* $Log: vvm_gates.h,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/
#endif

38
vvm/vvm_monitor.cc Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@picturel.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: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
vvm_monitor_t::vvm_monitor_t(const string&n)
: name_(n)
{
}
/*
* $Log: vvm_monitor.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/

78
vvm/vvm_pevent.cc Normal file
View File

@ -0,0 +1,78 @@
/*
* 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: vvm_pevent.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_gates.h"
vvm_pevent::vvm_pevent()
: value_(V0), hold_(0)
{
}
void vvm_pevent::wait(EDGE edge, vvm_thread*thr)
{
assert(hold_ == 0);
hold_ = thr;
hold_edge_ = edge;
}
void vvm_pevent::set(vvm_simulation*sim, unsigned, vvm_bit_t val)
{
if (hold_ == 0) {
value_ = val;
return;
}
if (value_ != val) {
vvm_thread*tmp;
switch (hold_edge_) {
case ANYEDGE:
tmp = hold_;
hold_ = 0;
sim->thread_active(tmp);
break;
case POSEDGE:
if (val == V1) {
tmp = hold_;
hold_ = 0;
sim->thread_active(tmp);
}
break;
case NEGEDGE:
if (val == V0) {
tmp = hold_;
hold_ = 0;
sim->thread_active(tmp);
}
break;
}
value_ = val;
}
}
/*
* $Log: vvm_pevent.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/

217
vvm/vvm_simulation.cc Normal file
View File

@ -0,0 +1,217 @@
/*
* 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: vvm_simulation.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_thread.h"
# include <assert.h>
/*
* The state of the simulation is stored as a list of simulation
* times. Each simulation time contains the delay to get to it, and
* also a list of events that are to execute here.
*
* The "events" member points to a list of inactive events to be made
* active as a group. Update events go into this list.
*
* The "nonblock" member points to a list of events to be executed
* only after ordinary events run out. This is intended to support the
* semantics of nonblocking assignment.
*/
struct vvm_simulation_cycle {
unsigned long delay;
struct vvm_simulation_cycle*next;
struct vvm_simulation_cycle*prev;
struct vvm_event*event_list;
struct vvm_event*event_last;
struct vvm_event*nonblock_list;
struct vvm_event*nonblock_last;
vvm_simulation_cycle()
: event_list(0), event_last(0), nonblock_list(0),
nonblock_last(0)
{ }
};
vvm_simulation::vvm_simulation()
{
sim_ = new vvm_simulation_cycle;
sim_->delay = 0;
sim_->next = sim_->prev = sim_;
mon_ = 0;
}
vvm_simulation::~vvm_simulation()
{
}
void vvm_simulation::insert_event(unsigned long delay, vvm_event*event)
{
assert(delay > 0);
vvm_simulation_cycle*cur = sim_->next;
while ((cur != sim_) && (cur->delay < delay)) {
delay -= cur->delay;
cur = cur->next;
}
if ((cur == sim_) || (cur->delay > delay)) {
vvm_simulation_cycle*cell = new vvm_simulation_cycle;
cell->delay = delay;
if (cur != sim_)
cur->delay -= delay;
cell->next = cur;
cell->prev = cur->prev;
cell->next->prev = cell;
cell->prev->next = cell;
cur = cell;
}
event->next_ = 0;
if (cur->event_list == 0) {
cur->event_list = cur->event_last = event;
} else {
cur->event_last->next_ = event;
cur->event_last = event;
}
}
void vvm_simulation::monitor_event(vvm_event*event)
{
mon_ = event;
}
void vvm_simulation::active_event(vvm_event*event)
{
event->next_ = 0;
if (sim_->event_list == 0) {
sim_->event_list = sim_->event_last = event;
} else {
sim_->event_last->next_ = event;
sim_->event_last = event;
}
}
/*
* This function takes a list of simulation cycles and runs the
* simulation. It consumes the list as the events are executes,
* eventually deleting everything.
*/
void vvm_simulation::run()
{
assert(sim_);
time_ = 0;
going_ = true;
while (going_) {
/* Step the time forward to the cycle I am about to
execute. */
time_ += sim_->delay;
sim_->delay = 0;
for (;;) {
/* Look for some events to make active. If the
main event list is empty, then activate the
nonblock list. */
vvm_event*active = sim_->event_list;
sim_->event_list = 0;
sim_->event_last = 0;
if (active == 0) {
active = sim_->nonblock_list;
sim_->nonblock_list = 0;
sim_->nonblock_last = 0;
}
/* Oops, no events left. Break out of this time cycle. */
if (active == 0)
break;
while (active) {
vvm_event*cur = active;
active = cur->next_;
cur->event_function();
delete cur;
}
}
/* XXXX Execute monitor events here. */
if (mon_) {
mon_->event_function();
mon_ = 0;
}
/* The time cycle is done, delete it from the list and
step to the next time. */
struct vvm_simulation_cycle*next = sim_->next;
if (next == sim_) {
continue;
}
sim_->next->prev = sim_->prev;
sim_->prev->next = sim_->next;
delete sim_;
sim_ = next;
}
}
class delay_event : public vvm_event {
public:
delay_event(vvm_thread*thr) : thr_(thr) { }
void event_function() { thr_->go(); }
private:
vvm_thread*thr_;
};
void vvm_simulation::s_finish()
{
going_ = false;
}
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
{
assert(delay > 0);
delay_event*ev = new delay_event(thr);
insert_event(delay, ev);
}
void vvm_simulation::thread_active(vvm_thread*thr)
{
delay_event*ev = new delay_event(thr);
active_event(ev);
}
/*
* $Log: vvm_simulation.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/

42
vvm/vvm_thread.cc Normal file
View File

@ -0,0 +1,42 @@
/*
* 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: vvm_thread.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_thread.h"
vvm_thread::vvm_thread(vvm_simulation*sim)
: sim_(sim)
{
sim_->thread_active(this);
}
vvm_thread::~vvm_thread()
{
}
/*
* $Log: vvm_thread.cc,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/

53
vvm/vvm_thread.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef __vvm_thread_H
#define __vvm_thread_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: vvm_thread.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#endif
# include "vvm.h"
/*
* A vvm_thread isn't really a thread in the POSIX sense, but a
* representation of the verilog thread. It is implemented as a state
* machine that performs an action, and possibly changes state, every
* time the go method is called. The events and delays that cause a
* thread to block arrange for the go method to be called in the
* future.
*/
class vvm_thread {
public:
explicit vvm_thread(vvm_simulation*sim);
virtual ~vvm_thread();
virtual void go() =0;
protected:
vvm_simulation*const sim_;
};
/*
* $Log: vvm_thread.h,v $
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
*/
#endif