Fully elaborate Sequential UDP behavior.

This commit is contained in:
steve 1998-12-14 02:01:34 +00:00
parent 45f45f73b7
commit 10b345bd16
5 changed files with 391 additions and 12 deletions

View File

@ -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

View File

@ -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<NetTmp*>(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<string,Module*>&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

View File

@ -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 <cassert>
@ -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<string,state_t_*>::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

View File

@ -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<string,state_t_*> 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

View File

@ -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