Add vvm library.
This commit is contained in:
parent
d189165ae9
commit
8705aa94c6
|
|
@ -0,0 +1 @@
|
|||
dep
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue