diff --git a/vvp/compile.cc b/vvp/compile.cc index 5708ee2093..756d553a29 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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. diff --git a/vvp/udp.cc b/vvp/udp.cc index c53e7775c5..8b302fa1f1 100644 --- a/vvp/udp.cc +++ b/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 #include #include - +#include 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,55 +210,461 @@ 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]) { + or_based_on_char(cur, tab[idx][pp], mask_bit); + } + + switch (tab[idx][port_count()]) { + case '0': + levels0_[nrows0++] = cur; + break; + case '1': + levels1_[nrows1++] = cur; + break; + default: + break; + } + } + + assert(nrows0 == nlevels0_); + 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': - cur.mask0 |= mask_bit; + nlevels0_ += 1; break; case '1': - cur.mask1 |= mask_bit; + nlevels1_ += 1; break; case 'x': - cur.maskx |= mask_bit; + nlevelsx_ += 1; break; - case 'b': - cur.mask0 |= mask_bit; - cur.mask1 |= mask_bit; + case '-': + nlevelsL_ += 1; break; - case 'l': - cur.mask0 |= mask_bit; - cur.maskx |= mask_bit; + default: + assert(0); break; - case 'h': - cur.maskx |= mask_bit; - cur.mask1 |= mask_bit; + } + + } else { + + switch (row[port_count()+1]) { + case '0': + nedges0_ += 1; + break; + case '1': + nedges1_ += 1; + break; + case 'x': break; - case '?': - cur.mask0 |= mask_bit; - cur.maskx |= mask_bit; - cur.mask1 |= mask_bit; + 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; + } - switch (tab[idx][ports_]) { - case '0': - levels0_[nrows0++] = cur; - break; - case '1': - levels1_[nrows1++] = cur; - break; - default: - break; } } +} - assert(nrows0 == nlevels0_); - assert(nrows1 == nlevels1_); +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, @@ -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. * diff --git a/vvp/udp.h b/vvp/udp.h index d78054ceb1..13e6d7d06b 100644 --- a/vvp/udp.h +++ b/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 # include +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. *