From 8705aa94c68d1c7053143d072862b88f7832c716 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 9 Nov 1998 23:44:10 +0000 Subject: [PATCH] Add vvm library. --- vvm/.cvsignore | 1 + vvm/Makefile | 22 +++++ vvm/display.cc | 205 ++++++++++++++++++++++++++++++++++++++ vvm/vvm.h | 221 +++++++++++++++++++++++++++++++++++++++++ vvm/vvm_bit.cc | 101 +++++++++++++++++++ vvm/vvm_calltf.cc | 169 +++++++++++++++++++++++++++++++ vvm/vvm_calltf.h | 89 +++++++++++++++++ vvm/vvm_event.cc | 36 +++++++ vvm/vvm_func.h | 172 ++++++++++++++++++++++++++++++++ vvm/vvm_gates.h | 225 ++++++++++++++++++++++++++++++++++++++++++ vvm/vvm_monitor.cc | 38 +++++++ vvm/vvm_pevent.cc | 78 +++++++++++++++ vvm/vvm_simulation.cc | 217 ++++++++++++++++++++++++++++++++++++++++ vvm/vvm_thread.cc | 42 ++++++++ vvm/vvm_thread.h | 53 ++++++++++ 15 files changed, 1669 insertions(+) create mode 100644 vvm/.cvsignore create mode 100644 vvm/Makefile create mode 100644 vvm/display.cc create mode 100644 vvm/vvm.h create mode 100644 vvm/vvm_bit.cc create mode 100644 vvm/vvm_calltf.cc create mode 100644 vvm/vvm_calltf.h create mode 100644 vvm/vvm_event.cc create mode 100644 vvm/vvm_func.h create mode 100644 vvm/vvm_gates.h create mode 100644 vvm/vvm_monitor.cc create mode 100644 vvm/vvm_pevent.cc create mode 100644 vvm/vvm_simulation.cc create mode 100644 vvm/vvm_thread.cc create mode 100644 vvm/vvm_thread.h diff --git a/vvm/.cvsignore b/vvm/.cvsignore new file mode 100644 index 000000000..7b5d7e4bc --- /dev/null +++ b/vvm/.cvsignore @@ -0,0 +1 @@ +dep diff --git a/vvm/Makefile b/vvm/Makefile new file mode 100644 index 000000000..0b16c3170 --- /dev/null +++ b/vvm/Makefile @@ -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) diff --git a/vvm/display.cc b/vvm/display.cc new file mode 100644 index 000000000..e6d44b487 --- /dev/null +++ b/vvm/display.cc @@ -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 + +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. + * + */ + diff --git a/vvm/vvm.h b/vvm/vvm.h new file mode 100644 index 000000000..de73f1499 --- /dev/null +++ b/vvm/vvm.h @@ -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 +# include + +/* + * 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 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 diff --git a/vvm/vvm_bit.cc b/vvm/vvm_bit.cc new file mode 100644 index 000000000..9337fdb9d --- /dev/null +++ b/vvm/vvm_bit.cc @@ -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. + * + */ + diff --git a/vvm/vvm_calltf.cc b/vvm/vvm_calltf.cc new file mode 100644 index 000000000..b81f3399d --- /dev/null +++ b/vvm/vvm_calltf.cc @@ -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 +# include +# include + +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. + * + */ + diff --git a/vvm/vvm_calltf.h b/vvm/vvm_calltf.h new file mode 100644 index 000000000..a09375e0e --- /dev/null +++ b/vvm/vvm_calltf.h @@ -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 + +/* + * 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 diff --git a/vvm/vvm_event.cc b/vvm/vvm_event.cc new file mode 100644 index 000000000..2cc6c1a2d --- /dev/null +++ b/vvm/vvm_event.cc @@ -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 + +vvm_event::~vvm_event() +{ +} + +/* + * $Log: vvm_event.cc,v $ + * Revision 1.1 1998/11/09 23:44:11 steve + * Add vvm library. + * + */ + diff --git a/vvm/vvm_func.h b/vvm/vvm_func.h new file mode 100644 index 000000000..9275a03be --- /dev/null +++ b/vvm/vvm_func.h @@ -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 +vvm_bitset_t vvm_unop_not(const vvm_bitset_t&p) +{ + vvm_bitset_t 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 +vvm_bitset_t vvm_binop_plus(const vvm_bitset_t&l, + const vvm_bitset_t&r) +{ + vvm_bitset_t 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 +vvm_bitset_t vvm_binop_minus(const vvm_bitset_t&l, + const vvm_bitset_t&r) +{ + vvm_bitset_t 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 +vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t&l, + const vvm_bitset_t&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 +vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t&l, + const vvm_bitset_t&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 diff --git a/vvm/vvm_gates.h b/vvm/vvm_gates.h new file mode 100644 index 000000000..97597a5a2 --- /dev/null +++ b/vvm/vvm_gates.h @@ -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 + +/* + * 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 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 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 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 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 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 diff --git a/vvm/vvm_monitor.cc b/vvm/vvm_monitor.cc new file mode 100644 index 000000000..179d34440 --- /dev/null +++ b/vvm/vvm_monitor.cc @@ -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. + * + */ + diff --git a/vvm/vvm_pevent.cc b/vvm/vvm_pevent.cc new file mode 100644 index 000000000..f5454c5ab --- /dev/null +++ b/vvm/vvm_pevent.cc @@ -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. + * + */ + diff --git a/vvm/vvm_simulation.cc b/vvm/vvm_simulation.cc new file mode 100644 index 000000000..421ad286c --- /dev/null +++ b/vvm/vvm_simulation.cc @@ -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 + +/* + * 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. + * + */ + diff --git a/vvm/vvm_thread.cc b/vvm/vvm_thread.cc new file mode 100644 index 000000000..769dcb71a --- /dev/null +++ b/vvm/vvm_thread.cc @@ -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. + * + */ + diff --git a/vvm/vvm_thread.h b/vvm/vvm_thread.h new file mode 100644 index 000000000..205a9dd97 --- /dev/null +++ b/vvm/vvm_thread.h @@ -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