@@ -46,7 +46,7 @@ PARGraphNode* MakeNode(
46
46
Greenpak4BitstreamEntity* entity,
47
47
PARGraph* dgraph);
48
48
49
- void InferExtraNodes (
49
+ bool InferExtraNodes (
50
50
Greenpak4Netlist* netlist,
51
51
Greenpak4Device* device,
52
52
PARGraph*& ngraph,
@@ -94,7 +94,8 @@ bool BuildGraphs(
94
94
return false ;
95
95
96
96
// Infer extra support nodes for things that use hidden functions of others
97
- InferExtraNodes (netlist, device, ngraph, ilmap);
97
+ if (!InferExtraNodes (netlist, device, ngraph, ilmap))
98
+ return false ;
98
99
99
100
return true ;
100
101
}
@@ -178,7 +179,7 @@ void ReplicateVREF(
178
179
/* *
179
180
@brief Add extra nodes to handle dependencies between nodes that share hard IP under the hood
180
181
*/
181
- void InferExtraNodes (
182
+ bool InferExtraNodes (
182
183
Greenpak4Netlist* netlist,
183
184
Greenpak4Device* device,
184
185
PARGraph*& ngraph,
@@ -214,8 +215,102 @@ void InferExtraNodes(
214
215
continue ;
215
216
Greenpak4NetlistCell* netsrc = driver.m_cell ;
216
217
217
- // We found the source of the net!
218
- LogVerbose (" Found a DAC not driven by a power rail\n " );
218
+ LogDebug (" DAC \" %s\" is driven by %s \" %s\"\n " ,
219
+ cell->m_name .c_str (),
220
+ netsrc->m_type .substr (3 ).c_str (),
221
+ netsrc->m_name .c_str ());
222
+ LogIndenter li;
223
+
224
+ // See if there's already a DCMP driven by the same signal.
225
+ vector<Greenpak4NetlistCell*> dcmps;
226
+ for (auto jt : net->m_nodeports )
227
+ {
228
+ if (jt.IsNull ())
229
+ continue ;
230
+ if (jt.m_cell ->m_type == " GP_DCMP" )
231
+ dcmps.push_back (jt.m_cell );
232
+ }
233
+
234
+ // If not, create one
235
+ if (dcmps.empty ())
236
+ {
237
+ LogDebug (" No DCMP driven by this cell, creating a dummy\n " );
238
+ madeChanges = true ;
239
+
240
+ // Monotonically increasing counter used to ensure unique node IDs
241
+ static unsigned int dcmp_id = 1 ;
242
+
243
+ // Create the cell
244
+ Greenpak4NetlistCell* dcmp = new Greenpak4NetlistCell (module);
245
+ dcmp->m_type = " GP_DCMP" ;
246
+
247
+ // Tie its negative input to our input
248
+ char tmp[128 ];
249
+ for (int i=0 ; i<8 ; i++)
250
+ {
251
+ snprintf (tmp, sizeof (tmp), " INN[%d]" , i);
252
+ dcmp->m_connections [tmp].push_back (net);
253
+ }
254
+
255
+ // Power down the comparator so it stays out of our way and doesn't waste power
256
+ dcmp->m_connections [" PWRDN" ].push_back (vdd);
257
+
258
+ // Give it a name
259
+ snprintf (tmp, sizeof (tmp), " $auto$make_graphs.cpp:%d:dcmp$%u" ,
260
+ __LINE__,
261
+ dcmp_id ++);
262
+ dcmp->m_name = tmp;
263
+
264
+ // Set a special attribute on the cell so that we don't give a "has no loads" warning
265
+ dcmp->m_attributes [" __IGNORE__NOLOAD__" ] = " 1" ;
266
+
267
+ // LOC it to DCMP1 to ensure correct routing
268
+ dcmp->m_attributes [" LOC" ] = " DCMP_1" ;
269
+
270
+ // Add the cell to the module
271
+ module->AddCell (dcmp);
272
+
273
+ // Create the PAR node for it
274
+ PARGraphNode* nnode = new PARGraphNode (ilmap[dcmp->m_type ], dcmp);
275
+ dcmp->m_parnode = nnode;
276
+ ngraph->AddNode (nnode);
277
+
278
+ // Copy the netlist edges to the PAR graph
279
+ // TODO: automate this somehow? Seems error-prone to do it twice
280
+ for (int i=0 ; i<8 ; i++)
281
+ {
282
+ snprintf (tmp, sizeof (tmp), " INN[%d]" , i);
283
+ netsrc->m_parnode ->AddEdge (driver.m_portname , nnode, tmp);
284
+ }
285
+ vddn->AddEdge (" OUT" , nnode, " PWRDN" );
286
+
287
+ dcmps.push_back (dcmp);
288
+ continue ;
289
+ }
290
+
291
+ // If exactly one, LOC it to DCMP1
292
+ else if (dcmps.size () == 1 )
293
+ {
294
+ // TODO: is it possible for IN+ to not be routable? If so, need to make a new DCMP to handle this
295
+ auto dcmp = *dcmps.begin ();
296
+ dcmp->m_attributes [" LOC" ] = " DCMP_1" ;
297
+ }
298
+
299
+ // TODO: If there's MORE than one DCMP driven by this signal, need to ensure one of them is placed at DCMP1
300
+ else
301
+ {
302
+ LogError (" Can't handle multiple DCMPs and a DAC all sharing the same input yet" );
303
+ return false ;
304
+ }
305
+ }
306
+
307
+ // Re-index the graph if we changed it
308
+ if (madeChanges)
309
+ {
310
+ LogNotice (" Re-indexing graph because we inferred additional nodes..\n " );
311
+ netlist->Reindex ();
312
+ ngraph->IndexNodesByLabel ();
313
+ madeChanges = false ;
219
314
}
220
315
221
316
// Look for IOBs driven by GP_VREF cells
@@ -362,6 +457,8 @@ void InferExtraNodes(
362
457
ngraph->IndexNodesByLabel ();
363
458
// madeChanges = false;
364
459
}
460
+
461
+ return true ;
365
462
}
366
463
367
464
/* *
0 commit comments