HAL
net_layout_junction.cpp
Go to the documentation of this file.
2 #ifdef JUNCTION_DEBUG
3 #include <QGraphicsScene>
4 #include <QGraphicsEllipseItem>
5 #include <QGraphicsLineItem>
6 #endif
7 #include <QBrush>
8 #include <QPen>
9 #include <QSet>
10 #include <QMultiMap>
11 #include <stdlib.h>
12 #include <QDebug>
13 #include <QPoint>
14 #include <QDir>
15 #include <QDateTime>
17 
18 #ifdef JUNCTION_DEBUG
19 QMap<u32,QColor> debugColorMap;
20 
21 QColor colorFromId(u32 netId)
22 {
23  QColor retval = debugColorMap.value(netId);
24  if (!retval.isValid())
25  return QColor("white");
26  return retval;
27 }
28 
29 void setColorMap(const hal::NetLayoutJunctionEntries& entries)
30 {
31  debugColorMap.clear();
32 
33  QMap<u32,int> pattern;
34  for (int i=0; i<4; i++)
35  {
36  int mask = 1 << i;
37  for (u32 id : entries.mEntries[i])
38  pattern[id] |= mask;
39  }
40  QSet<int> danglingWire = { 1, 2, 4, 8};
41  int count = 0;
42 
43  for (auto it = pattern.begin(); it != pattern.end(); ++it)
44  {
45  if (danglingWire.contains(it.value()))
46  {
47  debugColorMap[it.key()] = QColor::fromRgb(23,25,29);
48  continue;
49  }
50 
51  int hue = count++ * 25;
52  if (hue > 255)
53  {
54  int cc = (count-10)%20;
55  int cd = (count-10)/20;
56  int h = cc * 10;
57  int s = 80 - cd*40;
58  int v = 255;
59  qDebug() << cc << cd << h << s << v;
60  if (s <= 0)
61  {
62  int g = (20*count) % 128 + 128;
63  debugColorMap[it.key()] = QColor::fromRgb(g,g,g);
64  }
65  else
66  debugColorMap[it.key()] = QColor::fromHsv(h,s,v);
67  }
68  else
69  debugColorMap[it.key()] = QColor::fromHsv(hue,255,255);
70  }
71 }
72 
73 QGraphicsEllipseItem* getEllipse(QPoint p, u32 netId)
74 {
75  float dd = DELTA / 2.;
76  float x0 = FIRST + p.x() * DELTA - dd/2;
77  float y0 = FIRST + p.y() * DELTA - dd/2;
78  QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(x0,y0,dd,dd);
79  retval->setBrush(colorFromId(netId));
80  return retval;
81 }
82 #endif
83 
84 namespace hal {
85 
87  : mEntries(entries), mError(Ok)
88  {
89  memset(maxRoad,0,sizeof(maxRoad));
90  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
91  {
92  int iHoriz = dir.iHorizontal();
93  int n = mEntries.mEntries[dir.index()].size();
94  if (n>maxRoad[iHoriz]) maxRoad[iHoriz] = n;
95  for (int i=0; i<n; i++)
96  {
97 // qDebug() << "entry***" << i << n << dir.index() << mEntries.id(dir,i);
98  mNets[mEntries.id(dir,i)].addEntry(dir,i);
99  }
100  }
101  routeAllStraight(0,1);
102  routeAllStraight(2,3);
103  /*
104  for (auto netIt=mNets.begin(); netIt!=mNets.end(); ++netIt)
105  if (netIt.value().numberEntries()==4)
106  fourWayJunctions(netIt);
107  */
108  routeT();
109  routeAllCorner(0,2);
110  routeAllCorner(0,3);
111  routeAllCorner(1,2);
112  routeAllCorner(1,3);
113  routeAllMultiPin(0);
114  routeAllMultiPin(1);
115  findJunctions();
116  calculateRect();
117 
118  }
119 
120  void NetLayoutJunction::findJunctions()
121  {
122  for (auto it = mNets.begin(); it!= mNets.end(); ++it)
123  {
124  QList<NetLayoutJunctionWire> hNets, vNets;
125  for (const NetLayoutJunctionWire& nljw : it->mWires )
126  if (nljw.mIndex.hvIndex() == LaneIndex::Horizontal)
127  hNets.append(nljw);
128  else
129  vNets.append(nljw);
130 
131  for (const NetLayoutJunctionWire& hn : hNets)
132  for (const NetLayoutJunctionWire& vn : vNets)
133  if ((hn.mRange.innerPos(vn.mIndex.laneIndex()) && vn.mRange.contains(hn.mIndex.laneIndex())) ||
134  (hn.mRange.contains(vn.mIndex.laneIndex()) && vn.mRange.innerPos(hn.mIndex.laneIndex())))
135  it->mKnots.append(QPoint(vn.mIndex.laneIndex(),hn.mIndex.laneIndex()));
136  }
137  }
138 
139  void NetLayoutJunction::routeAllMultiPin(NetLayoutDirection leftOrRight)
140  {
141  int nEntries = mEntries.mEntries[leftOrRight.index()].size();
142 
144 
145  for (int iroad=0; iroad<nEntries; iroad++)
146  {
147  LaneIndex rinx(LaneIndex::Horizontal,iroad);
148  bool isRouted = false;
149  u32 id = mEntries.mEntries[leftOrRight.index()].at(iroad);
150  auto itNet = mNets.find(id);
151  Q_ASSERT(itNet != mNets.end());
152 
153  if (itNet.value().pattern() == (u32) (1 << leftOrRight.index() ))
154  {
156  isRouted = true;
157  }
158  else
159  {
161  for (const NetLayoutJunctionRange& rng : mOccupied.value(rinx))
162  {
163  if (rng.isEntry(leftOrRight.index()))
164  {
165  isRouted = true;
166  break;
167  }
168  // ... unless in the multipin case (isRouted=false)
169  }
170  }
171 
172  if (isRouted)
173  multiPinHash[id].mLane = iroad;
174  else
175  multiPinHash[id].mConnector.append(iroad);
176  }
177 
178  for (auto it = multiPinHash.begin(); it!= multiPinHash.end(); ++it)
179  {
180  if (it.value().mConnector.isEmpty()) continue;
181 // qDebug() << leftOrRight.index() << "MultiPin" << it.key() << it.value().mRoad << it.value().mConnector;
182  routeSingleMultiPin(it.key(), leftOrRight, it.value());
183  }
184 
185 
186  }
187 
188  void NetLayoutJunction::routeSingleMultiPin(u32 netId, NetLayoutDirection leftOrRight, const NetLayoutJunctionMultiPin& nmpin)
189  {
190  int ymin = nmpin.mLane;
191  int ymax = nmpin.mLane;
192  for (int iroad : nmpin.mConnector)
193  {
194  if (iroad < ymin) ymin = iroad;
195  if (iroad > ymax) ymax = iroad;
196  }
197 
198  int x0, x1, dx;
199  if (leftOrRight.isLeft())
200  {
201  x0 = -1;
203  dx = -1;
204  }
205  else
206  {
207  x0 = maxRoad[NetLayoutDirection::Right];
209  dx = 1;
210  }
211 
212  for (int x=x0; x!=x1; x+=dx)
213  {
214  QList<int> roads;
216  roads.append(x); // vertical first
217  rngs.append(NetLayoutJunctionRange(netId,ymin,ymax));
218  for (int iroad : nmpin.mConnector)
219  {
220  roads.append(iroad);
221  if (leftOrRight.isLeft())
222  rngs.append(NetLayoutJunctionRange(netId,x1,x));
223  else
224  rngs.append(NetLayoutJunctionRange(netId,x,x1));
225  }
226  bool hasConflict = false;
227 
228  // store connecting vertical road at i=0
229  for (int i=0; i<roads.size();i++)
230  {
231  if (conflict(LaneIndex(i?LaneIndex::Horizontal:LaneIndex::Vertical,roads.at(i)),rngs.at(i)))
232  {
233  hasConflict = true;
234  break;
235  }
236  }
237  if (!hasConflict)
238  {
239  for (int i=0; i<roads.size();i++)
240  place(LaneIndex(i?LaneIndex::Horizontal:LaneIndex::Vertical,roads.at(i)),rngs.at(i));
241  break;
242  }
243  }
244  }
245 
246  void NetLayoutJunction::calculateRect()
247  {
248  int x0, y0, x1, y1;
249  x0 = y0 = x1 = y1 = 0;
250  int x,y;
251 
252  for (LaneIndex ri : mOccupied.keys())
253  {
254  switch (ri.hvIndex())
255  {
257  y = ri.laneIndex();
258  if (y<y0) y0 = y;
259  if (y+1>y1) y1 = y+1;
260  break;
261  case LaneIndex::Vertical:
262  x = ri.laneIndex();
263  if (x<x0) x0 = x;
264  if (x+1>x1) x1 = x+1;
265  break;
266  }
267  }
268 
269  // empty junction has size 1
270  if (y1<=0) y1 = 1;
271  if (x1<=0) x1 = 1;
272  mRect = QRect(x0,y0,x1-x0,y1-y0);
273 
274  //TODO: truncate nets to rect might be range function
275  for (auto itNet = mNets.begin(); itNet != mNets.end(); ++itNet)
276  {
277  auto itWire = itNet->mWires.begin();
278  while (itWire != itNet->mWires.end())
279  {
280  if (itWire->mRange.first() == NetLayoutJunctionRange::MinInf)
281  {
282  if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal)
283  itWire->mRange.setFirst(x0);
284  else
285  itWire->mRange.setFirst(y0);
286  }
287  if (itWire->mRange.last() == NetLayoutJunctionRange::MaxInf)
288  {
289  if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal)
290  itWire->mRange.setLast(x1-1);
291  else
292  itWire->mRange.setLast(y1-1);
293  }
294  if (itWire->mRange.length() <=0)
295  itWire = itNet->mWires.erase(itWire);
296  else
297  ++itWire;
298  }
299  }
300  }
301 
302 #ifdef JUNCTION_DEBUG
303  void NetLayoutJunction::toScene(QGraphicsScene* scene) const
304  {
305  scene->setBackgroundBrush(QBrush(QColor::fromRgb(80,80,80)));
306  QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA,
307  FIRST + (mRect.y() - 0.5) * DELTA,
308  mRect.width() * DELTA,
309  mRect.height() * DELTA);
310 
311  float xscene0 = bg.left() < 100 ? bg.left() - 100 : 0;
312  float xscene1 = bg.right() > 900 ? bg.right() + 100 : 1000;
313  float yscene0 = bg.top() < 100 ? bg.top() - 100 : 0;
314  float yscene1 = bg.bottom() > 900 ? bg.bottom() + 100 : 1000;
315  scene->setSceneRect(xscene0,yscene0,xscene1,yscene1);
316 
317  QGraphicsRectItem* item = new QGraphicsRectItem(bg);
318  item->setBrush(QBrush(Qt::black));
319  scene->addItem(item);
320 
321  for (auto netIt = mNets.constBegin(); netIt != mNets.constEnd(); ++netIt)
322  {
323  for(QPoint jp : netIt.value().junctionPoints())
324  {
325  QGraphicsEllipseItem* item = getEllipse(jp,netIt.key());
326  scene->addItem(item);
327  }
328  }
329 
330 
331  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
332  {
333  int nEntries = mEntries.mEntries[dir.index()].size();
334  for (int ientry=0; ientry<nEntries; ientry++)
335  {
336  u32 id = mEntries.mEntries[dir.index()].at(ientry);
337  QColor col = colorFromId(id);
338  float qEntry = FIRST + ientry * DELTA;
339  if (id==0) continue;
340 
341  QGraphicsLineItem* item = nullptr;
342  switch (dir.direction()) {
344  item = new QGraphicsLineItem(xscene0, qEntry, bg.left(), qEntry);
345  break;
347  item = new QGraphicsLineItem(bg.right(), qEntry,xscene1, qEntry);
348  break;
350  item = new QGraphicsLineItem(qEntry, yscene0, qEntry, bg.top());
351  break;
353  item = new QGraphicsLineItem(qEntry, bg.bottom(), qEntry, yscene1);
354  break;
355  default:
356  break;
357  }
358  item->setPen(QPen(QBrush(col),3.));
359  scene->addItem(item);
360  }
361  }
362  }
363 
364  void NetLayoutJunction::toSceneStep(QGraphicsScene* scene, int istep)
365  {
366  if (istep >= mOccupied.mHistory.size()) return;
367 
368  QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA,
369  FIRST + (mRect.y() - 0.5) * DELTA,
370  mRect.width() * DELTA,
371  mRect.height() * DELTA);
372 
373  const QPair<u32,NetLayoutJunctionWire>& pw = mOccupied.mHistory.at(istep);
374  QColor col = colorFromId(pw.first);
375 
376  float x0, x1, y0, y1;
377 
378  const LaneIndex& ri = pw.second.mIndex;
379  const NetLayoutJunctionRange& rng = pw.second.mRange;
380  if (ri.hvIndex()==LaneIndex::Horizontal)
381  {
382  y0 = y1 = FIRST + ri.laneIndex() * DELTA;
383  x0 = FIRST + rng.first() * DELTA;
384  if (x0 < bg.left()) x0 = bg.left();
385  x1 = FIRST + rng.last() * DELTA;
386  if (x1 > bg.right()) x1 = bg.right();
387  qDebug() << "---" << ri.laneIndex() << rng.first() << rng.last();
388  }
389  else
390  {
391  x0 = x1 = FIRST + ri.laneIndex() * DELTA;
392  y0 = FIRST + rng.first() * DELTA;
393  if (y0 < bg.top()) y0 = bg.top();
394  y1 = FIRST + rng.last() * DELTA;
395  if (y1 > bg.bottom()) y1 = bg.bottom();
396  qDebug() << " | " << ri.laneIndex() << rng.first() << rng.last();
397  }
398  QGraphicsLineItem* item = new QGraphicsLineItem(x0,y0,x1,y1);
399  item->setPen(QPen(QBrush(col),3.));
400  scene->addItem(item);
401  }
402 #endif
403 
404  void NetLayoutJunction::routeT()
405  {
406  for (auto itNet=mNets.begin(); itNet!=mNets.end();++itNet)
407  {
408  if (itNet.value().numberEntries() >= 3)
409  {
410  int i0, i1, ilink;
411  LaneIndex::HVIndex itravers, imaindir;
412  u32 reducedPattern;
413  switch (itNet.value().pattern())
414  {
415  case 7: // L U R
416  i0 = 0;
417  i1 = 1;
418  ilink = 2;
419  itravers = LaneIndex::Vertical;
420  reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 6;
421  break;
422  case 11: // L D R
423  i0 = 0;
424  i1 = 1;
425  ilink = 3;
426  itravers = LaneIndex::Vertical;
427  reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 9;
428  break;
429  case 13: // U L D
430  i0 = 2;
431  i1 = 3;
432  ilink = 0;
433  itravers = LaneIndex::Horizontal;
434  reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 9;
435  break;
436  case 14: // U R D
437  i0 = 2;
438  i1 = 3;
439  ilink = 1;
440  itravers = LaneIndex::Horizontal;
441  reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 6;
442  break;
443  default:
444  continue;
445  }
446 
447  int roadLink = itNet.value().laneIndex(ilink);
449  QList<NetLayoutJunctionWire> mainWires = itNet.value().wireAtPos(roadLink,imaindir);
450  if (mainWires.isEmpty())
451  {
452  qDebug() << "T-join not found";
453  continue;
454  }
455 
456  int minlen = 0;
457  NetLayoutJunctionRange rngT = NetLayoutJunctionRange::entryRange(ilink,0,itNet.key());
458 
459  for (const NetLayoutJunctionWire& nljw : mainWires)
460  {
461  NetLayoutJunctionRange rng =
462  NetLayoutJunctionRange::entryRange(ilink,nljw.mIndex.laneIndex(),itNet.key());
463  if (!minlen || rng.length() < rngT.length())
464  {
465  rngT = rng;
466  minlen = rng.length();
467  }
468  }
469 
470  if (conflict(LaneIndex(itravers,roadLink),rngT))
471  itNet->setPattern(reducedPattern);
472  else
473  {
474  place(LaneIndex(itravers,roadLink),rngT);
475  itNet->setPlaced();
476  }
477  }
478  }
479  }
480 
481  void NetLayoutJunction::routeAllCorner(NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic)
482  {
483  u32 searchPattern = dirHoriz.toPattern() | dirVertic.toPattern();
484  if (dirVertic.isUp())
485  for (auto it = mEntries.mEntries[dirHoriz.index()].begin();
486  it != mEntries.mEntries[dirHoriz.index()].end(); ++it)
487  {
488  NetLayoutJunctionNet net = mNets.value(*it);
489  if (net.hasPattern(searchPattern) && !net.isPlaced())
490  routeSingleCorner(*it,dirHoriz,dirVertic);
491  }
492  else
493  for (auto it = mEntries.mEntries[dirHoriz.index()].rbegin();
494  it != mEntries.mEntries[dirHoriz.index()].rend(); ++it)
495  {
496  NetLayoutJunctionNet net = mNets.value(*it);
497  if (net.hasPattern(searchPattern) && !net.isPlaced())
498  routeSingleCorner(*it,dirHoriz,dirVertic);
499  }
500  }
501 
502  void NetLayoutJunction::routeAllStraight(NetLayoutDirection dirFrom, NetLayoutDirection dirTo)
503  {
504  QMap<int,int> straightConnected;
505  u32 searchPattern = dirFrom.toPattern() | dirTo.toPattern();
506 
507  for (u32 netId : mEntries.mEntries[dirFrom.index()])
508  {
509  auto itNet = mNets.find(netId);
510  Q_ASSERT(itNet != mNets.end());
511 // qDebug () << "straight" << searchPattern << netId << itNet.value().hasPattern(searchPattern) << itNet.value().pattern();
512  if (itNet.value().hasPattern(searchPattern))
513  {
514  int iroadIn = itNet.value().laneIndex(dirFrom);
515  int iroadOut = itNet.value().laneIndex(dirTo);
516  if (straightConnected.contains(iroadIn) && straightConnected.contains(iroadOut))
517  routeSingleSwap(netId, (searchPattern==3?0:1), iroadIn, iroadOut);
518  else
519  routeSingleStraight(netId, (searchPattern==3?0:1), iroadIn, iroadOut);
520  ++straightConnected[iroadIn];
521  ++straightConnected[iroadOut];
522  if (itNet.value().numberEntries() % 2 ==0)
523  itNet->setPlaced();
524  }
525  }
526  }
527 
528  bool NetLayoutJunction::conflict(const LaneIndex&ri, const NetLayoutJunctionRange& testRng) const
529  {
530  auto itConflict = mOccupied.find(ri);
531  if (itConflict == mOccupied.end()) return false;
532  return itConflict.value().conflict(testRng);
533  }
534 
535  bool NetLayoutJunction::canJoin(const LaneIndex &ri, u32 netId, int pos) const
536  {
537  auto itJoin = mOccupied.find(ri);
538  if (itJoin == mOccupied.end()) return false;
539  return itJoin.value().canJoin(netId,pos);
540  }
541 
542  void NetLayoutJunction::place(const LaneIndex &ri, const NetLayoutJunctionRange &range)
543  {
544  NetLayoutJunctionOccupiedHash::AddOrMerge aom = mOccupied.addOrMerge(ri,range);
545 
546  auto netIt = mNets.find(range.netId());
547  Q_ASSERT(netIt!=mNets.end());
548  switch (aom.mType )
549  {
551  {
552  NetLayoutJunctionWire nljw(range,ri);
553  netIt->addWire(nljw);
554  break;
555  }
557  {
558  NetLayoutJunctionWire nljw(*aom.mNewRange,ri);
559  netIt->replaceWire(*aom.mOldRange,nljw);
560  break;
561  }
562  default:
563  break;
564  }
565  }
566 
567  void NetLayoutJunction::routeSingleSwap(u32 netId, int iMain, int iroadIn, int iroadOut)
568  {
569  int iJump = 1-iMain;
570  int iroadJump0 = -1;
571  int iroadJump1 = maxRoad[iJump];
572  int iroadDetour = maxRoad[iMain];
573 
574  LaneIndex riDetour(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadDetour);
575  LaneIndex riJump0(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump0);
576  LaneIndex riJump1(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump1);
577  LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn);
578  LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut);
579 
580  for (;;) // break when route found
581  {
582  NetLayoutJunctionRange rngIn(netId, NetLayoutJunctionRange::MinInf, riJump0.laneIndex());
583  NetLayoutJunctionRange rngJ0(netId, iroadIn, riDetour.laneIndex());
584  NetLayoutJunctionRange rngDt(netId, riJump0.laneIndex(), riJump1.laneIndex());
585  NetLayoutJunctionRange rngJ1(netId, iroadOut, riDetour.laneIndex());
586  NetLayoutJunctionRange rngOut(netId, riJump1.laneIndex(), NetLayoutJunctionRange::MaxInf);
587 
588 
589  if (conflict(riDetour,rngDt))
590  {
591  ++riDetour;
592  continue;
593  }
594  if (conflict(riJump1,rngJ1) ||
595  conflict(riMainOut,rngOut))
596  {
597  ++riJump1;
598  continue;
599  }
600  if (conflict(riJump0,rngJ0) ||
601  conflict(riMainIn,rngIn))
602  {
603  --riJump0;
604  continue;
605  }
606  place(riMainIn,rngIn);
607  place(riJump0,rngJ0);
608  place(riDetour,rngDt);
609  place(riJump1,rngJ1);
610  place(riMainOut,rngOut);
611  break;
612  }
613  }
614 
615  void NetLayoutJunction::routeSingleStraight(u32 netId, int iMain, int iroadIn, int iroadOut)
616  {
617  int iJump = 1-iMain;
618  if (iroadIn == iroadOut)
619  {
620  NetLayoutJunctionRange rng(netId,NetLayoutJunctionRange::MinInf, NetLayoutJunctionRange::MaxInf);
621  place(LaneIndex(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn),rng);
622  return;
623  }
624  int iroadLo = iroadIn;
625  int iroadHi = iroadOut;
626  int iroadJump = -1;
627  int isearchIncr = -1;
628  if (iroadIn > iroadOut)
629  {
630  iroadLo = iroadOut;
631  iroadHi = iroadIn;
632  iroadJump = maxRoad[iJump];
633  isearchIncr = 1;
634  }
635  for (;;iroadJump+=isearchIncr)
636  {
637  if (iroadJump <= NetLayoutJunctionRange::MinInf ||
638  iroadJump >= NetLayoutJunctionRange::MaxInf)
639  {
640  qDebug() << "cannot route straight" << (iMain ? "vertical" : "horizontal")
641  << netId << iroadIn << iroadOut;
642  return;
643  }
644  NetLayoutJunctionRange rngIn(netId,
646  iroadJump);
647  NetLayoutJunctionRange rngJump(netId, iroadLo, iroadHi);
648  NetLayoutJunctionRange rngOut(netId,
649  iroadJump,
651 
652  LaneIndex riJump(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump);
653  LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn);
654  LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut);
655  if (!conflict(riJump,rngJump) &&
656  !conflict(riMainOut,rngOut) &&
657  !conflict(riMainIn,rngIn))
658  {
659  place(riJump,rngJump);
660  place(riMainIn,rngIn);
661  place(riMainOut,rngOut);
662  break;
663  }
664  }
665  }
666 
668  {
669  // operator will create entry if not existing
670  NetLayoutJunctionOccupied& nljo = this->operator[](ri);
671 
672  AddOrMerge retval;
673 
674  for (auto it = nljo.begin(); it!= nljo.end(); ++it)
675  {
676  if (*it == rng)
677  {
679  break;
680  }
681  if (it->canJoin(rng))
682  {
683  retval.mOldRange = new NetLayoutJunctionRange(*it);
684  it->expand(rng);
685  retval.mNewRange = new NetLayoutJunctionRange(*it);
686  retval.mType = AddOrMerge::Merged;
687  break;
688  }
689  }
690 
691  if (retval.mType == AddOrMerge::Added)
692  nljo.append(rng);
693 
694 #ifdef JUNCTION_DEBUG
695  mHistory.append(qMakePair(rng.netId(),NetLayoutJunctionWire(rng,ri)));
696 #endif
697  return retval;
698  }
699 
700  void NetLayoutJunction::routeSingleCorner(u32 netId, NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic)
701  {
702  auto netIt = mNets.find(netId);
703  Q_ASSERT(netIt != mNets.end());
704 
705  int iroadHoriz = netIt.value().laneIndex(dirHoriz);
706  int iroadVertic = netIt.value().laneIndex(dirVertic);
707 
708  // Try to connect straight lines directly without detour
710  NetLayoutJunctionRange::entryRange(dirHoriz,iroadVertic,netId);
712  NetLayoutJunctionRange::entryRange(dirVertic,iroadHoriz,netId);
713  if (!conflict(LaneIndex::horizontal(iroadHoriz),rngH) && !conflict(LaneIndex::vertical(iroadVertic),rngV))
714  {
715  place(LaneIndex::horizontal(iroadHoriz),rngH);
716  place(LaneIndex::vertical(iroadVertic),rngV);
717  netIt->setPlaced();
718  return;
719  }
720 
721  // OK, we need around corner detour
722  int hcroad = dirVertic.isUp() ? -1 : mEntries.mEntries[dirHoriz.index()].size();
723  int hstep = dirVertic.isUp() ? -1 : 1;
724  int vcroad = dirHoriz.isLeft() ? -1 : mEntries.mEntries[dirVertic.index()].size();
725  int vstep = dirHoriz.isLeft() ? -1 : 1;
726 
727  int icount = 0;
728  int tryMax = 2 * mOccupied.size();
729  for (int i=0; i<4; i++)
730  tryMax += 2* mEntries.mEntries[i].size();
731  for(;;)
732  {
733  NetLayoutJunctionRange rngVc(netId,iroadHoriz,hcroad);
734  NetLayoutJunctionRange rngHc(netId,iroadVertic,vcroad);
735  NetLayoutJunctionRange rngHe =
736  NetLayoutJunctionRange::entryRange(dirHoriz,vcroad,netId);
737  NetLayoutJunctionRange rngVe =
738  NetLayoutJunctionRange::entryRange(dirVertic,hcroad,netId);
739 
740  if (++icount > tryMax)
741  {
742  qDebug() << "giving up";
743  mError = CornerRouteError;
744  return;
745  }
746 
747 // qDebug() << "try" << netId << iroadHoriz << iroadVertic << hcroad << vcroad;
748 
749  if (conflict(LaneIndex::horizontal(hcroad),rngHc) || conflict(LaneIndex::vertical(iroadVertic),rngVe))
750  hcroad += hstep;
751  else if (conflict(LaneIndex::vertical(vcroad),rngVc) || conflict(LaneIndex::horizontal(iroadHoriz),rngHe))
752  vcroad += vstep;
753  else
754  {
755  place(LaneIndex::horizontal(hcroad),rngHc);
756  place(LaneIndex::vertical(vcroad),rngVc);
757 
758  place(LaneIndex::horizontal(iroadHoriz),rngHe);
759  place(LaneIndex::vertical(iroadVertic),rngVe);
760  netIt->setPlaced();
761  break;
762  }
763  }
764  }
765 
767  {
768  for (NetLayoutJunction* nlj : values())
769  delete nlj;
770  clear();
771  }
772 
773 
775  : mPattern(0), mEntries(0), mPlaced(false)
776  {
777  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
778  mLaneIndex[dir.index()] = -1;
779  }
780 
782  {
783  mPattern |= dir.toPattern();
784  mLaneIndex[dir.index()] = laneInx;
785  ++mEntries;
786  }
787 
788  bool NetLayoutJunctionNet::hasPattern(u32 searchPattern) const
789  {
790  return (mPattern & searchPattern) == searchPattern;
791  }
792 
794  {
795  for (auto it = mWires.begin(); it!= mWires.end(); ++it)
796  if (rng == *it)
797  {
798  *it = wire;
799  return;
800  }
801  }
802 
804  {
806  for (auto it = mWires.begin(); it!= mWires.end(); ++it)
807  if (it->mIndex.hvIndex() == hvi && it->mRange.contains(pos))
808  retval.append(*it);
809  return retval;
810  }
811 
813  {
814  QString retval;
815  const char* dirChar = "LRUD";
816  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
817  {
818  if (mPattern & dir.toPattern())
819  {
820  if (!retval.isEmpty()) retval += ":";
821  retval += QString("%1%2").arg(dirChar[dir.index()]).arg(mLaneIndex[dir.index()]);
822  }
823  }
824  return retval;
825  }
826 
828  : mNetId(netId_), mFirst(first), mLast(last)
829  {
830  if (last < first)
831  {
832  mFirst = last;
833  mLast = first;
834  }
835  }
836 
838  {
839  const int first[4] = { MinInf, ilane, MinInf, ilane };
840  const int last[4] = { ilane, MaxInf, ilane, MaxInf };
841  return NetLayoutJunctionRange(netId, first[dir.index()], last[dir.index()]);
842  }
843 
845  {
846  if (mNetId != other.mNetId) return false;
847  if (mFirst > other.mLast) return false;
848  if (other.mFirst > mLast) return false;
849  return true;
850  }
851 
853  {
854  return (mNetId == other.mNetId &&
855  mFirst == other.mFirst &&
856  mLast == other.mLast);
857  }
858 
860  {
861  return (mFirst == wire.mRange.mFirst && mLast == wire.mRange.mLast);
862  }
863 
864 
866  {
867  if (mNetId == other.mNetId) return false;
868  if (other.mLast < mFirst || mLast < other.mFirst) return false;
869  return true;
870  }
871 
872  int NetLayoutJunctionRange::endPosition(int iGetLast) const
873  {
874  if (!iGetLast) return mFirst;
875  return mLast;
876  }
877 
878  bool NetLayoutJunctionRange::isEntry(int iTestMax) const
879  {
880  if (iTestMax) return (mLast == MaxInf);
881  return (mFirst == MinInf);
882  }
883 
885  {
886  if (other.mFirst < mFirst) mFirst = other.mFirst;
887  if (other.mLast > mLast) mLast = other.mLast;
888  }
889 
890  bool NetLayoutJunctionOccupied::canJoin(u32 netId, int pos) const
891  {
892  for (const NetLayoutJunctionRange& r : *this)
893  {
894  if (r.netId() != netId) continue;
895  if (r.contains(pos)) return true;
896  }
897  return false;
898  }
899 
901  {
902  for (const NetLayoutJunctionRange& r : *this)
903  if (r.conflict(test)) return true;
904  return false;
905  }
906 
908  {
909  return mRange.isEntry(0) || mRange.isEntry(1);
910  }
911 
913  {
918  return false;
919  }
920 
922  {
923  QFile ff(QString::fromStdString(ProjectManager::instance()->get_project_directory().get_filename("junction_data.txt").string()));
924  if (!ff.open(QIODevice::WriteOnly | QIODevice::Append)) return;
925  QTextStream xout(&ff);
926  xout << "(" << pnt.x() << "," << pnt.y() << ")\n";
927  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
928  {
929  for (u32 id : mEntries[dir.index()])
930  xout << " " << id;
931  xout << "\n";
932  }
933  xout.flush();
934  }
935 
937  {
938  QFile ff(QString::fromStdString(ProjectManager::instance()->get_project_directory().get_filename("junction_data.txt").string()));
939  if (!ff.open(QIODevice::WriteOnly)) return;
940  ff.write(QDateTime::currentDateTime().toLocalTime().toString("--- dd.MM.yyyy hh:mm:ss ---\n").toUtf8());
941  }
942 
944  {
945  QString retval;
946  for (NetLayoutDirection dir(0); !dir.isMax(); ++dir)
947  {
948  retval += QString(" entries.mEntries[%1]").arg(dir.index());
949  for (u32 id : mEntries[dir.index()])
950  retval += QString(" << %1").arg(id);
951  retval += ";\n";
952  }
953  return retval;
954  }
955 
956  uint qHash(const LaneIndex& ri) { return ri.mIndex; }
957 } // namespace hal
int laneIndex() const
static LaneIndex horizontal(int ilane)
static LaneIndex vertical(int ilane)
HVIndex hvIndex() const
u32 id(NetLayoutDirection dir, int ilane) const
void dumpToFile(const QPoint &pnt) const
NetLayoutJunction(const NetLayoutJunctionEntries &entries)
QList< NetLayoutJunctionWire > wireAtPos(int pos, LaneIndex::HVIndex hvi)
QList< NetLayoutJunctionWire > mWires
void addEntry(NetLayoutDirection dir, int laneInx)
void replaceWire(const NetLayoutJunctionRange &rng, const NetLayoutJunctionWire &wire)
bool hasPattern(u32 searchPattern) const
enum hal::NetLayoutJunctionOccupiedHash::AddOrMerge::Type mType
AddOrMerge addOrMerge(const LaneIndex &ri, const NetLayoutJunctionRange &rng)
bool conflict(const NetLayoutJunctionRange &test) const
bool canJoin(u32 netId, int pos) const
int endPosition(int iGetLast) const
bool conflict(const NetLayoutJunctionRange &other) const
void expand(const NetLayoutJunctionRange &other)
bool canJoin(const NetLayoutJunctionRange &other) const
static NetLayoutJunctionRange entryRange(NetLayoutDirection dir, int ilane, u32 netId)
NetLayoutJunctionRange(u32 netId_, int first, int last)
bool operator==(const NetLayoutJunctionRange &other) const
bool isEntry(int iTestMax) const
NetLayoutJunctionRange mRange
static ProjectManager * instance()
uint qHash(const LaneIndex &ri)
Definition: test.py:1
n
Definition: test.py:6
const int DELTA
const int FIRST
quint32 u32
Net * net
i32 id
void setBrush(const QBrush &brush)
QColor fromHsv(int h, int s, int v, int a)
QColor fromRgb(QRgb rgb)
bool isValid() const const
QDateTime currentDateTime()
void setPen(const QPen &pen)
void addItem(QGraphicsItem *item)
void setBackgroundBrush(const QBrush &brush)
void setSceneRect(const QRectF &rect)
T & value() const const
QHash::iterator begin()
QHash::iterator end()
QHash::iterator find(const Key &key)
QList< Key > keys() const const
int size() const const
const T value(const Key &key) const const
void append(const T &value)
const T & at(int i) const const
QList::iterator begin()
QList::iterator end()
bool isEmpty() const const
QList::reverse_iterator rbegin()
QList::reverse_iterator rend()
int size() const const
T value(int i) const const
QMap::iterator begin()
void clear()
bool contains(const Key &key) const const
QMap::iterator end()
const T value(const Key &key, const T &defaultValue) const const
int x() const const
int y() const const
int height() const const
int width() const const
int x() const const
int y() const const
bool contains(const T &value) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
void flush()