From 7b79fd98e5e1205a8f6bc14246ae9931aa7f490b Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 24 Jul 2001 01:44:50 +0000 Subject: [PATCH] Fast UDP tables (Stephan Boettcher) --- vvp/udp.cc | 381 ++++++++++++++++++++++++++++++++++++----------------- vvp/udp.h | 16 ++- 2 files changed, 269 insertions(+), 128 deletions(-) diff --git a/vvp/udp.cc b/vvp/udp.cc index 28cfb317b..e0e7f3827 100644 --- a/vvp/udp.cc +++ b/vvp/udp.cc @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: udp.cc,v 1.7 2001/07/16 19:08:32 steve Exp $" +#ident "$Id: udp.cc,v 1.8 2001/07/24 01:44:50 steve Exp $" #endif #include "udp.h" @@ -26,9 +26,7 @@ #include "symbols.h" #include #include - -static symbol_table_t udp_table; - +#include void vvp_udp_s::set(vvp_ipoint_t ptr, functor_t fp, bool) { @@ -61,6 +59,9 @@ unsigned vvp_udp_s::get(vvp_ipoint_t i, functor_t f) assert(0); } + +static symbol_table_t udp_table; + struct vvp_udp_s *udp_create(char *label) { if (!udp_table) @@ -89,149 +90,285 @@ struct vvp_udp_s *udp_find(char *label) return (struct vvp_udp_s *)v.ptr; } +typedef unsigned int udp_vec_t; +struct udp_table_entry_s +{ + udp_vec_t not_0; // all inputs that must not be 0 + udp_vec_t not_1x; // all inputs that bust not be 1 or x + unsigned char edge_idx; // input index of the edge + unsigned char edge_type; // permissible transitions. 0: no edge. + unsigned char out; // new output, 0..2 +}; + +enum edge_type_e +{ + EDGE_0 = 0x01, + EDGE_1 = 0x02, + EDGE_x = 0x0c, + EDGE_any = 0x0f, +}; + unsigned char vvp_udp_s::propagate_(vvp_ipoint_t uix) { functor_t fu = functor_index(uix); unsigned char ret = 2; - for (char **rptr = table; *rptr ; rptr++) - { - char *row = *rptr; + unsigned edge_idx = 0; // input index that changed + unsigned edge_type = 0; // input transition - if (sequ) + udp_vec_t invec = 0x0; // vector of 2-bit inputs + + for (int i=0; i < nin; i+=4) + { + int idx = ipoint_input_index(uix, i); + functor_t pfun = functor_index(idx); + + invec |= pfun->ival << (2*i); + + unsigned char diff = pfun->ival ^ pfun->old_ival; + if (diff) { - char old_out = (fu->oval&3)["01xx"]; - if ( row[0]=='?' - || row[0]==old_out - || (row[0]=='b' && old_out!='x') - || (row[0]=='l' && old_out!='1') - || (row[0]=='h' && old_out!='0') ) - row++; - else - continue; + unsigned ii = 0; + if (diff & 0x03) ii = 0; + if (diff & 0x0c) ii = 1; + if (diff & 0x30) ii = 2; + if (diff & 0xc0) ii = 3; + + edge_idx = i+ii; + + unsigned old_in = (pfun->old_ival >> (2*ii)) & 3; + edge_type = (1<old_ival = pfun->ival; + } - for (i=0; i < nin; i++, row++) + if (sequ) + { + invec <<= 2; + invec |= (fu->oval&3); + } + + udp_vec_t inx = invec & 0xaaaaaaaaU; // all 'x'/'z' + udp_vec_t in01 = ~(inx>>1); // masks all 'x'/'z' + udp_vec_t in1x = invec & in01; // all 'x' and '1' + udp_vec_t in0 = ~invec & in01; // all '0' + + for (int ri=0; ri < ntable; ri++) + { + udp_table_entry_t row = table+ri; + + if ((in1x & row->not_1x) || (in0 & row->not_0)) + continue; + + if (!row->edge_type) { - assert (*row); - - int idx = ipoint_input_index(uix, i); - int port = ipoint_port(idx); - functor_t pfun = functor_index(idx); - - char new_bit = ((pfun->ival >> (2*port))&3)["01xx"]; - - if ( *row != new_bit - && *row != '?' - && (*row != 'b' || new_bit == 'x') - && (*row != 'l' || new_bit == '1') - && (*row != 'h' || new_bit == '0') ) - { - char old_bit = ((pfun->old_ival >> (2*port))&3)["01xx"]; - if (new_bit == old_bit) - break; - - switch (*row) - { - case '*': - continue; - case '_': - if (new_bit == '0') - continue; - break; - case '+': - if (new_bit == '1') - continue; - break; - case '%': - if (new_bit == 'x') - continue; - break; - case 'B': - if (old_bit == 'x') - continue; - break; - case 'r': - if (old_bit=='0' && new_bit=='1') - continue; - break; - case 'R': - if (old_bit=='x' && new_bit=='1') - continue; - break; - case 'f': - if (old_bit=='1' && new_bit=='0') - continue; - break; - case 'F': - if (old_bit=='x' && new_bit=='0') - continue; - break; - case 'P': - if (old_bit=='0') - continue; - break; - case 'p': - if (old_bit=='0' || new_bit=='1') - continue; - break; - case 'N': - if (old_bit=='1') - continue; - break; - case 'n': - if (old_bit=='1' || new_bit=='0') - continue; - break; - case 'Q': - if (old_bit=='0' && new_bit=='x') - continue; - break; - case 'M': - if (old_bit=='1' && new_bit=='x') - continue; - break; - } - break; - } + ret = row->out; + break; } - if (i == nin) + if (row->edge_idx != edge_idx) + continue; + + if (row->edge_type & edge_type) { - assert(*row); - if (*row == '-') - ret = fu->oval; - else - switch (*row) - { - case '0': - ret = 0; - break; - case '1': - ret = 1; - break; - default: - ret = 2; - break; - } + ret = row->out; break; } } - - for (int i=0; i < nin; i+=4) + + if (ret>2) + ret = fu->oval; + + return ret; +} + +void vvp_udp_s::compile_table(char **tab) +{ + ntable = 0; + for (char **ss = tab; *ss; ss++) + ntable++; + table = new struct udp_table_entry_s[ntable]; + for (unsigned i = 0; i < ntable; i++) { - functor_t fu = functor_index(ipoint_input_index(uix, i)); - fu->old_ival = fu->ival; + compile_row_(&table[i], tab[i]); + free(tab[i]); + } + free(tab); +} + +void vvp_udp_s::compile_row_(udp_table_entry_t row, char *rchr) +{ + row->not_0 = 0; // all inputs that must not be 0 + row->not_1x = 0; // all inputs that bust not be 1 or x + row->edge_idx = 0; // input index of the edge + row->edge_type = 0; // permissible transitions. 0: no edge. + + char *s = rchr; + for (unsigned i = (sequ ? 0 : 1); i <= nin; i++) + { + char c = *s; + s++; + + unsigned char n0 = 0; + unsigned char n1x = 0; + unsigned char edge = 0; + + switch (c) + { + default: + fprintf(stderr, "vvp: Illegal character (%d) in UDP table\n", c); + assert(0); + break; + + case '?': + break; + case '0': + n1x = 3; // 1, x not allowed + break; + case '1': + n0 = 1; // 0 not allowed + n1x = 2; // x not allowed + break; + case 'x': + n0 = 1; // 0 not allowed + n1x = 1; // 1 not allowed + break; + case 'b': + n1x = 2; // x not allowed + break; + case 'l': + n1x = 1; // 1 not allowed + break; + case 'h': + n0 = 1; // 0 not allowed + break; + + case '*': + edge = EDGE_any; + break; + + case '+': + n0 = 1; // 0 not allowed + n1x = 2; // x not allowed + edge = EDGE_any; + break; + case '_': + n1x = 3; // 1, x not allowed + edge = EDGE_any; + break; + case '%': + n0 = 1; // 0 not allowed + n1x = 1; // 1 not allowed + edge = EDGE_any; + break; + + case 'N': + edge = EDGE_1; + break; + case 'P': + edge = EDGE_0; + break; + case 'B': + edge = EDGE_x; + break; + + case 'r': + n0 = 1; // 0 not allowed + n1x = 2; // x not allowed + edge = EDGE_0; + break; + case 'R': + n0 = 1; // 0 not allowed + n1x = 2; // x not allowed + edge = EDGE_x; + break; + case 'f': + n1x = 3; // 1, x not allowed + edge = EDGE_1; + break; + case 'F': + n1x = 3; // 1, x not allowed + edge = EDGE_x; + break; + case 'Q': + n0 = 1; // 0 not allowed + n1x = 1; // 1 not allowed + edge = EDGE_0; + break; + case 'M': + n0 = 1; // 0 not allowed + n1x = 1; // 1 not allowed + edge = EDGE_1; + break; + + case 'n': + n1x = 1; // 1 not allowed + edge = EDGE_1 | EDGE_x; + break; + case 'p': + n0 = 1; // 0 not allowed + edge = EDGE_0 | EDGE_x; + break; + case 'v': + n1x = 2; // x not allowed + edge = EDGE_0 | EDGE_1; + break; + } + + if (edge) + { + if (!sequ) + { + fprintf(stderr, "vvp: edge in compinatorial UDP\n"); + assert(0); + } + if (!i) + { + fprintf(stderr, "vvp: edge in UDP output state\n"); + assert(0); + } + row->edge_idx = i-1; + if (row->edge_type) + { + fprintf(stderr, "vvp: multiple edges in UDP table row\n"); + assert(0); + } + row->edge_type = edge; + } + + int j = sequ ? i : i-1; + row->not_0 |= n0 << (2*j); + row->not_1x |= n1x << (2*j); + } + + switch (*s) + { + case '0': + row->out = 0; + break; + case '1': + row->out = 1; + break; + case 'x': + row->out = 2; + break; + case '-': + row->out = 4; + break; + default: + fprintf(stderr, "vvp: illegal character (%d) in udp output spec\n", *s); + assert(0); } - return ret; } /* * $Log: udp.cc,v $ + * Revision 1.8 2001/07/24 01:44:50 steve + * Fast UDP tables (Stephan Boettcher) + * * Revision 1.7 2001/07/16 19:08:32 steve * Schedule instead of propagating UDP output. (Stephan Boettcher) * diff --git a/vvp/udp.h b/vvp/udp.h index 5013cb437..8f31130d5 100644 --- a/vvp/udp.h +++ b/vvp/udp.h @@ -20,12 +20,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: udp.h,v 1.7 2001/07/22 00:04:50 steve Exp $" +#ident "$Id: udp.h,v 1.8 2001/07/24 01:44:50 steve Exp $" #endif #include "pointers.h" #include "functor.h" +typedef struct udp_table_entry_s *udp_table_entry_t; + class vvp_udp_s : public vvp_fobj_s { public: @@ -34,14 +36,16 @@ class vvp_udp_s : public vvp_fobj_s public: char *name; + udp_table_entry_t table; + unsigned short ntable; unsigned short sequ; unsigned short nin; unsigned char init; - char **table; - void compile_table(char **t) { table = t; } + void compile_table(char **tab); - private: + private: + void compile_row_(udp_table_entry_t, char *); unsigned char propagate_(vvp_ipoint_t i); }; @@ -51,8 +55,8 @@ struct vvp_udp_s *udp_find(char *label); /* * $Log: udp.h,v $ - * Revision 1.7 2001/07/22 00:04:50 steve - * Add the load/x instruction for bit selects. + * Revision 1.8 2001/07/24 01:44:50 steve + * Fast UDP tables (Stephan Boettcher) * * Revision 1.6 2001/05/06 03:51:37 steve * Regularize the mode-42 functor handling.