diff --git a/design_dump.cc b/design_dump.cc index c1732240e..a37abbeae 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: design_dump.cc,v 1.7 1998/12/07 04:53:17 steve Exp $" +#ident "$Id: design_dump.cc,v 1.8 1998/12/14 02:01:34 steve Exp $" #endif /* @@ -167,9 +167,55 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } -void NetUDP::dump_node(ostream&o, unsigned ind) const +void NetUDP::dump_sequ_(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "UDP: "; + string tmp = ""; + for (unsigned idx = 0 ; idx < ind ; idx += 1) + tmp += " "; + + o << tmp << "Sequential UDP" << " #(" << delay1() << + "," << delay2() << "," << delay3() << ") " << name() << + endl; + + for (FSM_::const_iterator ent = fsm_.begin() + ; ent != fsm_.end() ; ent++) { + o << setw(ind+6) << "" << (*ent).first << " -->"; + + state_t_*st = (*ent).second; + assert((*ent).first[0] == st->out); + for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { + string tmp = (*ent).first; + if (st->pins[idx].zer) { + tmp[0] = st->pins[idx].zer->out; + tmp[idx] = '0'; + o << " " << tmp; + } + + if (st->pins[idx].one) { + tmp[0] = st->pins[idx].one->out; + tmp[idx] = '1'; + o << " " << tmp; + } + + if (st->pins[idx].xxx) { + tmp[0] = st->pins[idx].xxx->out; + tmp[idx] = 'x'; + o << " " << tmp; + } + } + + o << endl; + } + + o << setw(ind+6) << "" << "initial value == " << init_ << endl; + + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + +void NetUDP::dump_comb_(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "Combinational UDP: "; o << " #(" << delay1() << "," << delay2() << "," << delay3() << ") " << name() << endl; @@ -177,6 +223,14 @@ void NetUDP::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } +void NetUDP::dump_node(ostream&o, unsigned ind) const +{ + if (sequential_) + dump_sequ_(o, ind); + else + dump_comb_(o, ind); +} + void NetPEvent::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "event: "; @@ -407,6 +461,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.8 1998/12/14 02:01:34 steve + * Fully elaborate Sequential UDP behavior. + * * Revision 1.7 1998/12/07 04:53:17 steve * Generate OBUF or IBUF attributes (and the gates * to garry them) where a wire is a pad. This involved diff --git a/elaborate.cc b/elaborate.cc index e0d6553c6..3916fc643 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.9 1998/12/07 04:53:17 steve Exp $" +#ident "$Id: elaborate.cc,v 1.10 1998/12/14 02:01:34 steve Exp $" #endif /* @@ -255,12 +255,20 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const } } +/* + * From a UDP definition in the source, make a NetUDP + * object. Elaborate the pin expressions as netlists, then connect + * those networks to the pins. + */ void PGModule::elaborate_udp_(Design*des, PUdp*udp, const string&path) const { const string my_name = path+"."+get_name(); - NetUDP*net = new NetUDP(my_name, udp->ports.size()); + NetUDP*net = new NetUDP(my_name, udp->ports.size(), udp->sequential); net->set_attributes(udp->attributes); + /* Run through the pins, making netlists for the pin + expressions and connecting them to the pin in question. All + of this is independent of the nature of the UDP. */ for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { if (pin(idx) == 0) continue; @@ -274,10 +282,37 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, const string&path) const connect(sig->pin(0), net->pin(idx)); + // Delete excess holding signal. if (NetTmp*tmp = dynamic_cast(sig)) delete tmp; } + /* Build up the truth table for the netlist from the input + strings. */ + for (unsigned idx = 0 ; idx < udp->tinput.size() ; idx += 1) { + string input = udp->sequential + ? (string("") + udp->tcurrent[idx] + udp->tinput[idx]) + : udp->tinput[idx]; + + net->set_table(input, udp->toutput[idx]); + } + + net->cleanup_table(); + + if (udp->sequential) switch (udp->initial) { + case verinum::V0: + net->set_initial('0'); + break; + case verinum::V1: + net->set_initial('1'); + break; + case verinum::Vx: + case verinum::Vz: + net->set_initial('x'); + break; + } + + // All done. Add the object to the design. des->add_node(net); } @@ -734,6 +769,9 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.10 1998/12/14 02:01:34 steve + * Fully elaborate Sequential UDP behavior. + * * Revision 1.9 1998/12/07 04:53:17 steve * Generate OBUF or IBUF attributes (and the gates * to garry them) where a wire is a pad. This involved diff --git a/netlist.cc b/netlist.cc index 2e0ba6567..bc0e1d9e6 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.11 1998/12/07 04:53:17 steve Exp $" +#ident "$Id: netlist.cc,v 1.12 1998/12/14 02:01:35 steve Exp $" #endif # include @@ -423,12 +423,213 @@ NetLogic::NetLogic(const string&n, unsigned pins, TYPE t) pin(idx).set_dir(Link::INPUT); } -NetUDP::NetUDP(const string&n, unsigned pins) -: NetNode(n, pins) +NetUDP::NetUDP(const string&n, unsigned pins, bool sequ) +: NetNode(n, pins), sequential_(sequ), init_('x') { pin(0).set_dir(Link::OUTPUT); for (unsigned idx = 1 ; idx < pins ; idx += 1) pin(idx).set_dir(Link::INPUT); + +} + +NetUDP::state_t_* NetUDP::find_state_(const string&str) +{ + map::iterator cur = fsm_.find(str); + if (cur != fsm_.end()) + return (*cur).second; + + state_t_*st = fsm_[str]; + if (st == 0) { + st = new state_t_(pin_count()); + st->out = str[0]; + fsm_[str] = st; + } + + return st; +} + +/* + * This method takes the input string, which contains exactly one + * edge, and connects it to the correct output state. The output state + * will be generated if needed, and the value compared. + */ +bool NetUDP::set_sequ_(const string&input, char output) +{ + if (output == '-') + output = input[0]; + + string frm = input; + string to = input; + to[0] = output; + + unsigned edge = frm.find_first_not_of("01x"); + assert(frm.find_last_not_of("01x") == edge); + + switch (input[edge]) { + case 'r': + frm[edge] = '0'; + to[edge] = '1'; + break; + case 'R': + frm[edge] = 'x'; + to[edge] = '1'; + break; + case 'f': + frm[edge] = '1'; + to[edge] = '0'; + break; + case 'F': + frm[edge] = 'x'; + to[edge] = '0'; + break; + case 'P': + frm[edge] = '0'; + to[edge] = 'x'; + break; + case 'N': + frm[edge] = '1'; + to[edge] = 'x'; + break; + default: + assert(0); + } + + state_t_*sfrm = find_state_(frm); + state_t_*sto = find_state_(to); + + switch (to[edge]) { + case '0': + assert(sfrm->pins[edge].zer == 0); + sfrm->pins[edge].zer = sto; + break; + case '1': + assert(sfrm->pins[edge].one == 0); + sfrm->pins[edge].one = sto; + break; + case 'x': + assert(sfrm->pins[edge].xxx == 0); + sfrm->pins[edge].xxx = sto; + break; + } + + return true; +} + +bool NetUDP::sequ_glob_(string input, char output) +{ + for (unsigned idx = 0 ; idx < input.length() ; idx += 1) + switch (input[idx]) { + case '0': + case '1': + case 'x': + case 'r': + case 'R': + case 'f': + case 'F': + case 'P': + case 'N': + break; + + case '?': // Iterate over all the levels + input[idx] = '0'; + sequ_glob_(input, output); + input[idx] = '1'; + sequ_glob_(input, output); + input[idx] = 'x'; + sequ_glob_(input, output); + return true; + + case '*': // Iterate over all the edges + input[idx] = 'r'; + sequ_glob_(input, output); + input[idx] = 'R'; + sequ_glob_(input, output); + input[idx] = 'f'; + sequ_glob_(input, output); + input[idx] = 'F'; + sequ_glob_(input, output); + input[idx] = 'P'; + sequ_glob_(input, output); + input[idx] = 'N'; + sequ_glob_(input, output); + return true; + + default: + assert(0); + } + + return set_sequ_(input, output); +} + +bool NetUDP::set_table(const string&input, char output) +{ + assert((output == '0') || (output == '1') || (sequential_ && + (output == '-'))); + + if (sequential_) { + assert(input.length() == pin_count()); + /* XXXX Need to check to make sure that the input vector + contains a legal combination of characters. */ + return sequ_glob_(input, output); + + } else { + assert(input.length() == (pin_count()-1)); + /* XXXX Need to check to make sure that the input vector + contains a legal combination of characters. In + combinational UDPs, only 0, 1 and x are allowed. */ + assert(0); + + return true; + } +} + +void NetUDP::cleanup_table() +{ + for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; idx++) { + string str = (*idx).first; + state_t_*st = (*idx).second; + assert(str[0] == st->out); + + for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) { + if (st->pins[pin].zer && st->pins[pin].zer->out == 'x') + st->pins[pin].zer = 0; + if (st->pins[pin].one && st->pins[pin].one->out == 'x') + st->pins[pin].one = 0; + if (st->pins[pin].xxx && st->pins[pin].xxx->out == 'x') + st->pins[pin].xxx = 0; + } + } + + for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; ) { + FSM_::iterator cur = idx; + idx ++; + + state_t_*st = (*cur).second; + + if (st->out != 'x') + continue; + + for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) { + if (st->pins[pin].zer) + goto break_label; + if (st->pins[pin].one) + goto break_label; + if (st->pins[pin].xxx) + goto break_label; + } + + //delete st; + fsm_.erase(cur); + + break_label:; + } +} + +void NetUDP::set_initial(char val) +{ + assert(sequential_); + assert((val == '0') || (val == '1') || (val == 'x')); + init_ = val; } string Design::get_flag(const string&key) const @@ -583,6 +784,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.12 1998/12/14 02:01:35 steve + * Fully elaborate Sequential UDP behavior. + * * Revision 1.11 1998/12/07 04:53:17 steve * Generate OBUF or IBUF attributes (and the gates * to garry them) where a wire is a pad. This involved diff --git a/netlist.h b/netlist.h index 4efdf69e3..18b7a47e8 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.11 1998/12/07 04:53:17 steve Exp $" +#ident "$Id: netlist.h,v 1.12 1998/12/14 02:01:35 steve Exp $" #endif /* @@ -338,14 +338,91 @@ class NetLogic : public NetNode { * The UDP is a User Defined Primitive from the Verilog source. Do not * expand it out any further then this in the netlist, as this can be * used to represent target device primitives. + * + * The UDP can be combinational or sequential. The sequentianl UDP + * includes the current output in the truth table, and supports edges, + * whereas the combinational does not and is entirely level sensitive. + * In any case, pin 0 is an output, and all the remaining pins are + * inputs. + * + * The truth table is canonically represented as a finite state + * machine with the current state representing the inputs and the + * current output, and the next state carrying the new output value to + * use. All the outgoing transitions from a state represent a single + * edge. + * + * Set_table takes as input a string with one letter per pin. The + * valid characters are: + * + * 0, 1, x -- The levels + * r -- (01) + * R -- (x1) + * f -- (10) + * F -- (x0) + * P -- (0x) + * N -- (1x) + * + * COMBINATIONAL + * The logic table is a map between the input levels and the + * output. Each input pin can have the value 0, 1 or x and the output + * can have the values 0 or 1. If the input matches nothing, the + * output is x. In canonical form, only the entries that generate 0 or + * 1 are listed. + * + * SEQUENTIAL + * These objects have a single bit of memory. The logic table includes + * an entry for the current value, and allows edges on the inputs. In + * canonical form, inly then entries that generate 0, 1 or - (no change) + * are listed. + * */ class NetUDP : public NetNode { public: - explicit NetUDP(const string&n, unsigned pins); + explicit NetUDP(const string&n, unsigned pins, bool sequ =false); virtual void emit_node(ostream&, struct target_t*) const; virtual void dump_node(ostream&, unsigned ind) const; + + /* return false if the entry conflicts with an existing + entry. In any case, the new output overrides. */ + bool set_table(const string&input, char output); + void cleanup_table(); + + void set_initial(char); + + bool is_sequential() const { return sequential_; } + + private: + const bool sequential_; + char init_; + + struct state_t_; + struct pin_t_ { + state_t_*zer; + state_t_*one; + state_t_*xxx; + + explicit pin_t_() : zer(0), one(0), xxx(0) { } + }; + + struct state_t_ { + char out; + pin_t_*pins; + + state_t_(unsigned n) : out(0), pins(new pin_t_[n]) {} + ~state_t_() { delete[]pins; } + }; + + typedef map FSM_; + FSM_ fsm_; + bool set_sequ_(const string&in, char out); + bool sequ_glob_(string, char out); + + state_t_*find_state_(const string&); + + void dump_sequ_(ostream&o, unsigned ind) const; + void dump_comb_(ostream&o, unsigned ind) const; }; /* ========= @@ -811,6 +888,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.12 1998/12/14 02:01:35 steve + * Fully elaborate Sequential UDP behavior. + * * Revision 1.11 1998/12/07 04:53:17 steve * Generate OBUF or IBUF attributes (and the gates * to garry them) where a wire is a pad. This involved diff --git a/parse.y b/parse.y index 13c9682f3..5972e4bae 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: parse.y,v 1.8 1998/12/01 00:42:14 steve Exp $" +#ident "$Id: parse.y,v 1.9 1998/12/14 02:01:35 steve Exp $" #endif # include "parse_misc.h" @@ -730,7 +730,7 @@ udp_input_sym | 'b' { $$ = 'b'; } | '*' { $$ = '*'; } | 'f' { $$ = 'f'; } - | 'r' { $$ = 'f'; } + | 'r' { $$ = 'r'; } ; udp_output_sym