1998-11-10 00:44:10 +01:00
|
|
|
#ifndef __vvm_gates_H
|
|
|
|
|
#define __vvm_gates_H
|
|
|
|
|
/*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
|
1998-11-10 00:44:10 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2000-02-23 03:56:53 +01:00
|
|
|
#if !defined(WINNT) && !defined(macintosh)
|
2000-02-23 05:43:43 +01:00
|
|
|
#ident "$Id: vvm_gates.h,v 1.37 2000/02/23 04:43:43 steve Exp $"
|
1998-11-10 00:44:10 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "vvm.h"
|
|
|
|
|
# include <assert.h>
|
|
|
|
|
|
1999-11-24 05:38:49 +01:00
|
|
|
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
|
1999-11-22 01:30:52 +01:00
|
|
|
extern vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count);
|
|
|
|
|
extern vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count);
|
|
|
|
|
extern vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count);
|
1999-11-24 05:38:49 +01:00
|
|
|
extern vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count);
|
|
|
|
|
extern vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count);
|
1999-11-22 01:30:52 +01:00
|
|
|
|
1999-12-02 05:54:11 +01:00
|
|
|
extern void compute_mux(vpip_bit_t*out, unsigned wid,
|
|
|
|
|
const vpip_bit_t*sel, unsigned swid,
|
|
|
|
|
const vpip_bit_t*dat, unsigned size);
|
|
|
|
|
|
1998-11-10 00:44:10 +01:00
|
|
|
/*
|
|
|
|
|
* 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:
|
1999-12-12 20:47:54 +01:00
|
|
|
typedef void (*action_t)(vpip_bit_t);
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_out_event(vpip_bit_t v, action_t o);
|
1999-11-22 01:30:52 +01:00
|
|
|
~vvm_out_event();
|
|
|
|
|
|
|
|
|
|
void event_function();
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const action_t output_;
|
1999-10-28 02:47:24 +02:00
|
|
|
const vpip_bit_t val_;
|
1998-11-10 00:44:10 +01:00
|
|
|
};
|
|
|
|
|
|
1999-11-22 01:30:52 +01:00
|
|
|
class vvm_1bit_out {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
|
|
|
|
|
~vvm_1bit_out();
|
1999-12-12 20:47:54 +01:00
|
|
|
void output(vpip_bit_t);
|
1999-11-22 01:30:52 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
unsigned delay_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
/*
|
|
|
|
|
* This template implements the LPM_ADD_SUB device type. The width of
|
1999-10-31 21:08:24 +01:00
|
|
|
* the device is a template parameter. The device handles addition and
|
|
|
|
|
* subtraction, selectable by the Add_Sub input. When configured as a
|
|
|
|
|
* subtractor, the device works by adding the 2s complement of
|
|
|
|
|
* DataB.
|
1999-10-31 05:11:27 +01:00
|
|
|
*/
|
|
|
|
|
template <unsigned WIDTH> class vvm_add_sub {
|
|
|
|
|
|
|
|
|
|
public:
|
1999-12-16 03:42:14 +01:00
|
|
|
vvm_add_sub() : ndir_(V0), co_(0) { }
|
1999-10-31 05:11:27 +01:00
|
|
|
|
|
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t a)
|
|
|
|
|
{ o_[idx] = a;
|
1999-12-16 03:42:14 +01:00
|
|
|
r_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void config_cout(vvm_out_event::action_t a)
|
|
|
|
|
{ co_ = a;
|
|
|
|
|
c_ = Vx;
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_DataA(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ a_[idx] = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_DataB(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ b_[idx] = val;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-31 21:08:24 +01:00
|
|
|
void init_Add_Sub(unsigned, vpip_bit_t val)
|
2000-02-23 05:43:43 +01:00
|
|
|
{ ndir_ = v_not(val);
|
1999-10-31 21:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-16 03:42:14 +01:00
|
|
|
void start() { compute_(); }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_DataA(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ a_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_DataB(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ b_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vpip_bit_t a_[WIDTH];
|
|
|
|
|
vpip_bit_t b_[WIDTH];
|
|
|
|
|
vpip_bit_t r_[WIDTH];
|
1999-12-16 03:42:14 +01:00
|
|
|
vpip_bit_t c_;
|
1999-10-31 05:11:27 +01:00
|
|
|
|
1999-10-31 21:08:24 +01:00
|
|
|
// this is the inverse of the Add_Sub port. It is 0 for add,
|
|
|
|
|
// and 1 for subtract.
|
|
|
|
|
vpip_bit_t ndir_;
|
|
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
vvm_out_event::action_t o_[WIDTH];
|
1999-12-16 03:42:14 +01:00
|
|
|
vvm_out_event::action_t co_;
|
1999-10-31 05:11:27 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void compute_()
|
1999-10-31 21:08:24 +01:00
|
|
|
{ vpip_bit_t carry = ndir_;
|
1999-10-31 05:11:27 +01:00
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
|
|
|
|
vpip_bit_t val;
|
1999-10-31 21:08:24 +01:00
|
|
|
val = add_with_carry(a_[idx], b_[idx] ^ ndir_, carry);
|
1999-10-31 05:11:27 +01:00
|
|
|
if (val == r_[idx]) continue;
|
|
|
|
|
r_[idx] = val;
|
|
|
|
|
if (o_[idx] == 0) continue;
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(val, o_[idx]);
|
|
|
|
|
ev->schedule();
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
1999-12-16 03:42:14 +01:00
|
|
|
if (co_ && (carry != c_))
|
|
|
|
|
(new vvm_out_event(carry, co_)) -> schedule();
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-22 01:30:52 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_and : private vvm_1bit_out {
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_and(vvm_out_event::action_t o)
|
1999-11-22 01:30:52 +01:00
|
|
|
: vvm_1bit_out(o, DELAY) { }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-01-01 02:44:56 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_and(input_,WIDTH)); }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-11-22 01:30:52 +01:00
|
|
|
{ if (input_[idx] == val) return;
|
1999-10-31 05:11:27 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_and(input_,WIDTH));
|
1998-11-10 00:44:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1998-11-10 00:44:10 +01:00
|
|
|
};
|
|
|
|
|
|
1999-11-14 21:24:28 +01:00
|
|
|
template <unsigned WIDTH, unsigned WDIST> class vvm_clshift {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_clshift()
|
|
|
|
|
{ dir_ = V0;
|
|
|
|
|
dist_val_ = WIDTH;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
data_[idx] = Vx;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
out_[idx] = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
|
|
|
|
dist_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~vvm_clshift() { }
|
|
|
|
|
|
|
|
|
|
void init_Data(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ data_[idx] = val;
|
|
|
|
|
}
|
|
|
|
|
void init_Distance(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ dist_[idx] = val;
|
|
|
|
|
calculate_dist_();
|
|
|
|
|
}
|
1999-12-19 21:57:07 +01:00
|
|
|
void init_Direction(unsigned, vpip_bit_t val)
|
1999-11-15 01:42:31 +01:00
|
|
|
{ dir_ = val; }
|
1999-11-14 21:24:28 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Data(unsigned idx, vpip_bit_t val)
|
1999-11-14 21:24:28 +01:00
|
|
|
{ if (data_[idx] == val) return;
|
|
|
|
|
data_[idx] = val;
|
|
|
|
|
if ((dist_val_ + idx) >= WIDTH) return;
|
1999-11-15 01:42:31 +01:00
|
|
|
if ((dist_val_ + idx) < 0) return;
|
1999-11-14 21:24:28 +01:00
|
|
|
vvm_out_event::action_t out = out_[dist_val_+idx];
|
|
|
|
|
if (out == 0) return;
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(val, out);
|
|
|
|
|
ev->schedule();
|
1999-11-14 21:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Distance(unsigned idx, vpip_bit_t val)
|
1999-11-14 21:24:28 +01:00
|
|
|
{ if (dist_[idx] == val) return;
|
|
|
|
|
dist_[idx] = val;
|
|
|
|
|
calculate_dist_();
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-11-14 21:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Direction(unsigned, vpip_bit_t val)
|
1999-11-15 01:42:31 +01:00
|
|
|
{ if (dir_ == val) return;
|
|
|
|
|
dir_ = val;
|
|
|
|
|
calculate_dist_();
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-11-15 01:42:31 +01:00
|
|
|
}
|
|
|
|
|
|
1999-11-14 21:24:28 +01:00
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
|
|
|
|
{ out_[idx] = o;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vpip_bit_t dir_;
|
|
|
|
|
vpip_bit_t data_[WIDTH];
|
|
|
|
|
vpip_bit_t dist_[WDIST];
|
|
|
|
|
vvm_out_event::action_t out_[WIDTH];
|
1999-11-15 01:42:31 +01:00
|
|
|
int dist_val_;
|
1999-11-14 21:24:28 +01:00
|
|
|
|
|
|
|
|
void calculate_dist_()
|
1999-11-15 01:42:31 +01:00
|
|
|
{ int tmp = 0;
|
1999-11-14 21:24:28 +01:00
|
|
|
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
|
|
|
|
|
switch (dist_[idx]) {
|
|
|
|
|
case V0:
|
|
|
|
|
break;
|
|
|
|
|
case V1:
|
|
|
|
|
tmp |= 1<<idx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tmp = WIDTH;
|
|
|
|
|
}
|
1999-11-15 01:42:31 +01:00
|
|
|
if (tmp > WIDTH)
|
|
|
|
|
tmp = WIDTH;
|
|
|
|
|
else if (dir_ == V1)
|
|
|
|
|
tmp = -tmp;
|
1999-11-14 21:24:28 +01:00
|
|
|
dist_val_ = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void compute_()
|
1999-11-14 21:24:28 +01:00
|
|
|
{ vvm_event*ev;
|
|
|
|
|
if (dist_val_ == WIDTH) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
|
|
|
|
if (out_[idx] == 0) continue;
|
1999-12-12 20:47:54 +01:00
|
|
|
ev = new vvm_out_event(Vx, out_[idx]);
|
|
|
|
|
ev->schedule();
|
1999-11-14 21:24:28 +01:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-11-15 01:42:31 +01:00
|
|
|
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
|
1999-11-14 21:24:28 +01:00
|
|
|
if (out_[idx] == 0) continue;
|
1999-11-15 01:42:31 +01:00
|
|
|
vpip_bit_t val;
|
|
|
|
|
if ((idx-dist_val_) >= WIDTH) val = V0;
|
|
|
|
|
else if ((idx-dist_val_) < 0) val = V0;
|
|
|
|
|
else val = data_[idx-dist_val_];
|
1999-12-12 20:47:54 +01:00
|
|
|
ev = new vvm_out_event(val, out_[idx]);
|
|
|
|
|
ev->schedule();
|
1999-11-14 21:24:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-15 00:43:45 +01:00
|
|
|
template <unsigned WIDTH> class vvm_compare {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_compare()
|
|
|
|
|
{ out_lt_ = 0;
|
|
|
|
|
out_le_ = 0;
|
|
|
|
|
gt_ = Vx;
|
|
|
|
|
lt_ = Vx;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
|
|
|
|
a_[idx] = Vx;
|
|
|
|
|
b_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
~vvm_compare() { }
|
|
|
|
|
|
|
|
|
|
void init_DataA(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ a_[idx] = val; }
|
|
|
|
|
void init_DataB(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ b_[idx] = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_DataA(unsigned idx, vpip_bit_t val)
|
1999-11-15 00:43:45 +01:00
|
|
|
{ if (a_[idx] == val) return;
|
|
|
|
|
a_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_DataB(unsigned idx, vpip_bit_t val)
|
1999-11-15 00:43:45 +01:00
|
|
|
{ if (b_[idx] == val) return;
|
|
|
|
|
b_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
compute_();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void config_ALB_out(vvm_out_event::action_t o)
|
|
|
|
|
{ out_lt_ = o; }
|
|
|
|
|
|
|
|
|
|
void config_ALEB_out(vvm_out_event::action_t o)
|
|
|
|
|
{ out_le_ = o; }
|
|
|
|
|
|
|
|
|
|
void config_AGB_out(vvm_out_event::action_t o)
|
|
|
|
|
{ out_gt_ = o; }
|
|
|
|
|
|
|
|
|
|
void config_AGEB_out(vvm_out_event::action_t o)
|
|
|
|
|
{ out_ge_ = o; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vpip_bit_t a_[WIDTH];
|
|
|
|
|
vpip_bit_t b_[WIDTH];
|
|
|
|
|
|
|
|
|
|
vpip_bit_t gt_;
|
|
|
|
|
vpip_bit_t lt_;
|
|
|
|
|
|
|
|
|
|
vvm_out_event::action_t out_lt_;
|
|
|
|
|
vvm_out_event::action_t out_le_;
|
|
|
|
|
vvm_out_event::action_t out_gt_;
|
|
|
|
|
vvm_out_event::action_t out_ge_;
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void compute_()
|
1999-11-15 00:43:45 +01:00
|
|
|
{ vpip_bit_t gt = V0;
|
|
|
|
|
vpip_bit_t lt = V0;
|
|
|
|
|
vvm_event*ev;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
|
|
|
|
gt = greater_with_cascade(a_[idx], b_[idx], gt);
|
|
|
|
|
lt = less_with_cascade(a_[idx], b_[idx], lt);
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-24 05:38:49 +01:00
|
|
|
if ((gt_ == gt) && (lt_ == lt)) return;
|
1999-11-15 00:43:45 +01:00
|
|
|
gt_ = gt;
|
|
|
|
|
lt_ = lt;
|
|
|
|
|
if (out_lt_) {
|
1999-12-12 20:47:54 +01:00
|
|
|
ev = new vvm_out_event(lt_, out_lt_);
|
|
|
|
|
ev->schedule();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
if (out_le_) {
|
2000-02-23 05:43:43 +01:00
|
|
|
ev = new vvm_out_event(v_not(gt_), out_le_);
|
1999-12-12 20:47:54 +01:00
|
|
|
ev->schedule();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
if (out_gt_) {
|
1999-12-12 20:47:54 +01:00
|
|
|
ev = new vvm_out_event(gt_, out_gt_);
|
|
|
|
|
ev->schedule();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
if (out_ge_) {
|
2000-02-23 05:43:43 +01:00
|
|
|
ev = new vvm_out_event(v_not(lt_), out_ge_);
|
1999-12-12 20:47:54 +01:00
|
|
|
ev->schedule();
|
1999-11-15 00:43:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
1999-11-01 03:07:40 +01:00
|
|
|
/*
|
|
|
|
|
* This class simulates the LPM flip-flop device.
|
|
|
|
|
* XXXX Inverted clock not yet supported.
|
|
|
|
|
*/
|
|
|
|
|
template <unsigned WIDTH> class vvm_ff {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_ff()
|
|
|
|
|
{ clk_ = Vx;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
q_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
~vvm_ff() { }
|
|
|
|
|
|
|
|
|
|
void init_Data(unsigned idx, vpip_bit_t val) { d_[idx] = val; }
|
|
|
|
|
void init_Clock(unsigned, vpip_bit_t val) { clk_ = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Clock(unsigned, vpip_bit_t val)
|
1999-11-01 03:07:40 +01:00
|
|
|
{ if (val == clk_) return;
|
|
|
|
|
bool flag = posedge(clk_, val);
|
|
|
|
|
clk_ = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
if (flag) latch_();
|
1999-11-01 03:07:40 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Data(unsigned idx, vpip_bit_t val)
|
1999-11-01 03:07:40 +01:00
|
|
|
{ d_[idx] = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
|
|
|
|
{ out_[idx] = o;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vpip_bit_t d_[WIDTH];
|
|
|
|
|
vpip_bit_t q_[WIDTH];
|
|
|
|
|
vpip_bit_t clk_;
|
|
|
|
|
|
|
|
|
|
vvm_out_event::action_t out_[WIDTH];
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void latch_()
|
1999-11-01 03:07:40 +01:00
|
|
|
{ q_ = d_;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
if (out_[idx]) {
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(q_[idx], out_[idx]);
|
|
|
|
|
ev->schedule();
|
1999-11-01 03:07:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2000-01-13 04:35:35 +01:00
|
|
|
/*
|
|
|
|
|
* This class behaves like a combinational multiplier. The device
|
|
|
|
|
* behaves like the LPM_MULT device.
|
|
|
|
|
*/
|
|
|
|
|
class vvm_mult {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_mult(unsigned rwid, unsigned awid,
|
|
|
|
|
unsigned bwid, unsigned swid);
|
|
|
|
|
~vvm_mult();
|
|
|
|
|
|
|
|
|
|
void init_DataA(unsigned idx, vpip_bit_t val);
|
|
|
|
|
void init_DataB(unsigned idx, vpip_bit_t val);
|
|
|
|
|
void init_Sum(unsigned idx, vpip_bit_t val);
|
|
|
|
|
|
|
|
|
|
void set_DataA(unsigned idx, vpip_bit_t val);
|
|
|
|
|
void set_DataB(unsigned idx, vpip_bit_t val);
|
|
|
|
|
void set_Sum(unsigned idx, vpip_bit_t val);
|
|
|
|
|
|
|
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t o);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
unsigned rwid_;
|
|
|
|
|
unsigned awid_;
|
|
|
|
|
unsigned bwid_;
|
|
|
|
|
unsigned swid_;
|
|
|
|
|
vpip_bit_t*bits_;
|
|
|
|
|
vvm_out_event::action_t*out_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-13 04:46:52 +01:00
|
|
|
/*
|
|
|
|
|
* This class supports mux devices. The width is the width of the data
|
|
|
|
|
* (or bus) path, SIZE is the number of alternative inputs and SELWID
|
|
|
|
|
* is the size (in bits) of the selector input.
|
|
|
|
|
*/
|
|
|
|
|
template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_mux()
|
1999-12-02 05:54:11 +01:00
|
|
|
{ unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < WIDTH ; idx += 1) out_[idx] = 0;
|
|
|
|
|
for (idx = 0 ; idx < WIDTH ; idx += 1) output_[idx] = Vx;
|
|
|
|
|
for (idx = 0 ; idx < SELWID; idx += 1) sel_[idx] = Vx;
|
|
|
|
|
for (idx = 0 ; idx < WIDTH*SIZE; idx += 1) input_[idx] = Vx;
|
1999-11-13 04:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_Sel(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ sel_[idx] = val; }
|
|
|
|
|
|
|
|
|
|
void init_Data(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Sel(unsigned idx, vpip_bit_t val)
|
1999-11-13 04:46:52 +01:00
|
|
|
{ if (sel_[idx] == val) return;
|
|
|
|
|
sel_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
evaluate_();
|
1999-11-13 04:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Data(unsigned idx, vpip_bit_t val)
|
1999-11-13 04:46:52 +01:00
|
|
|
{ if (input_[idx] == val) return;
|
|
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
evaluate_();
|
1999-11-13 04:46:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
|
|
|
|
{ out_[idx] = o; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vpip_bit_t sel_[SELWID];
|
|
|
|
|
vpip_bit_t input_[WIDTH * SIZE];
|
1999-12-02 05:54:11 +01:00
|
|
|
vpip_bit_t output_[WIDTH];
|
|
|
|
|
|
1999-11-13 04:46:52 +01:00
|
|
|
vvm_out_event::action_t out_[WIDTH];
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void evaluate_()
|
1999-12-02 05:54:11 +01:00
|
|
|
{ vpip_bit_t tmp[WIDTH];
|
|
|
|
|
compute_mux(tmp, WIDTH, sel_, SELWID, input_, SIZE);
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
if (tmp[idx] != output_[idx]) {
|
|
|
|
|
output_[idx] = tmp[idx];
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(output_[idx],
|
1999-11-13 04:46:52 +01:00
|
|
|
out_[idx]);
|
1999-12-12 20:47:54 +01:00
|
|
|
ev->schedule();
|
1999-11-13 04:46:52 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-25 02:34:04 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_or : private vvm_1bit_out {
|
1999-06-09 02:58:06 +02:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_or(vvm_out_event::action_t o)
|
1999-11-25 02:34:04 +01:00
|
|
|
: vvm_1bit_out(o,DELAY) { }
|
1999-06-09 02:58:06 +02:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-06-09 02:58:06 +02:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_or(input_,WIDTH)); }
|
1999-06-09 02:58:06 +02:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ if (input_[idx] == val)
|
1999-06-09 02:58:06 +02:00
|
|
|
return;
|
1999-10-31 05:11:27 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_or(input_,WIDTH));
|
1999-06-09 02:58:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1999-06-09 02:58:06 +02:00
|
|
|
};
|
|
|
|
|
|
1999-11-22 01:30:52 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_nor : private vvm_1bit_out {
|
1999-10-09 21:24:36 +02:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_nor(vvm_out_event::action_t o)
|
1999-11-22 01:30:52 +01:00
|
|
|
: vvm_1bit_out(o, DELAY) { }
|
1999-10-09 21:24:36 +02:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-10-09 21:24:36 +02:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_nor(input_,WIDTH)); }
|
1999-10-09 21:24:36 +02:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ if (input_[idx] == val)
|
1999-10-09 21:24:36 +02:00
|
|
|
return;
|
1999-10-31 05:11:27 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_nor(input_,WIDTH));
|
1999-10-09 21:24:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1999-10-09 21:24:36 +02:00
|
|
|
};
|
|
|
|
|
|
1999-12-05 03:24:08 +01:00
|
|
|
/*
|
|
|
|
|
* This object implements a LPM_RAM_DQ device, except for the actual
|
|
|
|
|
* contents of the memory, which are stored in a vvm_memory_t
|
|
|
|
|
* object. Note that there may be many vvm_ram_dq items referencing
|
|
|
|
|
* the same memory.
|
|
|
|
|
*
|
|
|
|
|
* XXXX Only asynchronous reads are supported.
|
|
|
|
|
* XXXX Only *synchronous* writes with WE are supported.
|
|
|
|
|
*/
|
1999-11-21 01:13:08 +01:00
|
|
|
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
|
|
|
|
|
class vvm_ram_dq : protected vvm_ram_callback {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
|
|
|
|
|
: mem_(mem)
|
|
|
|
|
{ mem->set_callback(this);
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
out_[idx] = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
|
|
|
|
|
addr_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_Address(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ addr_[idx] = val; }
|
|
|
|
|
|
1999-12-05 03:24:08 +01:00
|
|
|
void init_Data(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ data_[idx] = val; }
|
|
|
|
|
|
|
|
|
|
void init_WE(unsigned, vpip_bit_t val)
|
|
|
|
|
{ we_ = val; }
|
|
|
|
|
|
|
|
|
|
void init_InClock(unsigned, vpip_bit_t val)
|
|
|
|
|
{ iclk_ = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Address(unsigned idx, vpip_bit_t val)
|
1999-11-21 01:13:08 +01:00
|
|
|
{ if (addr_[idx] == val) return;
|
|
|
|
|
addr_[idx] = val;
|
|
|
|
|
compute_();
|
1999-12-12 20:47:54 +01:00
|
|
|
send_out_();
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_Data(unsigned idx, vpip_bit_t val)
|
1999-12-05 03:24:08 +01:00
|
|
|
{ data_[idx] = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_WE(unsigned, vpip_bit_t val)
|
1999-12-05 03:24:08 +01:00
|
|
|
{ we_ = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_InClock(unsigned, vpip_bit_t val)
|
1999-12-05 03:24:08 +01:00
|
|
|
{ if (val == iclk_) return;
|
|
|
|
|
vpip_bit_t tmp = iclk_;
|
|
|
|
|
iclk_ = val;
|
|
|
|
|
if (we_ != V1) return;
|
1999-12-12 20:47:54 +01:00
|
|
|
if (posedge(tmp, val)) mem_->set_word(addr_val_, data_);
|
1999-12-05 03:24:08 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void handle_write(unsigned idx)
|
|
|
|
|
{ if (idx == addr_val_) send_out_(); }
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
void config_rout(unsigned idx, vvm_out_event::action_t o)
|
|
|
|
|
{ out_[idx] = o; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_memory_t<WIDTH,SIZE>*mem_;
|
1999-12-05 03:24:08 +01:00
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
vpip_bit_t addr_[AWIDTH];
|
1999-12-05 03:24:08 +01:00
|
|
|
vpip_bit_t data_[WIDTH];
|
|
|
|
|
vpip_bit_t we_;
|
|
|
|
|
vpip_bit_t iclk_;
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
vvm_out_event::action_t out_[WIDTH];
|
|
|
|
|
|
|
|
|
|
unsigned long addr_val_;
|
|
|
|
|
|
|
|
|
|
void compute_()
|
|
|
|
|
{ unsigned bit;
|
|
|
|
|
unsigned mask;
|
|
|
|
|
addr_val_ = 0;
|
|
|
|
|
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
|
|
|
|
|
if (addr_[bit] == V1) addr_val_ |= mask;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void send_out_()
|
1999-11-21 01:13:08 +01:00
|
|
|
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
|
|
|
|
|
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
|
|
|
|
|
if (out_[bit]) {
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(ov[bit],
|
1999-11-21 01:13:08 +01:00
|
|
|
out_[bit]);
|
1999-12-12 20:47:54 +01:00
|
|
|
ev->schedule();
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-21 02:16:51 +01:00
|
|
|
template <unsigned long DELAY> class vvm_buf {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_buf(vvm_out_event::action_t o)
|
|
|
|
|
: output_(o)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
void init_I(unsigned, vpip_bit_t) { }
|
1999-12-12 20:47:54 +01:00
|
|
|
void start() { }
|
1999-11-21 02:16:51 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned, vpip_bit_t val)
|
1999-11-21 02:16:51 +01:00
|
|
|
{ vpip_bit_t outval = val;
|
|
|
|
|
if (val == Vz) val = Vx;
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(outval, output_);
|
|
|
|
|
ev->schedule(DELAY);
|
1999-11-21 02:16:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-02-15 06:52:50 +01:00
|
|
|
template <unsigned long DELAY> class vvm_bufif1 {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_bufif1(vvm_out_event::action_t o)
|
|
|
|
|
: output_(o)
|
|
|
|
|
{ input_[0] = Vx;
|
|
|
|
|
input_[1] = Vx;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set(unsigned idx, vpip_bit_t val)
|
1999-02-15 06:52:50 +01:00
|
|
|
{ if (input_[idx-1] == val)
|
|
|
|
|
return;
|
|
|
|
|
input_[idx-1] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(compute_(), output_);
|
|
|
|
|
ev->schedule(DELAY);
|
1999-02-15 06:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
1999-02-15 06:52:50 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[2];
|
1999-02-15 06:52:50 +01:00
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t compute_() const
|
1999-02-15 06:52:50 +01:00
|
|
|
{ if (input_[1] != V1) return Vz;
|
|
|
|
|
if (input_[0] == Vz) return Vx;
|
|
|
|
|
return input_[0];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-25 02:34:04 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_nand : private vvm_1bit_out {
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_nand(vvm_out_event::action_t o)
|
1999-11-25 02:34:04 +01:00
|
|
|
: vvm_1bit_out(o, DELAY) { }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-11-25 02:34:04 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-11-14 19:22:12 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_nand(input_,WIDTH)); }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-11-25 02:34:04 +01:00
|
|
|
{ if (input_[idx] == val) return;
|
1999-11-14 19:22:12 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_nand(input_,WIDTH));
|
1998-11-10 00:44:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1998-11-10 00:44:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Simple inverter buffer.
|
|
|
|
|
*/
|
1999-11-22 01:30:52 +01:00
|
|
|
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_not(vvm_out_event::action_t o)
|
1999-11-22 01:30:52 +01:00
|
|
|
: vvm_1bit_out(o, DELAY) { }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned, vpip_bit_t) { }
|
1999-12-12 20:47:54 +01:00
|
|
|
void start() { }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned, vpip_bit_t val)
|
2000-02-23 05:43:43 +01:00
|
|
|
{ output(v_not(val)); }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
};
|
|
|
|
|
|
1999-11-25 02:34:04 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_xnor : private vvm_1bit_out {
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_xnor(vvm_out_event::action_t o)
|
1999-11-25 02:34:04 +01:00
|
|
|
: vvm_1bit_out(o,DELAY) { }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
|
1999-01-31 19:15:55 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_xnor(input_,WIDTH)); }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ if (input_[idx] == val)
|
1998-11-10 00:44:10 +01:00
|
|
|
return;
|
1999-10-31 05:11:27 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_xnor(input_,WIDTH));
|
1998-11-10 00:44:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1998-11-10 00:44:10 +01:00
|
|
|
};
|
|
|
|
|
|
1999-11-25 02:34:04 +01:00
|
|
|
template <unsigned WIDTH, unsigned long DELAY>
|
|
|
|
|
class vvm_xor : private vvm_1bit_out {
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_xor(vvm_out_event::action_t o)
|
1999-11-25 02:34:04 +01:00
|
|
|
: vvm_1bit_out(o,DELAY) { }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-01-01 02:44:56 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ output(compute_xor(input_,WIDTH)); }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-10-31 05:11:27 +01:00
|
|
|
{ if (input_[idx] == val)
|
1998-11-10 00:44:10 +01:00
|
|
|
return;
|
1999-10-31 05:11:27 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
output(compute_xor(input_,WIDTH)); }
|
1999-01-01 02:44:56 +01:00
|
|
|
|
|
|
|
|
private:
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[WIDTH];
|
1998-11-10 00:44:10 +01:00
|
|
|
};
|
|
|
|
|
|
1999-10-10 03:59:54 +02:00
|
|
|
/*
|
|
|
|
|
* This gate has only 3 pins, the output at pin 0 and two inputs. The
|
|
|
|
|
* output is 1 or 0 if the two inputs are exactly equal or not.
|
|
|
|
|
*/
|
|
|
|
|
template <unsigned long DELAY> class vvm_eeq {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_eeq(vvm_out_event::action_t o)
|
|
|
|
|
: output_(o) { }
|
|
|
|
|
|
1999-12-02 17:58:58 +01:00
|
|
|
void init_I(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ input_[idx] = val; }
|
1999-10-10 03:59:54 +02:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void start()
|
|
|
|
|
{ vvm_event*ev = new vvm_out_event(compute_(), output_);
|
|
|
|
|
ev->schedule(DELAY);
|
1999-10-10 03:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_I(unsigned idx, vpip_bit_t val)
|
1999-12-02 17:58:58 +01:00
|
|
|
{ if (input_[idx] == val)
|
1999-10-10 03:59:54 +02:00
|
|
|
return;
|
1999-12-02 17:58:58 +01:00
|
|
|
input_[idx] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
start();
|
1999-10-10 03:59:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t compute_() const
|
|
|
|
|
{ vpip_bit_t outval = V0;
|
1999-10-10 03:59:54 +02:00
|
|
|
if (input_[0] == input_[1])
|
|
|
|
|
outval = V1;
|
|
|
|
|
return outval;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t input_[2];
|
1999-10-10 03:59:54 +02:00
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
};
|
|
|
|
|
|
1998-12-18 00:54:58 +01:00
|
|
|
/*
|
|
|
|
|
* A Sequential UDP has a more complex truth table, and handles
|
|
|
|
|
* edges. Pin 0 is an output, and all the remaining pins are
|
|
|
|
|
* input. The WIDTH is the number of input pins.
|
|
|
|
|
*
|
|
|
|
|
* See vvm.txt for a description of the gate transition table.
|
|
|
|
|
*/
|
|
|
|
|
template <unsigned WIDTH> class vvm_udp_ssequ {
|
|
|
|
|
|
|
|
|
|
public:
|
1999-10-28 02:47:24 +02:00
|
|
|
explicit vvm_udp_ssequ(vvm_out_event::action_t o, vpip_bit_t i,
|
1998-12-18 00:54:58 +01:00
|
|
|
const vvm_u32*tab)
|
|
|
|
|
: output_(o), table_(tab)
|
|
|
|
|
{ state_[0] = i;
|
|
|
|
|
for (unsigned idx = 1; idx < WIDTH+1 ; idx += 1)
|
|
|
|
|
state_[idx] = Vx;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
void init(unsigned pin, vpip_bit_t val)
|
1998-12-20 03:05:41 +01:00
|
|
|
{ state_[pin] = val; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set(unsigned pin, vpip_bit_t val)
|
1998-12-18 00:54:58 +01:00
|
|
|
{ assert(pin > 0);
|
|
|
|
|
assert(pin < WIDTH+1);
|
|
|
|
|
if (val == Vz) val = Vx;
|
|
|
|
|
if (state_[pin] == val) return;
|
|
|
|
|
// Convert the current state into a table index.
|
|
|
|
|
unsigned entry = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < WIDTH+1 ; idx += 1) {
|
|
|
|
|
entry *= 3;
|
|
|
|
|
entry += state_[idx];
|
|
|
|
|
}
|
|
|
|
|
// Get the table entry, and the 4bits that encode
|
|
|
|
|
// activity on this pin.
|
|
|
|
|
vvm_u32 code = table_[entry];
|
|
|
|
|
code >>= 4 * (WIDTH-pin);
|
|
|
|
|
switch (state_[pin]*4 + val) {
|
|
|
|
|
case (V0*4 + V1):
|
|
|
|
|
case (V1*4 + V0):
|
|
|
|
|
case (Vx*4 + V0):
|
|
|
|
|
code = (code>>2) & 3;
|
|
|
|
|
break;
|
|
|
|
|
case (V0*4 + Vx):
|
|
|
|
|
case (V1*4 + Vx):
|
|
|
|
|
case (Vx*4 + V1):
|
|
|
|
|
code &= 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1999-10-28 02:47:24 +02:00
|
|
|
// Convert the code to a vpip_bit_t and run with it.
|
|
|
|
|
vpip_bit_t outval = (code == 0)? V0 : (code == 1)? V1 : Vx;
|
1998-12-18 00:54:58 +01:00
|
|
|
state_[0] = outval;
|
|
|
|
|
state_[pin] = val;
|
1999-12-12 20:47:54 +01:00
|
|
|
vvm_event*ev = new vvm_out_event(outval, output_);
|
|
|
|
|
ev->schedule(1); // XXXX Delay not supported.
|
1998-12-18 00:54:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
const vvm_u32*const table_;
|
1999-10-28 02:47:24 +02:00
|
|
|
vpip_bit_t state_[WIDTH+1];
|
1998-12-18 00:54:58 +01:00
|
|
|
};
|
|
|
|
|
|
1998-11-10 00:44:10 +01:00
|
|
|
class vvm_bufz {
|
|
|
|
|
public:
|
|
|
|
|
explicit vvm_bufz(vvm_out_event::action_t o)
|
|
|
|
|
: output_(o)
|
|
|
|
|
{ }
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
void init(unsigned idx, vpip_bit_t val) { }
|
1998-12-20 03:05:41 +01:00
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set(unsigned idx, vpip_bit_t val)
|
|
|
|
|
{ output_(val); }
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_out_event::action_t output_;
|
|
|
|
|
};
|
|
|
|
|
|
1999-05-01 04:57:52 +02:00
|
|
|
/*
|
|
|
|
|
* Threads use the vvm_sync to wait for something to happen. This
|
|
|
|
|
* class cooperates with the vvm_pevent class that is the actual gates
|
|
|
|
|
* that receive signals. By handling the suspension and the awakening
|
|
|
|
|
* separately, I can trivially handle event OR expressions.
|
|
|
|
|
*
|
|
|
|
|
* When there is an event expression in the source, the elaborator
|
|
|
|
|
* makes NetNEvent objects, which are approximately represented by the
|
|
|
|
|
* vvm_pevent class.
|
|
|
|
|
*/
|
|
|
|
|
class vvm_sync {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
vvm_sync();
|
|
|
|
|
|
|
|
|
|
void wait(vvm_thread*);
|
1999-12-12 20:47:54 +01:00
|
|
|
void wakeup();
|
1999-05-01 04:57:52 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvm_thread*hold_;
|
|
|
|
|
|
|
|
|
|
private: // not implemented
|
|
|
|
|
vvm_sync(const vvm_sync&);
|
|
|
|
|
vvm_sync& operator= (const vvm_sync&);
|
|
|
|
|
};
|
|
|
|
|
|
1999-05-01 22:43:55 +02:00
|
|
|
template <unsigned WIDTH> class vvm_pevent {
|
1998-11-10 00:44:10 +01:00
|
|
|
public:
|
|
|
|
|
enum EDGE { ANYEDGE, POSEDGE, NEGEDGE };
|
|
|
|
|
|
1999-05-01 22:43:55 +02:00
|
|
|
explicit vvm_pevent(vvm_sync*tgt, EDGE e)
|
|
|
|
|
: target_(tgt), edge_(e)
|
|
|
|
|
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
|
|
|
|
value_[idx] = Vz;
|
|
|
|
|
}
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-05-01 22:43:55 +02:00
|
|
|
vvm_bitset_t<WIDTH> get() const { return value_; }
|
|
|
|
|
|
1999-12-12 20:47:54 +01:00
|
|
|
void set_P(unsigned idx, vpip_bit_t val)
|
1999-05-01 22:43:55 +02:00
|
|
|
{ if (value_[idx] == val) return;
|
|
|
|
|
switch (edge_) {
|
|
|
|
|
case ANYEDGE:
|
1999-12-12 20:47:54 +01:00
|
|
|
target_->wakeup();
|
1999-05-01 22:43:55 +02:00
|
|
|
break;
|
|
|
|
|
case POSEDGE:
|
|
|
|
|
if (val == V1)
|
1999-12-12 20:47:54 +01:00
|
|
|
target_->wakeup();
|
1999-05-01 22:43:55 +02:00
|
|
|
break;
|
|
|
|
|
case NEGEDGE:
|
|
|
|
|
if (val == V0)
|
1999-12-12 20:47:54 +01:00
|
|
|
target_->wakeup();
|
1999-05-01 22:43:55 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
value_[idx] = val;
|
|
|
|
|
}
|
1998-11-10 00:44:10 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
void init_P(int idx, vpip_bit_t val)
|
1999-07-17 05:07:27 +02:00
|
|
|
{ assert(idx < WIDTH);
|
|
|
|
|
value_[idx] = val;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-10 00:44:10 +01:00
|
|
|
private:
|
1999-05-01 04:57:52 +02:00
|
|
|
vvm_sync*target_;
|
1999-05-03 03:51:29 +02:00
|
|
|
vvm_bitset_t<WIDTH> value_;
|
1999-05-01 04:57:52 +02:00
|
|
|
EDGE edge_;
|
1998-11-10 00:44:10 +01:00
|
|
|
|
|
|
|
|
private: // not implemented
|
|
|
|
|
vvm_pevent(const vvm_pevent&);
|
|
|
|
|
vvm_pevent& operator= (const vvm_pevent&);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: vvm_gates.h,v $
|
2000-02-23 05:43:43 +01:00
|
|
|
* Revision 1.37 2000/02/23 04:43:43 steve
|
|
|
|
|
* Some compilers do not accept the not symbol.
|
|
|
|
|
*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Revision 1.36 2000/02/23 02:56:57 steve
|
|
|
|
|
* Macintosh compilers do not support ident.
|
|
|
|
|
*
|
2000-01-13 04:35:35 +01:00
|
|
|
* Revision 1.35 2000/01/13 03:35:35 steve
|
|
|
|
|
* Multiplication all the way to simulation.
|
|
|
|
|
*
|
1999-12-19 21:57:07 +01:00
|
|
|
* Revision 1.34 1999/12/19 20:57:07 steve
|
|
|
|
|
* Proper init_ method prototype.
|
|
|
|
|
*
|
1999-12-16 03:42:14 +01:00
|
|
|
* Revision 1.33 1999/12/16 02:42:15 steve
|
|
|
|
|
* Simulate carry output on adders.
|
|
|
|
|
*
|
1999-12-12 20:47:54 +01:00
|
|
|
* Revision 1.32 1999/12/12 19:47:54 steve
|
|
|
|
|
* Remove the useless vvm_simulation class.
|
|
|
|
|
*
|
1999-12-05 03:24:08 +01:00
|
|
|
* Revision 1.31 1999/12/05 02:24:09 steve
|
|
|
|
|
* Synthesize LPM_RAM_DQ for writes into memories.
|
|
|
|
|
*
|
1999-12-02 17:58:58 +01:00
|
|
|
* Revision 1.30 1999/12/02 16:58:58 steve
|
|
|
|
|
* Update case comparison (Eric Aardoom).
|
|
|
|
|
*
|
1999-12-02 05:54:11 +01:00
|
|
|
* Revision 1.29 1999/12/02 04:54:11 steve
|
|
|
|
|
* Handle mux sel of X, if inputs are equal.
|
|
|
|
|
*
|
1999-11-25 02:34:04 +01:00
|
|
|
* Revision 1.28 1999/11/25 01:34:04 steve
|
|
|
|
|
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
|
|
|
|
|
*
|
1999-11-24 05:38:49 +01:00
|
|
|
* Revision 1.27 1999/11/24 04:38:49 steve
|
|
|
|
|
* LT and GT fixes from Eric Aardoom.
|
|
|
|
|
*
|
1999-11-22 01:30:52 +01:00
|
|
|
* Revision 1.26 1999/11/22 00:30:52 steve
|
|
|
|
|
* Detemplate some and, or and nor methods.
|
|
|
|
|
*
|
1999-11-21 02:16:51 +01:00
|
|
|
* Revision 1.25 1999/11/21 01:16:51 steve
|
|
|
|
|
* Fix coding errors handling names of logic devices,
|
|
|
|
|
* and add support for buf device in vvm.
|
|
|
|
|
*
|
1999-11-21 01:13:08 +01:00
|
|
|
* Revision 1.24 1999/11/21 00:13:09 steve
|
|
|
|
|
* Support memories in continuous assignments.
|
|
|
|
|
*
|
1999-11-15 01:42:31 +01:00
|
|
|
* Revision 1.23 1999/11/15 00:42:31 steve
|
|
|
|
|
* Fixup to include right shift support.
|
|
|
|
|
*
|
1999-11-15 00:43:45 +01:00
|
|
|
* Revision 1.22 1999/11/14 23:43:46 steve
|
|
|
|
|
* Support combinatorial comparators.
|
|
|
|
|
*
|
1999-11-14 21:24:28 +01:00
|
|
|
* Revision 1.21 1999/11/14 20:24:28 steve
|
|
|
|
|
* Add support for the LPM_CLSHIFT device.
|
|
|
|
|
*
|
1999-11-14 19:22:12 +01:00
|
|
|
* Revision 1.20 1999/11/14 18:22:12 steve
|
|
|
|
|
* Fix NAND gate support to use named pins.
|
|
|
|
|
*
|
1999-11-13 04:46:52 +01:00
|
|
|
* Revision 1.19 1999/11/13 03:46:52 steve
|
|
|
|
|
* Support the LPM_MUX in vvm.
|
|
|
|
|
*
|
1999-11-01 03:07:40 +01:00
|
|
|
* Revision 1.18 1999/11/01 02:07:41 steve
|
|
|
|
|
* Add the synth functor to do generic synthesis
|
|
|
|
|
* and add the LPM_FF device to handle rows of
|
|
|
|
|
* flip-flops.
|
1998-11-10 00:44:10 +01:00
|
|
|
*/
|
|
|
|
|
#endif
|