diff --git a/synth2.cc b/synth2.cc index 8d7d22793..560163af9 100644 --- a/synth2.cc +++ b/synth2.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: synth2.cc,v 1.39.2.11 2005/12/15 02:38:51 steve Exp $" +#ident "$Id: synth2.cc,v 1.39.2.12 2005/12/19 01:13:47 steve Exp $" #endif # include "config.h" @@ -58,14 +58,13 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*ff, NetNet*nex_map, NetNet*nex_out, const svector&events) { - DEBUG_SYNTH2_ENTRY("NetProc") - +#if 0 if (events.count() > 0) { cerr << get_line() << ": error: Events are unaccounted" - << " for in process synthesis." << endl; + << " for in process synthesis. (proc)" << endl; des->errors += 1; } - +#endif /* Synthesize the input to the DFF. */ return synth_async(des, scope, true, nex_map, nex_out); } @@ -630,6 +629,50 @@ bool NetProcTop::synth_async(Design*des) return flag; } +static bool merge_ff_slices(NetFF*ff1, unsigned idx1, + NetFF*ff2, unsigned idx2) +{ + /* If the Data inputs to both FFs are connected, then there + are multiple descriptions of the inputs to this DFF + device. That is an error. */ + if (ff1->pin_Data(idx1).is_linked() && ff2->pin_Data(idx2).is_linked()) { + cerr << ff2->get_line() << ": error: " + << "Synchronous output conflicts with " + << ff1->get_line() << "." << endl; + return false; + } + + /* If the Aset inputs are connected, and not to each other + (possible since pre-existing Asets are carried forwards) + then there is a conflict. */ + if (ff1->pin_Aset().is_linked() + && ff2->pin_Aset().is_linked() + && ! ff1->pin_Aset().is_linked(ff2->pin_Aset())) { + cerr << ff2->get_line() << ": error: " + << "DFF Aset conflicts with " + << ff1->get_line() << "." << endl; + return false; + } + + if (ff1->pin_Aclr().is_linked() + && ff2->pin_Aclr().is_linked() + && ! ff1->pin_Aclr().is_linked(ff2->pin_Aclr())) { + cerr << ff2->get_line() << ": error: " + << "DFF Aclr conflicts with " + << ff1->get_line() << "." << endl; + return false; + } + + if (ff2->pin_Data(idx2).is_linked()) + connect(ff1->pin_Data(idx1), ff2->pin_Data(idx2)); + if (ff2->pin_Aset().is_linked()) + connect(ff1->pin_Aset(), ff2->pin_Aset()); + if (ff2->pin_Aclr().is_linked()) + connect(ff1->pin_Aclr(), ff2->pin_Aclr()); + + return true; +} + /* * This method is called when a block is encountered near the surface * of a synchronous always statement. For example, this code will be @@ -648,11 +691,9 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, NetNet*nex_map, NetNet*nex_out, const svector&events_in) { - DEBUG_SYNTH2_ENTRY("NetBlock") - if (last_ == 0) { - DEBUG_SYNTH2_EXIT("NetBlock",true) + /* Do nothing for empty blocks. */ + if (last_ == 0) return true; - } bool flag = true; @@ -660,10 +701,19 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, const perm_string tmp2 = perm_string::literal("tmp2"); /* Keep an accounting of which statement accounts for which - bit slice of the FF bank. This is used for error checking. */ - NetProc**pin_accounting = new NetProc* [ff->pin_count()]; - for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) - pin_accounting[idx] = 0; + bit slice of the FF bank. This is used for error + checking. */ + struct accounting_struct { + NetProc*proc; + NetFF*ff; + unsigned pin; + }; + struct accounting_struct*pin_accounting + = new accounting_struct [ff->pin_count()]; + for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { + pin_accounting[idx].proc = 0; + pin_accounting[idx].ff = 0; + } NetProc*cur = last_; do { @@ -698,6 +748,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, copy the aset_value bits for the new ff device. */ NetFF*ff2 = new NetFF(scope, scope->local_symbol(), tmp_out->pin_count()); + ff2->set_line(*cur); des->add_node(ff2); verinum aset_value2 (verinum::V1, ff2->width()); @@ -706,10 +757,6 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, unsigned ptr = find_nexus_in_set(nex_map, tmp_map->pin(idx).nexus()); - /* Connect Data and Q bits to the new FF. */ - connect(ff->pin_Data(ptr), ff2->pin_Data(idx)); - connect(ff->pin_Q(ptr), ff2->pin_Q(idx)); - /* Copy the asynch set bit to the new device. */ if (ptr < tmp_aset.len()) aset_value2.set(idx, tmp_aset[ptr]); @@ -718,18 +765,21 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, if (ptr < tmp_sset.len()) sset_value2.set(idx, tmp_sset[ptr]); - if (pin_accounting[ptr] != 0) { - cerr << cur->get_line() << ": error: " - << "Synchronous output conflicts with " - << pin_accounting[ptr]->get_line() - << "." << endl; - flag = false; + if (pin_accounting[ptr].proc != 0) { } else { - pin_accounting[ptr] = cur; + pin_accounting[ptr].proc = cur; + pin_accounting[ptr].ff = ff2; + pin_accounting[ptr].pin = idx; + + /* Connect Data and Q bits to the new FF. */ + connect(ff->pin_Data(ptr), ff2->pin_Data(idx)); + connect(ff->pin_Q(ptr), ff2->pin_Q(idx)); } } + /* PUll the non-sliced inputs (clock, set, reset, etc) + forward to the new FF we are building. */ if (ff->pin_Aclr().is_linked()) connect(ff->pin_Aclr(), ff2->pin_Aclr()); if (ff->pin_Aset().is_linked()) @@ -771,6 +821,26 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, if (ok_flag == false) continue; + unsigned ff2_pins_used = ff2->width(); + for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) { + unsigned ptr = find_nexus_in_set(nex_map, + tmp_map->pin(idx).nexus()); + if (pin_accounting[ptr].ff == ff2) + continue; + + assert(ff2_pins_used > 0); + ff2_pins_used -= 1; + bool tflag = merge_ff_slices(pin_accounting[ptr].ff, + pin_accounting[ptr].pin, + ff2, idx); + if (! tflag) { + flag = false; + } + } + + if (ff2_pins_used == 0) + delete ff2; + /* Use the nex_map to link up the output from the substatement to the output of the block as a whole. It is occasionally possible to have outputs @@ -789,13 +859,31 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff, } while (cur != last_); + /* Run through the pin accounting one more time to make sure + the data inputs are all connected. */ + for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) { + NetFF*ff2 = pin_accounting[idx].ff; + unsigned pin = pin_accounting[idx].pin; + /* Skip this output if it is not handled in this block. */ + if (ff2 == 0) + continue; + + /* If this block mentioned it, then the data must have + been set here. */ + if (!ff2->pin_Data(pin).is_linked()) { + cerr << ff2->get_line() << ": error: " + << "DFF introduced here is missing Data inputs." + << endl; + flag = false; + } + } + delete[]pin_accounting; /* Done. The large NetFF is no longer needed, as it has been taken up by the smaller NetFF devices. */ delete ff; - DEBUG_SYNTH2_EXIT("NetBlock",flag) return flag; } @@ -893,9 +981,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff, delete expr_input; if (else_ == 0) { - cerr << get_line() << ": error: In this context, " - << "synthesis requires an \"else\" clause." << endl; - return false; + + /* The lack of an else_ clause here means that + there is no data input to the DFF yet + defined. This is bad, but the data input may be + given later in an enclosing block, so don't + report an error here quite yet. */ + return true; } assert(else_ != 0); @@ -986,19 +1078,13 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff, delete a_set; /* Failed to find an asynchronous set/reset, so any events - input are probably in error. */ - if (events_in.count() > 0) { - cerr << get_line() << ": error: Events are unaccounted" - << " for in process synthesis." << endl; - des->errors += 1; - } + input are probably in error, or simply not in use. */ /* If this is an if/then/else, then it is likely a combinational if, and I should synthesize it that way. */ if (if_ && else_) { bool flag = synth_async(des, scope, true, nex_map, nex_out); - DEBUG_SYNTH2_EXIT("NetCondit",flag) return flag; } @@ -1059,7 +1145,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff, DEBUG_SYNTH2_ENTRY("NetEvWait") if (events_in.count() > 0) { cerr << get_line() << ": error: Events are unaccounted" - << " for in process synthesis." << endl; + << " for in process synthesis. (evw)" << endl; des->errors += 1; } @@ -1245,6 +1331,9 @@ void synth2(Design*des) /* * $Log: synth2.cc,v $ + * Revision 1.39.2.12 2005/12/19 01:13:47 steve + * Handle DFF definitions spread out within a block. + * * Revision 1.39.2.11 2005/12/15 02:38:51 steve * Fix missing outputs from synchronous conditionals to get out from in. *