Support sequential UDP devices.
This commit is contained in:
parent
2f7ec71a78
commit
77792dcc2f
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: compile.cc,v 1.204 2005/06/02 16:02:11 steve Exp $"
|
||||
#ident "$Id: compile.cc,v 1.205 2005/06/09 04:12:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "arith.h"
|
||||
|
|
@ -1119,8 +1119,13 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
|
|||
void compile_udp_def(int sequ, char *label, char *name,
|
||||
unsigned nin, unsigned init, char **table)
|
||||
{
|
||||
vvp_udp_s *u = new vvp_udp_s(label, name, nin, sequ? true : false);
|
||||
u->compile_table(table);
|
||||
if (sequ) {
|
||||
vvp_udp_seq_s *u = new vvp_udp_seq_s(label, name, nin);
|
||||
u->compile_table(table);
|
||||
} else {
|
||||
vvp_udp_comb_s *u = new vvp_udp_comb_s(label, name, nin);
|
||||
u->compile_table(table);
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
|
||||
|
|
@ -1548,6 +1553,9 @@ void compile_param_string(char*label, char*name, char*str, char*value)
|
|||
|
||||
/*
|
||||
* $Log: compile.cc,v $
|
||||
* Revision 1.205 2005/06/09 04:12:30 steve
|
||||
* Support sequential UDP devices.
|
||||
*
|
||||
* Revision 1.204 2005/06/02 16:02:11 steve
|
||||
* Add support for notif0/1 gates.
|
||||
* Make delay nodes support inertial delay.
|
||||
|
|
|
|||
567
vvp/udp.cc
567
vvp/udp.cc
|
|
@ -20,7 +20,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: udp.cc,v 1.29 2005/04/04 05:13:59 steve Exp $"
|
||||
#ident "$Id: udp.cc,v 1.30 2005/06/09 04:12:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "udp.h"
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static symbol_table_t udp_table;
|
||||
|
||||
|
|
@ -44,38 +44,44 @@ struct vvp_udp_s *udp_find(const char *label)
|
|||
return (struct vvp_udp_s *)v.ptr;
|
||||
}
|
||||
|
||||
vvp_udp_s::vvp_udp_s(char*label, char*name, unsigned ports, bool sequ)
|
||||
vvp_udp_s::vvp_udp_s(char*label, unsigned ports)
|
||||
: ports_(ports)
|
||||
{
|
||||
assert(!sequ); // XXXX sequential UDPs not supported yet.
|
||||
|
||||
if (!udp_table)
|
||||
udp_table = new_symbol_table();
|
||||
|
||||
assert(!udp_find(label));
|
||||
assert( !udp_find(label) );
|
||||
|
||||
symbol_value_t v;
|
||||
v.ptr = this;
|
||||
sym_set_value(udp_table, label, v);
|
||||
}
|
||||
|
||||
vvp_udp_s::~vvp_udp_s()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned vvp_udp_s::port_count() const
|
||||
{
|
||||
return ports_;
|
||||
}
|
||||
|
||||
vvp_udp_comb_s::vvp_udp_comb_s(char*label, char*name, unsigned ports)
|
||||
: vvp_udp_s(label, ports)
|
||||
{
|
||||
name_ = name;
|
||||
ports_ = ports;
|
||||
levels0_ = 0;
|
||||
levels1_ = 0;
|
||||
nlevels0_ = 0;
|
||||
nlevels1_ = 0;
|
||||
}
|
||||
|
||||
vvp_udp_s::~vvp_udp_s()
|
||||
vvp_udp_comb_s::~vvp_udp_comb_s()
|
||||
{
|
||||
if (levels0_) delete[] levels0_;
|
||||
if (levels1_) delete[] levels1_;
|
||||
}
|
||||
|
||||
unsigned vvp_udp_s::port_count() const
|
||||
{
|
||||
return ports_;
|
||||
}
|
||||
|
||||
/*
|
||||
* The cur table that is passed in must have for every valid bit
|
||||
* position exactly one of the three mask bits set. This represents an
|
||||
|
|
@ -94,8 +100,14 @@ unsigned vvp_udp_s::port_count() const
|
|||
* the three bit positions is set in the cur input table, the bit
|
||||
* position will generate a match.
|
||||
*/
|
||||
vvp_bit4_t vvp_udp_s::test_levels(const udp_levels_table&cur)
|
||||
vvp_bit4_t vvp_udp_comb_s::test_levels(const udp_levels_table&cur)
|
||||
{
|
||||
/* To test for a row match, test that the mask0, mask1 and
|
||||
maskx vectors all have bits set where the matching
|
||||
cur.mask0/1/x vectors have bits set. It is possible that a
|
||||
levels0_[idx] vector has more bits set then the cur mask,
|
||||
but this is OK and these bits are to be ignored. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < nlevels0_ ; idx += 1) {
|
||||
if (cur.mask0 != (cur.mask0 & levels0_[idx].mask0))
|
||||
continue;
|
||||
|
|
@ -121,15 +133,57 @@ vvp_bit4_t vvp_udp_s::test_levels(const udp_levels_table&cur)
|
|||
return BIT4_X;
|
||||
}
|
||||
|
||||
void vvp_udp_s::compile_table(char**tab)
|
||||
vvp_bit4_t vvp_udp_comb_s::calculate_output(const udp_levels_table&cur,
|
||||
const udp_levels_table&,
|
||||
vvp_bit4_t)
|
||||
{
|
||||
return test_levels(cur);
|
||||
}
|
||||
|
||||
static void or_based_on_char(udp_levels_table&cur, char flag,
|
||||
unsigned long mask_bit)
|
||||
{
|
||||
switch (flag) {
|
||||
case '0':
|
||||
cur.mask0 |= mask_bit;
|
||||
break;
|
||||
case '1':
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'x':
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'b':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'l':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'h':
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case '?':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_udp_comb_s::compile_table(char**tab)
|
||||
{
|
||||
unsigned nrows0 = 0, nrows1 = 0;
|
||||
|
||||
/* First run through the table to figure out the number of
|
||||
rows I need for each kind of table. */
|
||||
for (unsigned idx = 0 ; tab[idx] ; idx += 1) {
|
||||
assert(strlen(tab[idx]) == ports_ + 1);
|
||||
switch (tab[idx][ports_]) {
|
||||
assert(strlen(tab[idx]) == port_count() + 1);
|
||||
switch (tab[idx][port_count()]) {
|
||||
case '0':
|
||||
nrows0 += 1;
|
||||
break;
|
||||
|
|
@ -156,42 +210,13 @@ void vvp_udp_s::compile_table(char**tab)
|
|||
cur.mask0 = 0;
|
||||
cur.mask1 = 0;
|
||||
cur.maskx = 0;
|
||||
assert(ports_ <= sizeof(cur.mask0));
|
||||
for (unsigned pp = 0 ; pp < ports_ ; pp += 1) {
|
||||
assert(port_count() <= sizeof(cur.mask0));
|
||||
for (unsigned pp = 0 ; pp < port_count() ; pp += 1) {
|
||||
unsigned long mask_bit = 1UL << pp;
|
||||
switch (tab[idx][pp]) {
|
||||
case '0':
|
||||
cur.mask0 |= mask_bit;
|
||||
break;
|
||||
case '1':
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'x':
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'b':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'l':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'h':
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case '?':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
or_based_on_char(cur, tab[idx][pp], mask_bit);
|
||||
}
|
||||
|
||||
switch (tab[idx][ports_]) {
|
||||
switch (tab[idx][port_count()]) {
|
||||
case '0':
|
||||
levels0_[nrows0++] = cur;
|
||||
break;
|
||||
|
|
@ -207,6 +232,441 @@ void vvp_udp_s::compile_table(char**tab)
|
|||
assert(nrows1 == nlevels1_);
|
||||
}
|
||||
|
||||
vvp_udp_seq_s::vvp_udp_seq_s(char*label, char*name, unsigned ports)
|
||||
: vvp_udp_s(label, ports)
|
||||
{
|
||||
levels0_ = 0;
|
||||
levels1_ = 0;
|
||||
levelsx_ = 0;
|
||||
levelsL_ = 0;
|
||||
|
||||
nlevels0_ = 0;
|
||||
nlevels1_ = 0;
|
||||
nlevelsx_ = 0;
|
||||
nlevelsL_ = 0;
|
||||
|
||||
edges0_ = 0;
|
||||
edges1_ = 0;
|
||||
edgesL_ = 0;
|
||||
|
||||
nedges0_ = 0;
|
||||
nedges1_ = 0;
|
||||
nedgesL_ = 0;
|
||||
}
|
||||
|
||||
vvp_udp_seq_s::~vvp_udp_seq_s()
|
||||
{
|
||||
if (levels0_) delete[]levels0_;
|
||||
if (levels1_) delete[]levels1_;
|
||||
if (levelsx_) delete[]levelsx_;
|
||||
if (levelsL_) delete[]levelsL_;
|
||||
if (edges0_) delete[]edges0_;
|
||||
if (edges1_) delete[]edges1_;
|
||||
if (edgesL_) delete[]edgesL_;
|
||||
}
|
||||
|
||||
void edge_based_on_char(struct udp_edges_table&cur, char chr, unsigned pos)
|
||||
{
|
||||
unsigned long mask_bit = 1 << pos;
|
||||
|
||||
switch (chr) {
|
||||
case '0':
|
||||
cur.mask0 |= mask_bit;
|
||||
break;
|
||||
case '1':
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'x':
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'b':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case 'l':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
break;
|
||||
case 'h':
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
case '?':
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.maskx |= mask_bit;
|
||||
cur.mask1 |= mask_bit;
|
||||
break;
|
||||
|
||||
case 'f': // (10) edge
|
||||
cur.mask0 |= mask_bit;
|
||||
cur.edge_position = pos;
|
||||
cur.edge_mask0 = 0;
|
||||
cur.edge_maskx = 0;
|
||||
cur.edge_mask1 = 1;
|
||||
break;
|
||||
case 'q': // (bx) edge
|
||||
cur.maskx |= mask_bit;
|
||||
cur.edge_position = pos;
|
||||
cur.edge_mask0 = 1;
|
||||
cur.edge_maskx = 0;
|
||||
cur.edge_mask1 = 1;
|
||||
break;
|
||||
case 'r': // (01) edge
|
||||
cur.mask1 |= mask_bit;
|
||||
cur.edge_position = pos;
|
||||
cur.edge_mask0 = 1;
|
||||
cur.edge_maskx = 0;
|
||||
cur.edge_mask1 = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_udp_seq_s::compile_table(char**tab)
|
||||
{
|
||||
|
||||
for (unsigned idx = 0 ; tab[idx] ; idx += 1) {
|
||||
const char*row = tab[idx];
|
||||
assert(strlen(row) == port_count() + 2);
|
||||
|
||||
if (strspn(row, "01xblh?") >= port_count()+1) {
|
||||
|
||||
switch (row[port_count()+1]) {
|
||||
case '0':
|
||||
nlevels0_ += 1;
|
||||
break;
|
||||
case '1':
|
||||
nlevels1_ += 1;
|
||||
break;
|
||||
case 'x':
|
||||
nlevelsx_ += 1;
|
||||
break;
|
||||
case '-':
|
||||
nlevelsL_ += 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch (row[port_count()+1]) {
|
||||
case '0':
|
||||
nedges0_ += 1;
|
||||
break;
|
||||
case '1':
|
||||
nedges1_ += 1;
|
||||
break;
|
||||
case 'x':
|
||||
break;
|
||||
case '-':
|
||||
nedgesL_ += 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
levels0_ = new udp_levels_table[nlevels0_];
|
||||
levels1_ = new udp_levels_table[nlevels1_];
|
||||
levelsx_ = new udp_levels_table[nlevelsx_];
|
||||
levelsL_ = new udp_levels_table[nlevelsL_];
|
||||
edges0_ = new udp_edges_table[nedges0_];
|
||||
edges1_ = new udp_edges_table[nedges1_];
|
||||
edgesL_ = new udp_edges_table[nedgesL_];
|
||||
|
||||
unsigned idx_lev0 = 0;
|
||||
unsigned idx_lev1 = 0;
|
||||
unsigned idx_levx = 0;
|
||||
unsigned idx_levL = 0;
|
||||
unsigned idx_edg0 = 0;
|
||||
unsigned idx_edg1 = 0;
|
||||
unsigned idx_edgL = 0;
|
||||
|
||||
for (unsigned idx = 0 ; tab[idx] ; idx += 1) {
|
||||
const char*row = tab[idx];
|
||||
|
||||
if (strspn(row, "01xblh?") >= port_count()+1) {
|
||||
struct udp_levels_table cur;
|
||||
cur.mask0 = 0;
|
||||
cur.mask1 = 0;
|
||||
cur.maskx = 0;
|
||||
for (unsigned pp = 0 ; pp < port_count() ; pp += 1) {
|
||||
unsigned long mask_bit = 1UL << pp;
|
||||
or_based_on_char(cur, row[pp+1], mask_bit);
|
||||
}
|
||||
|
||||
or_based_on_char(cur, row[0], 1UL << port_count());
|
||||
|
||||
switch (row[port_count()+1]) {
|
||||
case '0':
|
||||
levels0_[idx_lev0++] = cur;
|
||||
break;
|
||||
case '1':
|
||||
levels1_[idx_lev1++] = cur;
|
||||
break;
|
||||
case 'x':
|
||||
levelsx_[idx_levx++] = cur;
|
||||
break;
|
||||
case '-':
|
||||
levelsL_[idx_levL++] = cur;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct udp_edges_table cur;
|
||||
cur.mask0 = 0;
|
||||
cur.mask1 = 0;
|
||||
cur.maskx = 0;
|
||||
cur.edge_position = 0;
|
||||
cur.edge_mask0 = 0;
|
||||
cur.edge_mask1 = 0;
|
||||
cur.edge_maskx = 0;
|
||||
|
||||
for (unsigned pp = 0 ; pp < port_count() ; pp += 1) {
|
||||
edge_based_on_char(cur, row[pp+1], pp);
|
||||
}
|
||||
edge_based_on_char(cur, row[0], port_count());
|
||||
|
||||
switch (row[port_count()+1]) {
|
||||
case '0':
|
||||
edges0_[idx_edg0++] = cur;
|
||||
break;
|
||||
case '1':
|
||||
edges1_[idx_edg1++] = cur;
|
||||
break;
|
||||
case 'x':
|
||||
break;
|
||||
case '-':
|
||||
edgesL_[idx_edgL++] = cur;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vvp_bit4_t vvp_udp_seq_s::calculate_output(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev,
|
||||
vvp_bit4_t cur_out)
|
||||
{
|
||||
udp_levels_table cur_tmp = cur;
|
||||
|
||||
unsigned long mask_out = 1UL << port_count();
|
||||
switch (cur_out) {
|
||||
case BIT4_0:
|
||||
cur_tmp.mask0 |= mask_out;
|
||||
break;
|
||||
case BIT4_1:
|
||||
cur_tmp.mask1 |= mask_out;
|
||||
break;
|
||||
default:
|
||||
cur_tmp.maskx |= mask_out;
|
||||
break;
|
||||
}
|
||||
|
||||
vvp_bit4_t lev = test_levels_(cur_tmp);
|
||||
if (lev == BIT4_Z) {
|
||||
lev = test_edges_(cur_tmp, prev);
|
||||
}
|
||||
|
||||
return lev;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function tests the levels of the input with the additional
|
||||
* check match for the current output. It uses this to calculate a
|
||||
* next output, or Z if there was no match. (This is different from
|
||||
* the combinational version of this function, which returns X for the
|
||||
* cases that don't match.) This method assumes that the caller has
|
||||
* set the mask bit in bit postion [port_count()] to reflect the
|
||||
* current output.
|
||||
*/
|
||||
vvp_bit4_t vvp_udp_seq_s::test_levels_(const udp_levels_table&cur)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nlevels0_ ; idx += 1) {
|
||||
if (cur.mask0 != (cur.mask0 & levels0_[idx].mask0))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & levels0_[idx].mask1))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & levels0_[idx].maskx))
|
||||
continue;
|
||||
|
||||
return BIT4_0;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nlevels1_ ; idx += 1) {
|
||||
if (cur.mask0 != (cur.mask0 & levels1_[idx].mask0))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & levels1_[idx].mask1))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & levels1_[idx].maskx))
|
||||
continue;
|
||||
|
||||
return BIT4_1;
|
||||
}
|
||||
|
||||
/* We need to test against an explicit X-output table, since
|
||||
we need to distinguish from an X output and no match. */
|
||||
for (unsigned idx = 0 ; idx < nlevelsx_ ; idx += 1) {
|
||||
if (cur.mask0 != (cur.mask0 & levelsx_[idx].mask0))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & levelsx_[idx].mask1))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & levelsx_[idx].maskx))
|
||||
continue;
|
||||
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
/* Test the table that requests the next output be the same as
|
||||
the current output. This gets the current output from the
|
||||
levels table that was passed in. */
|
||||
for (unsigned idx = 0 ; idx < nlevelsL_ ; idx += 1) {
|
||||
if (cur.mask0 != (cur.mask0 & levelsL_[idx].mask0))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & levelsL_[idx].mask1))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & levelsL_[idx].maskx))
|
||||
continue;
|
||||
|
||||
if (cur.mask0 & (1 << port_count()))
|
||||
return BIT4_0;
|
||||
if (cur.mask1 & (1 << port_count()))
|
||||
return BIT4_1;
|
||||
if (cur.maskx & (1 << port_count()))
|
||||
return BIT4_X;
|
||||
|
||||
assert(0);
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
/* No explicit levels entry match. Return a Z to signal that
|
||||
further testing is needed. */
|
||||
return BIT4_Z;
|
||||
}
|
||||
|
||||
vvp_bit4_t vvp_udp_seq_s::test_edges_(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev)
|
||||
{
|
||||
/* The edge_mask is true for all bits that are different in
|
||||
the cur and prev tables. */
|
||||
unsigned long edge0_mask = cur.mask0 ^ prev.mask0;
|
||||
unsigned long edgex_mask = cur.maskx ^ prev.maskx;
|
||||
unsigned long edge1_mask = cur.mask1 ^ prev.mask1;
|
||||
|
||||
unsigned long edge_mask = edge0_mask|edgex_mask|edge1_mask;
|
||||
edge_mask &= ~ (-1UL << port_count());
|
||||
|
||||
/* If there are no differences, then there are no edges. Give
|
||||
up now. */
|
||||
if (edge_mask == 0)
|
||||
return BIT4_X;
|
||||
|
||||
unsigned edge_position = 0;
|
||||
while ((edge_mask&1) == 0) {
|
||||
edge_mask >>= 1;
|
||||
edge_position += 1;
|
||||
}
|
||||
|
||||
/* We expect that there is exactly one edge in here. */
|
||||
assert(edge_mask == 1);
|
||||
|
||||
edge_mask = 1UL << edge_position;
|
||||
|
||||
unsigned edge_mask0 = (prev.mask0&edge_mask)? 1 : 0;
|
||||
unsigned edge_maskx = (prev.maskx&edge_mask)? 1 : 0;
|
||||
unsigned edge_mask1 = (prev.mask1&edge_mask)? 1 : 0;
|
||||
|
||||
|
||||
/* Now the edge_position and edge_mask* variables have the
|
||||
values we use to test the applicability of the edge_table
|
||||
entries. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < nedges0_ ; idx += 1) {
|
||||
struct udp_edges_table*row = edges0_ + idx;
|
||||
|
||||
if (row->edge_position != edge_position)
|
||||
continue;
|
||||
if (edge_mask0 && !row->edge_mask0)
|
||||
continue;
|
||||
if (edge_maskx && !row->edge_maskx)
|
||||
continue;
|
||||
if (edge_mask1 && !row->edge_mask1)
|
||||
continue;
|
||||
if (cur.mask0 != (cur.mask0 & row->mask0))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & row->maskx))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & row->mask1))
|
||||
continue;
|
||||
|
||||
return BIT4_0;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nedges1_ ; idx += 1) {
|
||||
struct udp_edges_table*row = edges1_ + idx;
|
||||
|
||||
if (row->edge_position != edge_position)
|
||||
continue;
|
||||
if (edge_mask0 && !row->edge_mask0)
|
||||
continue;
|
||||
if (edge_maskx && !row->edge_maskx)
|
||||
continue;
|
||||
if (edge_mask1 && !row->edge_mask1)
|
||||
continue;
|
||||
if (cur.mask0 != (cur.mask0 & row->mask0))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & row->maskx))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & row->mask1))
|
||||
continue;
|
||||
|
||||
return BIT4_1;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nedgesL_ ; idx += 1) {
|
||||
struct udp_edges_table*row = edgesL_ + idx;
|
||||
|
||||
if (row->edge_position != edge_position)
|
||||
continue;
|
||||
if (edge_mask0 && !row->edge_mask0)
|
||||
continue;
|
||||
if (edge_maskx && !row->edge_maskx)
|
||||
continue;
|
||||
if (edge_mask1 && !row->edge_mask1)
|
||||
continue;
|
||||
if (cur.mask0 != (cur.mask0 & row->mask0))
|
||||
continue;
|
||||
if (cur.maskx != (cur.maskx & row->maskx))
|
||||
continue;
|
||||
if (cur.mask1 != (cur.mask1 & row->mask1))
|
||||
continue;
|
||||
|
||||
if (cur.mask0 & (1 << port_count()))
|
||||
return BIT4_0;
|
||||
if (cur.mask1 & (1 << port_count()))
|
||||
return BIT4_1;
|
||||
if (cur.maskx & (1 << port_count()))
|
||||
return BIT4_X;
|
||||
|
||||
assert(0);
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
return BIT4_X;
|
||||
}
|
||||
|
||||
vvp_udp_fun_core::vvp_udp_fun_core(vvp_net_t*net,
|
||||
vvp_udp_s*def,
|
||||
vvp_delay_t*del)
|
||||
|
|
@ -232,6 +692,8 @@ void vvp_udp_fun_core::recv_vec4_from_inputs(unsigned port)
|
|||
|
||||
unsigned long mask = 1UL << port;
|
||||
|
||||
udp_levels_table prev = current_;
|
||||
|
||||
switch (value(port).value(0)) {
|
||||
|
||||
case BIT4_0:
|
||||
|
|
@ -251,7 +713,7 @@ void vvp_udp_fun_core::recv_vec4_from_inputs(unsigned port)
|
|||
break;
|
||||
}
|
||||
|
||||
vvp_bit4_t out_bit = def_->test_levels(current_);
|
||||
vvp_bit4_t out_bit = def_->calculate_output(current_, prev, cur_out_);
|
||||
vvp_vector4_t out (1);
|
||||
out.set_bit(0, out_bit);
|
||||
|
||||
|
|
@ -289,6 +751,9 @@ void compile_udp_functor(char*label, char*type,
|
|||
|
||||
/*
|
||||
* $Log: udp.cc,v $
|
||||
* Revision 1.30 2005/06/09 04:12:30 steve
|
||||
* Support sequential UDP devices.
|
||||
*
|
||||
* Revision 1.29 2005/04/04 05:13:59 steve
|
||||
* Support row level wildcards.
|
||||
*
|
||||
|
|
|
|||
146
vvp/udp.h
146
vvp/udp.h
|
|
@ -22,14 +22,35 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: udp.h,v 1.16 2005/04/03 05:45:51 steve Exp $"
|
||||
#ident "$Id: udp.h,v 1.17 2005/06/09 04:12:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <vvp_net.h>
|
||||
# include <delay.h>
|
||||
|
||||
struct udp_levels_table;
|
||||
|
||||
struct vvp_udp_s {
|
||||
|
||||
public:
|
||||
explicit vvp_udp_s(char*label, unsigned ports);
|
||||
virtual ~vvp_udp_s();
|
||||
|
||||
// Return the number of input ports for the defined UDP. This
|
||||
// does *not* include the current output value for a
|
||||
// sequential UDP.
|
||||
unsigned port_count() const;
|
||||
|
||||
virtual vvp_bit4_t calculate_output(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev,
|
||||
vvp_bit4_t cur_out) =0;
|
||||
|
||||
private:
|
||||
unsigned ports_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The vvp_udp_s instance represents a *definition* of a
|
||||
* The vvp_udp_async_s instance represents a *definition* of a
|
||||
* primitive. netlist instances refer to these definitions.
|
||||
*
|
||||
* The ports argument of the constructor is the number of input ports
|
||||
|
|
@ -50,7 +71,31 @@
|
|||
* will be set in the three masks for each bit position.
|
||||
*
|
||||
* This table structure implies that the number of inputs to the level
|
||||
* sensitive device is limited to the number of bits in an unsigned long.
|
||||
* sensitive device is limited to the number of bits in an unsigned
|
||||
* long.
|
||||
*
|
||||
* The array of strings passed to the compile_table method of a
|
||||
* combinational UDP are strings of port_count()+1 characters. The
|
||||
* expected inputs are in the order of the UDP inputs, and the output
|
||||
* is the last character. For example, an AND gate has these strings
|
||||
* passed to the compile_table function:
|
||||
*
|
||||
* 000 (Both inputs are 0)
|
||||
* 010 (Second input is a 1)
|
||||
* 100
|
||||
* 111 (All inputs are 1, so generate a 1 output)
|
||||
*
|
||||
* The characters allowed in the input positions are:
|
||||
*
|
||||
* 0 -- Expect a 0
|
||||
* 1 -- Expect a 1
|
||||
* x -- Expect an x or z
|
||||
* b -- 0 or 1
|
||||
* l -- 0 or x
|
||||
* h -- x or 1
|
||||
* ? -- 0, x or 1
|
||||
*
|
||||
* Only 0, 1 and x characters are allowed in the output position.
|
||||
*/
|
||||
|
||||
struct udp_levels_table {
|
||||
|
|
@ -59,23 +104,23 @@ struct udp_levels_table {
|
|||
unsigned long maskx;
|
||||
};
|
||||
|
||||
class vvp_udp_s {
|
||||
class vvp_udp_comb_s : public vvp_udp_s {
|
||||
|
||||
public:
|
||||
vvp_udp_s(char*label, char*name, unsigned ports, bool sequ);
|
||||
~vvp_udp_s();
|
||||
vvp_udp_comb_s(char*label, char*name, unsigned ports);
|
||||
~vvp_udp_comb_s();
|
||||
void compile_table(char**tab);
|
||||
|
||||
// Return the number of input ports for the defined UDP.
|
||||
unsigned port_count() const;
|
||||
|
||||
// Test the cur table with the compiled rows, and return the
|
||||
// bit value that matches.
|
||||
vvp_bit4_t test_levels(const udp_levels_table&cur);
|
||||
|
||||
vvp_bit4_t calculate_output(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev,
|
||||
vvp_bit4_t cur_out);
|
||||
|
||||
private:
|
||||
char*name_;
|
||||
unsigned ports_;
|
||||
|
||||
// Level sensitive rows of the device.
|
||||
struct udp_levels_table*levels0_;
|
||||
|
|
@ -83,6 +128,84 @@ class vvp_udp_s {
|
|||
unsigned nlevels0_, nlevels1_;
|
||||
};
|
||||
|
||||
/*
|
||||
* udp sequential devices are a little more complex in that they have
|
||||
* an additional output type: no-change. They also have, in addition
|
||||
* to a table of levels, a table of edges that are similar to levels
|
||||
* but one of the positions has an edge value.
|
||||
*
|
||||
* The port_count() for the device is the number of inputs. Sequential
|
||||
* devices have and additional phantom port that is the current output
|
||||
* value. This implies that the maximim port count for sequential
|
||||
* devices is 1 less then for combinational.
|
||||
*
|
||||
* The input table that is passed to the compile_table method is very
|
||||
* similar to that for the combinational UDP. The differences are that
|
||||
* there is one extra entry in the beginning of each input row that is
|
||||
* the current output, and there are more characters accepted at each
|
||||
* bit position.
|
||||
*
|
||||
* The current output bit may contain the same characters as a
|
||||
* combinational UDP input position. No edges.
|
||||
*
|
||||
* The next output position takes the possible values 0, x, 1 and -.
|
||||
*
|
||||
* The input bit positions take the combinational input characters,
|
||||
* plus edge specification characters. Only one input of a row may
|
||||
* have an edge input.
|
||||
*
|
||||
* The edges_table is similar to the levels, table, with the mask?
|
||||
* bits having the same meaning as with the levels tables. The edge_*
|
||||
* members specify the edge for a single bit position. In this case,
|
||||
* the edge_mask* members give the mask of source bits for that
|
||||
* position, and the edge_position the bit that has shifted. In the
|
||||
* edge case, the mask* members give the final position and the
|
||||
* edge_mask* bits the initial position of the bit.
|
||||
*/
|
||||
struct udp_edges_table {
|
||||
unsigned long edge_position : 8;
|
||||
unsigned long edge_mask0 : 1;
|
||||
unsigned long edge_mask1 : 1;
|
||||
unsigned long edge_maskx : 1;
|
||||
unsigned long mask0;
|
||||
unsigned long mask1;
|
||||
unsigned long maskx;
|
||||
};
|
||||
|
||||
class vvp_udp_seq_s : public vvp_udp_s {
|
||||
|
||||
public:
|
||||
vvp_udp_seq_s(char*label, char*name, unsigned ports);
|
||||
~vvp_udp_seq_s();
|
||||
|
||||
void compile_table(char**tab);
|
||||
|
||||
vvp_bit4_t calculate_output(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev,
|
||||
vvp_bit4_t cur_out);
|
||||
|
||||
private:
|
||||
|
||||
vvp_bit4_t test_levels_(const udp_levels_table&cur);
|
||||
|
||||
// Level sensitive rows of the device.
|
||||
struct udp_levels_table*levels0_;
|
||||
struct udp_levels_table*levels1_;
|
||||
struct udp_levels_table*levelsx_;
|
||||
struct udp_levels_table*levelsL_;
|
||||
unsigned nlevels0_, nlevels1_, nlevelsx_, nlevelsL_;
|
||||
|
||||
vvp_bit4_t test_edges_(const udp_levels_table&cur,
|
||||
const udp_levels_table&prev);
|
||||
|
||||
// Edge sensitive rows of the device
|
||||
struct udp_edges_table*edges0_;
|
||||
struct udp_edges_table*edges1_;
|
||||
struct udp_edges_table*edgesL_;
|
||||
unsigned nedges0_, nedges1_, nedgesL_;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Ths looks up a UDP definition from its LABEL.
|
||||
*/
|
||||
|
|
@ -114,6 +237,9 @@ class vvp_udp_fun_core : public vvp_wide_fun_core {
|
|||
|
||||
/*
|
||||
* $Log: udp.h,v $
|
||||
* Revision 1.17 2005/06/09 04:12:30 steve
|
||||
* Support sequential UDP devices.
|
||||
*
|
||||
* Revision 1.16 2005/04/03 05:45:51 steve
|
||||
* Rework the vvp_delay_t class.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue