vvm_clshift implementation without templates.

This commit is contained in:
steve 2000-03-17 02:22:03 +00:00
parent 5ea3610d4a
commit 8cbf4f815e
4 changed files with 221 additions and 286 deletions

173
t-vvm.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: t-vvm.cc,v 1.110 2000/03/16 23:13:49 steve Exp $"
#ident "$Id: t-vvm.cc,v 1.111 2000/03/17 02:22:03 steve Exp $"
#endif
# include <iostream>
@ -1072,9 +1072,9 @@ void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate)
void target_vvm::lpm_clshift(ostream&os, const NetCLShift*gate)
{
os << "static vvm_clshift<" << gate->width() << "," <<
gate->width_dist() << "> " << mangle(gate->name()) << ";"
<< endl;
os << "static vvm_clshift " << mangle(gate->name()) << "(" <<
gate->width() << "," << gate->width_dist() << ");" <<
endl;
/* Connect the Data input pins... */
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
@ -1370,104 +1370,8 @@ void target_vvm::udp(ostream&os, const NetUDP*gate)
}
/*
* The non-blocking assignment works by creating an event to do the
* assignment at the right time. The value to be assigned is saved in
* the event and the event function performs the actual assignment.
*
* The net part of the assign generates a type ot represent the
* assignment. Creating instances of this event will be dealt with
* later.
*/
void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
{
#ifdef REMOVE_ME_WHEN_NB_ASSIGN_IS_DONE
const string name = mangle(net->name());
unsigned iwid = net->pin_count();
os << "class " << name << " : public vvm_event {" << endl;
os << " public:" << endl;
if (net->bmux()) {
os << " " << name << "(const vvm_bitset_t<"
<< iwid << ">&v, unsigned idx)" << endl;
os << " : value_(v), idx_(idx) { }" << endl;
} else {
os << " " << name << "(const vvm_bits_t&v)"
<< endl;
os << " : value_(v) { }" << endl;
}
os << " void event_function();" << endl;
os << " private:" << endl;
os << " vvm_bitset_t<" << iwid << ">value_;" << endl;
if (net->bmux())
os << " unsigned idx_;" << endl;
os << "};" << endl;
/* Write the event_function to do the actual assignment. */
delayed << "void " << name << "::event_function()" << endl;
delayed << "{" << endl;
if (net->bmux()) {
/* If the assignment is to a single bit (with a mux)
then write a switch statement that selects which pins
to write to. */
delayed << " switch (idx_) {" << endl;
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
const NetObj*cur;
unsigned pin;
delayed << " case " << idx << ":" << endl;
for (net->pin(idx).next_link(cur, pin)
; net->pin(idx) != cur->pin(pin)
; cur->pin(pin).next_link(cur, pin)) {
const NetObj::Link&lnk = cur->pin(pin);
// Skip output only pins.
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
delayed << " " << mangle(cur->name())
<< ".set_" << lnk.get_name()
<< lnk.get_inst() << ", value_[0]);" << endl;
}
delayed << " break;" << endl;
}
delayed << " }" << endl;
} else {
/* If there is no BMUX, then write all the bits of the
value to all the pins. */
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
const NetObj*cur;
unsigned pin;
for (net->pin(idx).next_link(cur, pin)
; net->pin(idx) != cur->pin(pin)
; cur->pin(pin).next_link(cur, pin)) {
const NetObj::Link&lnk = cur->pin(pin);
// Skip output only pins.
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
delayed << " " << mangle(cur->name()) <<
".set_" << lnk.get_name() << "("
<< lnk.get_inst() << ", value_[" <<
idx << "]);" << endl;
}
}
}
delayed << "}" << endl;
#endif
}
void target_vvm::net_case_cmp(ostream&os, const NetCaseCmp*gate)
@ -1597,6 +1501,8 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
if (net->bmux()) {
//XXXX Not updated to nexus style??
// This is a bit select. Assign the low bit of the rval
// to the selected bit of the lval.
string bval = emit_proc_rval(defn, 8, net->bmux());
@ -1637,45 +1543,11 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
defn << " }" << endl;
} else {
#if 0
/* Not only is the lvalue signal assigned to, send the
bits to all the other pins that are connected to this
signal. */
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
const NetObj*cur;
unsigned pin;
map<string,bool> written;
for (net->pin(idx).next_link(cur, pin)
; net->pin(idx) != cur->pin(pin)
; cur->pin(pin).next_link(cur, pin)) {
// Skip output only pins.
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
// It is possible for a named device to show up
// several times in a link. This is the classic
// case with NetESignal objects, which are
// repeated for each expression that uses it.
if (written[cur->name()])
continue;
written[cur->name()] = true;
defn << " " << mangle(cur->name()) <<
".set_" << cur->pin(pin).get_name() <<
"(" << cur->pin(pin).get_inst() <<
", " << rval << "[" << idx << "]);" << endl;
}
}
#else
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&net->pin(idx)));
defn << " " << nexus << "_nex.reg_assign(" <<
rval << "[" << idx << "]);" << endl;
}
#endif
}
}
@ -1713,26 +1585,38 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem)
void target_vvm::proc_assign_nb(ostream&os, const NetAssignNB*net)
{
string rval = emit_proc_rval(defn, 8, net->rval());
const unsigned long delay = net->rise_time();
if (net->bmux()) {
/* If the l-value has a bit select, set the output bit
to only the desired bit. Evaluate the index and use
that to drive a switch statement.
XXXX I'm not fully satisfied with this, I might like
better generating a demux device and doing the assign
to the device input. Food for thought. */
string bval = emit_proc_rval(defn, 8, net->bmux());
defn << " (new " << mangle(net->name()) << "("
<< rval << ", " << bval << ".as_unsigned())) "
<< "-> schedule(" << net->rise_time() << ");" << endl;
defn << " switch (" << bval << ".as_unsigned()) {" << endl;
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&net->pin(idx)));
defn << " case " << idx << ":" << endl;
defn << " vvm_delyed_assign(" << nexus <<
"_nex, " << rval << ", " << delay << ");" << endl;
defn << " break;" << endl;
}
defn << " }" << endl;
} else {
const unsigned long delay = net->rise_time();
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&net->pin(idx)));
defn << " vvm_delayed_assign(" << nexus <<
"_nex, " << rval << "[" << idx << "], " <<
delay << ");" << endl;
}
#ifdef REMOVE_ME_WHEN_NB_ASSIGN_IS_DONE
defn << " (new " << mangle(net->name()) << "("
<< rval << ")) -> schedule(" << net->rise_time() <<
");" << endl;
#endif
}
}
@ -2297,6 +2181,9 @@ extern const struct target tgt_vvm = {
};
/*
* $Log: t-vvm.cc,v $
* Revision 1.111 2000/03/17 02:22:03 steve
* vvm_clshift implementation without templates.
*
* Revision 1.110 2000/03/16 23:13:49 steve
* Update LPM_MUX to nexus style.
*

View File

@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.21 2000/03/16 19:03:04 steve Exp $"
#ident "$Id: Makefile.in,v 1.22 2000/03/17 02:22:03 steve Exp $"
#
#
SHELL = /bin/sh
@ -58,7 +58,8 @@ all: libvvm.a
$(CC) -Wall $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_func.o vvm_gates.o vvm_mult.o \
O = vvm_bit.o vvm_calltf.o vvm_clshift.o vvm_event.o vvm_func.o \
vvm_gates.o vvm_mult.o \
vvm_nexus.o vvm_pevent.o vvm_signal.o vvm_thread.o vpip.o
P = vpi_callback.o \

164
vvm/vvm_clshift.cc Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: vvm_clshift.cc,v 1.1 2000/03/17 02:22:03 steve Exp $"
#endif
# include "vvm_gates.h"
/*
* This is the implementation of the LMP_CLSHIFT device.
*
* The device has input/output width if width_ bits, and a distance
* input of wdist_ bits. The inputs are stored in the ibits_ array,
* the data bits first, then the select bits.
*/
vvm_clshift::vvm_clshift(unsigned wid, unsigned wid_dist)
: width_(wid), wdist_(wid_dist)
{
ibits_ = new vpip_bit_t[width_ + wdist_];
out_ = new vvm_nexus::drive_t[width_];
dist_val_ = width_;
dir_ = V0;
for (unsigned idx = 0 ; idx < width_+wdist_ ; idx += 1)
ibits_[idx] = Vx;
}
vvm_clshift::~vvm_clshift()
{
delete[]out_;
delete[]ibits_;
}
vvm_nexus::drive_t* vvm_clshift::config_rout(unsigned idx)
{
return out_+idx;
}
unsigned vvm_clshift::key_Data(unsigned idx) const
{
return idx;
}
unsigned vvm_clshift::key_Distance(unsigned idx) const
{
return idx+width_;
}
unsigned vvm_clshift::key_Direction(unsigned) const
{
return 0x20000;
}
void vvm_clshift::init_Data(unsigned idx, vpip_bit_t val)
{
ibits_[idx] = val;
}
void vvm_clshift::init_Distance(unsigned idx, vpip_bit_t val)
{
ibits_[width_+idx] = val;
calculate_dist_();
}
void vvm_clshift::init_Direction(unsigned, vpip_bit_t val)
{
dir_ = val;
}
void vvm_clshift::take_value(unsigned key, vpip_bit_t val)
{
if (key == 0x20000) {
if (dir_ == val) return;
dir_ = val;
calculate_dist_();
compute_();
return;
}
if (ibits_[key] == val) return;
ibits_[key] = val;
if (key < width_) {
if ((dist_val_ + key) >= width_) return;
if ((dist_val_ + key) < 0) return;
out_[dist_val_ + key].set_value(val);
} else {
calculate_dist_();
compute_();
}
}
void vvm_clshift::compute_()
{
// The dist_val_ is set to width_ if its value is not fully
// known. In this case, just set the output to unknown.
if (dist_val_ == (int)width_) {
for (unsigned idx = 0 ; idx < width_ ; idx += 1)
out_[idx].set_value(Vx);
return;
}
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
vpip_bit_t val;
if ((idx-dist_val_) >= width_) val = V0;
else if ((idx-dist_val_) < 0) val = V0;
else val = ibits_[idx-dist_val_];
out_[idx].set_value(val);
}
}
void vvm_clshift::calculate_dist_()
{
int tmp = 0;
for (unsigned idx = 0 ; idx < wdist_ ; idx += 1)
switch (ibits_[width_+idx]) {
case V0:
break;
case V1:
tmp |= 1<<idx;
break;
default:
tmp = width_;
}
/* If the shift amount is too large (no matter the direction)
then set it to exactly width_ and the compute_ function
will handle the case directly. Otherwise, turn the shift
amount into a signed value that depends on the direction. */
if (tmp > (int)width_)
tmp = width_;
else if (dir_ == V1)
tmp = -tmp;
dist_val_ = tmp;
}
/*
* $Log: vvm_clshift.cc,v $
* Revision 1.1 2000/03/17 02:22:03 steve
* vvm_clshift implementation without templates.
*
*/

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_gates.h,v 1.40 2000/03/16 23:13:49 steve Exp $"
#ident "$Id: vvm_gates.h,v 1.41 2000/03/17 02:22:03 steve Exp $"
#endif
# include "vvm.h"
@ -182,120 +182,42 @@ class vvm_and : public vvm_1bit_out, public vvm_nexus::recvr_t {
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned WDIST>
/*
* This class implements LPM_CLSHIFT devices with specified data width
* and selector input width. The direction bit is a single bit input.
*/
class vvm_clshift : public vvm_nexus::recvr_t {
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 < WDIST ; idx += 1)
dist_[idx] = Vx;
}
vvm_clshift(unsigned wid, unsigned dwid);
~vvm_clshift();
~vvm_clshift() { }
void init_Data(unsigned idx, vpip_bit_t val);
void init_Distance(unsigned idx, vpip_bit_t val);
void init_Direction(unsigned, vpip_bit_t val);
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_();
}
void init_Direction(unsigned, vpip_bit_t val)
{ dir_ = val; }
vvm_nexus::drive_t* config_rout(unsigned idx);
vvm_nexus::drive_t* config_rout(unsigned idx)
{ return out_+idx; }
unsigned key_Data(unsigned idx) const { return idx; }
unsigned key_Distance(unsigned idx) const { return 0x10000+idx; }
unsigned key_Direction(unsigned) const { return 0x20000; }
unsigned key_Data(unsigned idx) const;
unsigned key_Distance(unsigned idx) const;
unsigned key_Direction(unsigned) const;
private:
void take_value(unsigned key, vpip_bit_t val)
{ unsigned code = key>>16;
unsigned idx = key & 0xffff;
switch (code) {
case 0:
set_Data(idx, val);
break;
case 1:
set_Distance(idx, val);
break;
default:
set_Direction(idx, val);
break;
}
}
void set_Data(unsigned idx, vpip_bit_t val)
{ if (data_[idx] == val) return;
data_[idx] = val;
if ((dist_val_ + idx) >= WIDTH) return;
if ((dist_val_ + idx) < 0) return;
out_[dist_val_+idx].set_value(val);
}
void set_Distance(unsigned idx, vpip_bit_t val)
{ if (dist_[idx] == val) return;
dist_[idx] = val;
calculate_dist_();
compute_();
}
void set_Direction(unsigned, vpip_bit_t val)
{ if (dir_ == val) return;
dir_ = val;
calculate_dist_();
compute_();
}
void take_value(unsigned key, vpip_bit_t val);
private:
unsigned width_, wdist_;
vpip_bit_t dir_;
vpip_bit_t data_[WIDTH];
vpip_bit_t dist_[WDIST];
vvm_nexus::drive_t out_[WIDTH];
int dist_val_;
void calculate_dist_()
{ int tmp = 0;
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
switch (dist_[idx]) {
case V0:
break;
case V1:
tmp |= 1<<idx;
break;
default:
tmp = WIDTH;
}
if (tmp > WIDTH)
tmp = WIDTH;
else if (dir_ == V1)
tmp = -tmp;
dist_val_ = tmp;
}
vpip_bit_t*ibits_;
vvm_nexus::drive_t*out_;
void compute_()
{ vvm_event*ev;
if (dist_val_ == WIDTH) {
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
out_[idx].set_value(Vx);
return;
}
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
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_];
out_[idx].set_value(val);
}
}
void calculate_dist_();
void compute_();
};
template <unsigned WIDTH> class vvm_compare {
public:
@ -1004,6 +926,9 @@ template <unsigned WIDTH> class vvm_pevent : public vvm_nexus::recvr_t {
/*
* $Log: vvm_gates.h,v $
* Revision 1.41 2000/03/17 02:22:03 steve
* vvm_clshift implementation without templates.
*
* Revision 1.40 2000/03/16 23:13:49 steve
* Update LPM_MUX to nexus style.
*
@ -1036,47 +961,5 @@ template <unsigned WIDTH> class vvm_pevent : public vvm_nexus::recvr_t {
*
* Revision 1.31 1999/12/05 02:24:09 steve
* Synthesize LPM_RAM_DQ for writes into memories.
*
* Revision 1.30 1999/12/02 16:58:58 steve
* Update case comparison (Eric Aardoom).
*
* Revision 1.29 1999/12/02 04:54:11 steve
* Handle mux sel of X, if inputs are equal.
*
* Revision 1.28 1999/11/25 01:34:04 steve
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
*
* Revision 1.27 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Revision 1.26 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* 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.
*
* Revision 1.24 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.23 1999/11/15 00:42:31 steve
* Fixup to include right shift support.
*
* Revision 1.22 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
*
* Revision 1.21 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.20 1999/11/14 18:22:12 steve
* Fix NAND gate support to use named pins.
*
* Revision 1.19 1999/11/13 03:46:52 steve
* Support the LPM_MUX in vvm.
*
* 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.
*/
#endif