From ee7b053db9f38fc14deaab9adf93b26412f2df8e Mon Sep 17 00:00:00 2001 From: joern274 Date: Wed, 29 Mar 2023 16:48:24 +0200 Subject: [PATCH 01/22] measure performance marker for callgrind inserted --- plugins/gui/src/graph_widget/layouters/graph_layouter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 15ef6ebee91..c5940f56d3d 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -18,6 +18,7 @@ #include "hal_core/netlist/module.h" #include "hal_core/netlist/net.h" +#include #include #include #include @@ -253,7 +254,10 @@ namespace hal createBoxes(); if (mOptimizeNetLayout) { + CALLGRIND_START_INSTRUMENTATION; alternateLayout(); + CALLGRIND_STOP_INSTRUMENTATION; + CALLGRIND_DUMP_STATS; qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); return; } From 60df168ee2865e4509753e553fb2f194e5ad31eb Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 4 Apr 2023 10:29:54 +0200 Subject: [PATCH 02/22] find duplicate net bug --- .../items/nets/standard_graphics_net.h | 2 +- .../graph_widget/layouters/net_layout_junction.h | 2 +- .../items/nets/standard_graphics_net.cpp | 16 +++++++++++++++- .../graph_widget/layouters/graph_layouter.cpp | 8 ++------ .../layouters/net_layout_junction.cpp | 12 ++++++++++++ 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h index 85cc07e027d..b85e743dc9c 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h @@ -96,7 +96,7 @@ namespace hal /** * Merges all horizontal and vertical lines so that overlapping lines are replaced by only a single line. */ - void mergeLines(); + void mergeLines(QGraphicsScene* sc); /** * Gets the total amount of lines (includes horizontal AND vertical lines). diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index 70b05eaacdf..e500f8d3656 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -122,7 +122,7 @@ namespace hal { void setPattern(u32 pat) { mPattern = pat; } bool isPlaced() const { return mPlaced; } void setPlaced() { mPlaced = true; } - void addWire(const NetLayoutJunctionWire& wire) { mWires.append(wire); } + void addWire(const NetLayoutJunctionWire& wire); NetLayoutJunctionWireIntersection junctionPoint() const { return mJunction; } void setJunctionPoint(const NetLayoutJunctionWireIntersection& jp, NetLayoutJunctionWireIntersection::PlacementType placement diff --git a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp index 9ed8199b9c4..fc1fa322916 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include namespace hal { @@ -205,8 +208,9 @@ namespace hal mVLines.append(VLine{x, mSmallY, mBigY}); } - void StandardGraphicsNet::Lines::mergeLines() + void StandardGraphicsNet::Lines::mergeLines(QGraphicsScene *sc) { + qDebug() << "optimal number threads" << QThread::idealThreadCount(); QVector merged_h_lines; QVector merged_v_lines; @@ -220,6 +224,11 @@ namespace hal if (h.mBigX < merged_h_lines.at(i).mSmallX || merged_h_lines.at(i).mBigX < h.mSmallX) continue; + qreal x0 = merged_h_lines.at(i).mSmallX > h.mSmallX ? merged_h_lines.at(i).mSmallX : h.mSmallX; + qreal x1 = merged_h_lines.at(i).mBigX < h.mBigX ? merged_h_lines.at(i).mBigX : h.mBigX; + + qDebug() << "h-ov" << h.y << x0 << x1; +// sc->addLine(x0,h.y,x1,h.y,QPen(Qt::yellow)); overlaps.append(i); } @@ -257,6 +266,11 @@ namespace hal if (v.mBigY < merged_v_lines.at(i).mSmallY || merged_v_lines.at(i).mBigY < v.mSmallY) continue; + qreal y0 = merged_v_lines.at(i).mSmallY > v.mSmallY ? merged_v_lines.at(i).mSmallY : v.mSmallY; + qreal y1 = merged_v_lines.at(i).mBigY < v.mBigY ? merged_v_lines.at(i).mBigY : v.mBigY; + + qDebug() << "v-ov" << v.x << y0 << y1; +// sc->addLine(v.x,y0,v.x,y1,QPen(Qt::red)); overlaps.append(i); } diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index c5940f56d3d..f541eb31f53 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -18,7 +18,6 @@ #include "hal_core/netlist/module.h" #include "hal_core/netlist/net.h" -#include #include #include #include @@ -254,10 +253,7 @@ namespace hal createBoxes(); if (mOptimizeNetLayout) { - CALLGRIND_START_INSTRUMENTATION; alternateLayout(); - CALLGRIND_STOP_INSTRUMENTATION; - CALLGRIND_DUMP_STATS; qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); return; } @@ -1412,7 +1408,7 @@ namespace hal drawNetsJunction(lines, id); drawNetsEndpoint(lines, id); - lines.mergeLines(); + lines.mergeLines(mScene); GraphicsNet* graphicsNet = nullptr; switch (epl.netType()) @@ -2348,7 +2344,7 @@ namespace hal } } - lines.mergeLines(); + lines.mergeLines(mScene); if (lines.nLines() > 0) { StandardGraphicsNet* GraphicsNet = new StandardGraphicsNet(n, lines); diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index c042f1b72df..f0104d1b721 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -808,6 +808,18 @@ namespace hal { return mFirst; } + void NetLayoutJunctionNet::addWire(const NetLayoutJunctionWire& wire) + { + for (const NetLayoutJunctionWire& w : mWires) + if (w.mHorizontal == wire.mHorizontal && + w.mRoad == wire.mRoad && + (w.mLast < wire.mFirst || w.mFirst > wire.mLast )) + { + qDebug() << "junction" << w.mHorizontal << w.mRoad << w.mFirst << w.mLast << wire.mFirst << wire.mLast; + } + mWires.append(wire); + } + bool NetLayoutJunctionWire::isEntry() const { return mFirst == NetLayoutJunctionRange::sMinInf From 24031b1135cd3f7e5d16fc02ef82dc5a6f7af648 Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 27 Jun 2023 14:52:41 +0200 Subject: [PATCH 03/22] Next step debugging duplicate junction road --- .../gui/src/graph_widget/items/nets/standard_graphics_net.cpp | 4 ++-- plugins/gui/src/graph_widget/layouters/graph_layouter.cpp | 4 ++-- .../gui/src/graph_widget/layouters/net_layout_junction.cpp | 3 --- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp index fc1fa322916..0dee11df7d3 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp @@ -228,7 +228,7 @@ namespace hal qreal x1 = merged_h_lines.at(i).mBigX < h.mBigX ? merged_h_lines.at(i).mBigX : h.mBigX; qDebug() << "h-ov" << h.y << x0 << x1; -// sc->addLine(x0,h.y,x1,h.y,QPen(Qt::yellow)); + sc->addLine(x0,h.y,x1,h.y,QPen(Qt::yellow)); overlaps.append(i); } @@ -270,7 +270,7 @@ namespace hal qreal y1 = merged_v_lines.at(i).mBigY < v.mBigY ? merged_v_lines.at(i).mBigY : v.mBigY; qDebug() << "v-ov" << v.x << y0 << y1; -// sc->addLine(v.x,y0,v.x,y1,QPen(Qt::red)); + sc->addLine(v.x,y0,v.x,y1,QPen(Qt::red)); overlaps.append(i); } diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index f541eb31f53..3210f16e9d3 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -631,8 +631,8 @@ namespace hal for (auto it = mJunctionEntries.constBegin(); it != mJunctionEntries.constEnd(); ++it) { - // it.value().dumpFile(it.key()); - // qDebug() << "Junction at" << it.key().x() << it.key().y(); + it.value().dumpFile(it.key()); + qDebug() << "Junction at" << it.key().x() << it.key().y(); NetLayoutJunction* nlj = new NetLayoutJunction(it.value()); if (nlj->lastError() != NetLayoutJunction::Ok) qDebug() << "Junction route error" << nlj->lastError() << it.key(); diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index f0104d1b721..fbeabe38e92 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -586,9 +586,6 @@ namespace hal { place(1,vcroad,rngVc); place(0,iroadHoriz,rngHe); place(1,iroadVertic,rngVe); - mOccupied[1][vcroad].append(rngVc); - mOccupied[0][iroadHoriz].append(rngHe); - mOccupied[1][iroadVertic].append(rngVe); netIt->setPlaced(); break; } From ff125dec831fc8ae61ccfbab8553e366913ab4e0 Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 23 Oct 2023 10:03:53 +0200 Subject: [PATCH 04/22] Makeover for class NetLayoutJunction --- .../layouters/net_layout_junction.h | 427 ++++++--- .../graph_widget/layouters/graph_layouter.cpp | 33 +- .../layouters/net_layout_junction.cpp | 831 +++++++++--------- 3 files changed, 750 insertions(+), 541 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index e500f8d3656..3ba33ba072e 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -1,28 +1,3 @@ -// MIT License -// -// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. -// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. -// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. -// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - #pragma once #include @@ -32,142 +7,370 @@ #include #include #include -#include "net_layout_point.h" +#include "gui/graph_widget/layouters/net_layout_point.h" + +// #define JUNCTION_DEBUG = 1 class QGraphicsEllipseItem; class QGraphicsLineItem; class QGraphicsScene; +const int DELTA = 20; +const int FIRST = 400; +const int GAP = 200; + QColor colorFromId(u32 netId); namespace hal { /** - * @ingroup gui + * Condensed lane index comprises information whether road is horizontal or vertical + * + * @ingroup graph-layouter */ - class NetLayoutJunctionWireIntersection : public QPoint + class LaneIndex { - bool mValid; + friend uint qHash(const LaneIndex& ri); + int mIndex; public: - NetLayoutJunctionWireIntersection(bool valid=false, int x_=0, int y_=0) - : QPoint(x_,y_), mValid(valid) {;} - enum PlacementType { Normal, Verify, Endpoint }; - bool isValid() const { return mValid; } - QGraphicsEllipseItem* graphicsFactory(u32 netId) const; + enum HVIndex { Horizontal, Vertical }; + + /** + * Constructor + * @param ihv Horizontal or Vertical + * @param ilane Lane index + */ + LaneIndex(HVIndex ihv, int ilane) : mIndex(ihv | (ilane << 1)) {;} + + /** + * Cast to integer, mainly used as index + */ + operator int () const { return mIndex; } + + /** + * Increment to next parallel lane + * @return The incremented index + */ + LaneIndex& operator++() { mIndex += 2; return *this; } + + /** + * Decrement to previous parallel lane + * @return The decremented index + */ + LaneIndex& operator--() { mIndex -= 2; return *this; } + + /** + * Getter for road direction + * @return Horizontal or Vertical + */ + HVIndex hvIndex() const { return (HVIndex) (mIndex & 1); } + + /** + * Getter for lane index + * @return The index (might be negative) + */ + int laneIndex() const { return (mIndex >> 1); } + + /** + * Convenience method to check whether road direction is horizontal + * @return true if horizontal, false otherwise + */ + bool isHorizontal() const { return hvIndex() == Horizontal; } + + /** + * Convenience method to check whether road direction is vertical + * @return true if vertical, false otherwise + */ + bool isVertical() const { return hvIndex() == Vertical; } + + /** + * Construct horizontal lane + * @param ilane - lane index + */ + static LaneIndex horizontal(int ilane) { return LaneIndex(Horizontal,ilane); } + + /** + * Construct vertical lane + * @param ilane - lane index + */ + static LaneIndex vertical(int ilane) { return LaneIndex(Vertical,ilane); } }; + class NetLayoutJunctionWire; + /** + * Range including first and last grid point (potentially) on lane used by net id. + * External nets leading to junction start at MinInf or MaxInf. + * * @ingroup graph-layouter */ - class NetLayoutJunctionWire + class NetLayoutJunctionRange { - public: - int mHorizontal; - int mRoad; + u32 mNetId; int mFirst; int mLast; - NetLayoutJunctionWire(int hor, int rd, int fir, int las) - : mHorizontal(hor), mRoad(rd), mFirst(fir), mLast(las) {;} - NetLayoutJunctionWireIntersection intersection(const NetLayoutJunctionWire& other) const; - bool isEntry() const; - int centralEnd() const; + public: + static const int MinInf = -32767; + static const int MaxInf = 32767; + + NetLayoutJunctionRange(u32 netId_, int first, int last); + + /** + * Check whether range instance would overlap with instance from other net + * @param other Possibly conflicting range + * @return true if nets are different and share at least a common point, false otherwise + */ + bool conflict(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether position is within range including first and last grid point + * @param pos Relevant coordinate from grid point to check + * @return true if in range according to condition above, false otherwise + */ + bool contains(int pos) const { return mFirst <= pos && pos <= mLast; } + + /** + * Checks whether position is within range excluding first and last grid point + * @param pos Relevant coordinate from grid point to check + * @return true if in range according to condition above, false otherwise + */ + bool innerPos(int pos) const { return mFirst < pos && pos < mLast; } + + /** + * Checks whether ranges of same net can be joined to bigger range + * @param other Range which might be joined + * @return true if range can be joined, false otherwise + */ + bool canJoin(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether range is entry from external net + * @param iTestMax Test for MinInf if 0, MaxInf otherwise + * @return true if range is entry from external net + */ + bool isEntry(int iTestMax) const; + + /** + * Checks whether two ranges are equal + */ + bool operator==(const NetLayoutJunctionRange& other) const; + + /** + * Checks whether range from wire is equal with this range + */ + bool operator==(const NetLayoutJunctionWire& wire) const; + + /** + * Getter for net ID + * @return the net ID + */ + u32 netId() const { return mNetId; } + + /** + * Getter for first grid point position in range + * @return the first grid point position in range + */ + int first() const { return mFirst; } + + /** + * Setter for first grid point position in range + * @param fst the new first grid point position in range + */ + void setFirst(int fst) { mFirst = fst; } + + /** + * Getter for last grid point position in range + * @return the last grid point position in range + */ + int last() const { return mLast; } + + /** + * Setter for last grid point position in range + * @param lst the new last grid point position in range + */ + void setLast(int lst) { mLast = lst; } + + /** + * Getter for the difference between first and last grid point of range + * @return the differnce between first and last + */ + int length() const { return mLast-mFirst; } + + /** + * Getter for the first or last grid position in range + * @param iGetLast get first position if 0, last positon otherwise + * @return the first or last grid position in range + */ + int endPosition(int iGetLast) const; + + /** + * Expand the range by joining other range + * @param other The other range + */ + void expand(const NetLayoutJunctionRange& other); + + /** + * Return range parameter as human readable string + * @return The string + */ + QString toString() const { return QString("<%1|%2..%3>").arg(mNetId).arg(mFirst).arg(mLast); } + + /** + * Generate an entry range + * @param dir Direction (Left, Right, Up, Down) + * @param ilane Lane index + * @param netId Net ID + * @return The range + */ + static NetLayoutJunctionRange entryRange(NetLayoutDirection dir, int ilane, u32 netId); }; /** + * Single straight wire located in a range of a lane + * * @ingroup graph-layouter */ + class NetLayoutJunctionWire + { + public: + /** + * Lane index + */ + LaneIndex mIndex; + + /** + * Range including net id + */ + NetLayoutJunctionRange mRange; + + /** + * constructor + */ + NetLayoutJunctionWire(const NetLayoutJunctionRange& rng, const LaneIndex& li) + : mIndex(li), mRange(rng) {;} + + /** + * Checks whether wire is entry from external net + * @return true if wire is entry from external net, false otherwise + */ + bool isEntry() const; + }; + + /** + * List of nets entering the junction sorted by entry direction + */ class NetLayoutJunctionEntries { - friend class NetLayoutJunction; - protected: - QList mEntries[4]; public: - int size(NetLayoutDirection dir) const { return mEntries[dir.index()].size(); } - u32 id(NetLayoutDirection dir, int i) const { return mEntries[dir.index()].at(i); } - QString dump() const; - void dumpFile(const NetLayoutPoint& pnt) const; - void setEntries(NetLayoutDirection dir, const QList& entries_); + /** + * Entries sorted by direction (Left, Right, Up, Down) + */ + QList mEntries[4]; + + /** + * Get net ID from junction entry list / array + * @param dir Direction (Left, Right, Up, Down) + * @param ilane Lane index + * @return Net ID + */ + u32 id(NetLayoutDirection dir, int ilane) const { return mEntries[dir.index()].at(ilane); } + + /** + * String output for debugging purpose + */ + QString toString() const; }; + /** + * Connection more than one gate pin with the same wire + */ class NetLayoutJunctionMultiPin { public: - int mRoad; + /** + * The lane connecting the gate which was routed first + */ + int mLane; + + /** + * Other lanes (except mLane) connecting the net with the gate + */ QList mConnector; - NetLayoutJunctionMultiPin() : mRoad(-1) {} - void setRoad(int road) { mRoad = road; } + + /** + * Constructor + */ + NetLayoutJunctionMultiPin() : mLane(-1) {} }; /** + * @brief Single net to be routed through the junction + * + * At this point there can only be one entry point for each given direction. * @ingroup graph-layouter */ class NetLayoutJunctionNet { - u32 mPattern; - int mRoadNumber[4]; // index: Left = 0, Right = 1, Up = 2, Down = 3 value: -1 = unused + u32 mPattern; // binary pattern + int mLaneIndex[4]; // index: Left = 0, Right = 1, Up = 2, Down = 3 value: -1 = unused int mEntries; bool mPlaced; - NetLayoutJunctionWireIntersection mJunction; public: QList mWires; + QList mJunctions; NetLayoutJunctionNet(); - void addEntry(NetLayoutDirection dir, int roadNo); + void addEntry(NetLayoutDirection dir, int laneInx); QString toString() const; + + /** + * Check whether search pattern is included in binary pattern + * @param searchPattern Combination of Left (bit 0), Right (bit 1), Up (bit 2), Down (bit 3) + * @return true if search pattern is included in binary pattern, false otherwise + */ bool hasPattern(u32 searchPattern) const; - int roadNumber(NetLayoutDirection dir) const { return mRoadNumber[dir.index()]; } + int laneIndex(NetLayoutDirection dir) const { return mLaneIndex[dir.index()]; } int numberEntries() const { return mEntries; } u32 pattern() const { return mPattern; } void setPattern(u32 pat) { mPattern = pat; } bool isPlaced() const { return mPlaced; } + QList wireAtPos(int pos, LaneIndex::HVIndex hvi); void setPlaced() { mPlaced = true; } - void addWire(const NetLayoutJunctionWire& wire); - NetLayoutJunctionWireIntersection junctionPoint() const { return mJunction; } - void setJunctionPoint(const NetLayoutJunctionWireIntersection& jp, - NetLayoutJunctionWireIntersection::PlacementType placement - = NetLayoutJunctionWireIntersection::Normal); + void addWire(const NetLayoutJunctionWire& wire) { mWires.append(wire); } + void replaceWire(const NetLayoutJunctionRange& rng, const NetLayoutJunctionWire& wire); + QList junctionPoints() const { return mJunctions; } }; /** * @ingroup graph-layouter */ - class NetLayoutJunctionRange + class NetLayoutJunctionOccupied : public QList { - u32 mNetId; - int mFirst; - int mLast; public: - static const int sMinInf = -32767; - static const int sMaxInf = 32767; - static const int sSceneDelta = 20; - static const int sSceneFirst = 400; - static const int sSceneGap = 200; - NetLayoutJunctionRange(u32 netId_, int first, int last); - - NetLayoutJunctionWire toWire(int hor, int rd) const; - bool conflict(const NetLayoutJunctionRange& other) const; + bool conflict(const NetLayoutJunctionRange& test) const; bool canJoin(u32 netId, int pos) const; - bool canJoin(const NetLayoutJunctionRange& other) const; - u32 netId() const { return mNetId; } - int endPosition(int inx) const; - bool isEntry(int inx) const; - int graphFirst() const; - int graphLast() const; - bool operator==(const NetLayoutJunctionRange& other) const; - void expand(const NetLayoutJunctionRange& other); - static NetLayoutJunctionRange entryRange(NetLayoutDirection dir, int iroad, u32 netId); }; /** * @ingroup graph-layouter */ - class NetLayoutJunctionOccupied : public QList + class NetLayoutJunctionOccupiedHash : public QHash { public: - bool conflict(const NetLayoutJunctionRange& test) const; - bool canJoin(u32 netId, int pos) const; - void add(const NetLayoutJunctionRange& rng); + enum AddType { None, Added, Merged }; + + /** + * Adds new entry for range or merges it + * @param ri Road index where to add + * @param rng Range to add, will be modified on merge + * @return see AddType above. + */ + AddType addOrMerge(const LaneIndex &ri, NetLayoutJunctionRange& rng); + +#ifdef JUNCTION_DEBUG + QList> mHistory; +#endif }; /** @@ -180,37 +383,47 @@ namespace hal { ~NetLayoutJunction() {;} QRect rect() const { return mRect; } void dump() const; - NetLayoutJunctionNet netById(u32 id) const { return mNetsOutput.value(id); } - enum mErrorT {StraightRouteError = -2, CornerRouteError = -1, Ok = 0 }; - mErrorT lastError() const { return mError; } + NetLayoutJunctionNet netById(u32 id) const { return mNets.value(id); } + +#ifdef JUNCTION_DEBUG + void toScene(QGraphicsScene* scene) const; + void toSceneStep(QGraphicsScene* scene, int istep); + int numberSteps() const { return mOccupied.mHistory.size(); } +#endif private: - void fourWayJunctions(QHash::iterator& netIt); void routeT(); void routeAllStraight(NetLayoutDirection dirFrom, NetLayoutDirection dirTo); void routeAllCorner(NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic); void routeSingleStraight(u32 netId, int iMain, int iroadIn, int iroadOut); - void routeSingleDetour(u32 netId, int iMain, int iroadIn, int iroadOut); + void routeSingleSwap(u32 netId, int iMain, int iroadIn, int iroadOut); void routeSingleCorner(u32 netId, NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic); + + /** + * Connect nets with multiple pins at same node + * @param leftOrRight whether Node is to the left or right of node + */ void routeAllMultiPin(NetLayoutDirection leftOrRight); + + /** + * Connect a single node where + * @param netId + * @param leftOrRight + * @param nmpin + */ void routeSingleMultiPin(u32 netId, NetLayoutDirection leftOrRight, const NetLayoutJunctionMultiPin &nmpin); + void findJunctions(); void calculateRect(); - bool conflict(int ihoriz, int iroad, const NetLayoutJunctionRange& testRng) const; - void place(int ihoriz, int iroad, const NetLayoutJunctionRange& range); - bool canJoin(int ihoriz, int iroad, u32 netId, int pos) const; - int* canJoinAny(int ihoriz, u32 netId, int pos) const; + bool conflict(const LaneIndex& ri, const NetLayoutJunctionRange& testRng) const; + void place(const LaneIndex& ri, const NetLayoutJunctionRange& range); + bool canJoin(const LaneIndex& ri, u32 netId, int pos) const; QRect mRect; NetLayoutJunctionEntries mEntries; - QHash mNetsInput; - QHash mNetsOutput; - QHash mOccupied[2]; // 0=horizontal, 1=vertical + QHash mNets; + NetLayoutJunctionOccupiedHash mOccupied; int maxRoad[2]; - mErrorT mError; }; - /** - * @ingroup graph-layouter - */ class NetLayoutJunctionHash : public QHash { public: @@ -218,5 +431,7 @@ namespace hal { ~NetLayoutJunctionHash(); void clearAll(); }; + + uint qHash(const LaneIndex& ri); } diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 3210f16e9d3..22c772d4f9e 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -593,7 +593,7 @@ namespace hal // iend == 0 => horizontal wire: right endpoint junction: left entry NetLayoutPoint pnt = iend ? it.key().endPoint(NetLayoutWire::SourcePoint) : it.key().endPoint(NetLayoutWire::DestinationPoint); int idirBase = it.key().isHorizontal() ? NetLayoutDirection::Left : NetLayoutDirection::Up; - mJunctionEntries[pnt].setEntries(idirBase + iend, it.value()); + mJunctionEntries[pnt].mEntries[idirBase + iend] = it.value(); } } @@ -602,10 +602,10 @@ namespace hal { NetLayoutPoint inPnt(nbox->x(), nbox->y() * 2); QList inpNets = nbox->item()->inputNets(); - mJunctionEntries[inPnt].setEntries(NetLayoutDirection::Right, nbox->item()->inputNets()); + mJunctionEntries[inPnt].mEntries[NetLayoutDirection::Right] = nbox->item()->inputNets(); mEndpointHash[inPnt].setInputPins(nbox->item()->inputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance()); NetLayoutPoint outPnt(nbox->x() + 1, nbox->y() * 2); - mJunctionEntries[outPnt].setEntries(NetLayoutDirection::Left, nbox->item()->outputNets()); + mJunctionEntries[outPnt].mEntries[NetLayoutDirection::Left] = nbox->item()->outputNets(); mEndpointHash[outPnt].setOutputPins(nbox->item()->outputNets(), nbox->item()->yTopPinDistance(), nbox->item()->yEndpointDistance()); } @@ -614,7 +614,7 @@ namespace hal QList netIds; netIds.append(itGlInp.key()); NetLayoutPoint pnt(mNodeBoundingBox.left(), 2 * itGlInp.value()); - mJunctionEntries[pnt].setEntries(NetLayoutDirection::Left, netIds); + mJunctionEntries[pnt].mEntries[NetLayoutDirection::Left] = netIds; if (!mEndpointHash.contains(pnt)) mEndpointHash[pnt].setOutputPins(netIds, 0, 0); } @@ -624,18 +624,20 @@ namespace hal QList netIds; netIds.append(itGlOut.key()); NetLayoutPoint pnt(mNodeBoundingBox.right() + 1, 2 * itGlOut.value()); - mJunctionEntries[pnt].setEntries(NetLayoutDirection::Right, netIds); + mJunctionEntries[pnt].mEntries[NetLayoutDirection::Right] = netIds; if (!mEndpointHash.contains(pnt)) mEndpointHash[pnt].setInputPins(netIds, 0, 0); } for (auto it = mJunctionEntries.constBegin(); it != mJunctionEntries.constEnd(); ++it) { - it.value().dumpFile(it.key()); + // it.value().dumpFile(it.key()); qDebug() << "Junction at" << it.key().x() << it.key().y(); NetLayoutJunction* nlj = new NetLayoutJunction(it.value()); + /* if (nlj->lastError() != NetLayoutJunction::Ok) qDebug() << "Junction route error" << nlj->lastError() << it.key(); + */ mJunctionHash.insert(it.key(), nlj); } } @@ -1540,12 +1542,13 @@ namespace hal for (const NetLayoutJunctionWire& jw : jt.value()->netById(id).mWires) { - if (jw.mHorizontal == 0) + int li = jw.mIndex.laneIndex(); + if (jw.mIndex.isHorizontal()) { Q_ASSERT(epcIt != mEndpointHash.constEnd() || !isEndpoint); - float x0 = mCoordX.value(x).lanePosition(jw.mFirst); - float x1 = mCoordX.value(x).lanePosition(jw.mLast); - float yy = isEndpoint ? epcIt.value().lanePosition(jw.mRoad, true) : mCoordY.value(y).lanePosition(jw.mRoad); + float x0 = mCoordX.value(x).lanePosition(jw.mRange.first()); + float x1 = mCoordX.value(x).lanePosition(jw.mRange.last()); + float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mCoordY.value(y).lanePosition(li); lines.appendHLine(x0, x1, yy); } else @@ -1553,13 +1556,13 @@ namespace hal float y0, y1; if (!isEndpoint) { - y0 = mCoordY.value(y).lanePosition(jw.mFirst); - y1 = mCoordY.value(y).lanePosition(jw.mLast); + y0 = mCoordY.value(y).lanePosition(jw.mRange.first()); + y1 = mCoordY.value(y).lanePosition(jw.mRange.last()); } else if (epcIt != mEndpointHash.constEnd()) { - y0 = epcIt.value().lanePosition(jw.mFirst, true); - y1 = epcIt.value().lanePosition(jw.mLast, true); + y0 = epcIt.value().lanePosition(jw.mRange.first(), true); + y1 = epcIt.value().lanePosition(jw.mRange.last(), true); } else { @@ -1568,7 +1571,7 @@ namespace hal if (y1 <= y0) y1 = y0 + 1; } - float xx = mCoordX.value(x).lanePosition(jw.mRoad); + float xx = mCoordX.value(x).lanePosition(li); lines.appendVLine(xx, y0, y1); } } diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index fbeabe38e92..e0b2f484541 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -1,45 +1,64 @@ +#include "gui/graph_widget/layouters/net_layout_junction.h" +#ifdef JUNCTION_DEBUG +#include #include #include -#include +#endif #include #include #include -#include #include #include #include #include -#include "gui/graph_widget/layouters/net_layout_junction.h" + +#ifdef JUNCTION_DEBUG +QGraphicsEllipseItem* getEllipse(QPoint p, u32 netId) +{ + float dd = DELTA / 2.; + float x0 = FIRST + p.x() * DELTA - dd/2; + float y0 = FIRST + p.y() * DELTA - dd/2; + QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(x0,y0,dd,dd); + retval->setBrush(colorFromId(netId)); + return retval; +} +#endif QColor colorFromId(u32 netId) { int hue = (netId-1) * 25; + if (hue > 255) + { + int gray = (hue - 256) % 160 + 95; + return QColor::fromRgb(gray+1,gray,gray); + } return QColor::fromHsv(hue,255,255); } namespace hal { NetLayoutJunction::NetLayoutJunction(const NetLayoutJunctionEntries& entries) - : mEntries(entries), mError(Ok) + : mEntries(entries) { memset(maxRoad,0,sizeof(maxRoad)); for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) { int iHoriz = dir.iHorizontal(); - int n = mEntries.size(dir); + int n = mEntries.mEntries[dir.index()].size(); if (n>maxRoad[iHoriz]) maxRoad[iHoriz] = n; for (int i=0; i hNets, vNets; + for (const NetLayoutJunctionWire& nljw : it->mWires ) + if (nljw.mIndex.hvIndex() == LaneIndex::Horizontal) + hNets.append(nljw); + else + vNets.append(nljw); + + for (const NetLayoutJunctionWire& hn : hNets) + for (const NetLayoutJunctionWire& vn : vNets) + if ((hn.mRange.innerPos(vn.mIndex.laneIndex()) && vn.mRange.contains(hn.mIndex.laneIndex())) || + (hn.mRange.contains(vn.mIndex.laneIndex()) && vn.mRange.innerPos(hn.mIndex.laneIndex()))) + it->mJunctions.append(QPoint(vn.mIndex.laneIndex(),hn.mIndex.laneIndex())); + } + } void NetLayoutJunction::routeAllMultiPin(NetLayoutDirection leftOrRight) { @@ -59,28 +98,33 @@ namespace hal { for (int iroad=0; iroady1) y1 = y+1; - } - } - if (!mOccupied[1].isEmpty()) - { - for (int x : mOccupied[1].keys()) - { + break; + case LaneIndex::Vertical: + x = ri.laneIndex(); if (xx1) x1 = x+1; + break; } } + + // empty junction has size 1 if (y1<=0) y1 = 1; if (x1<=0) x1 = 1; mRect = QRect(x0,y0,x1-x0,y1-y0); - for (int ihoriz = 0; ihoriz<2; ihoriz++) - for (auto itOcc = mOccupied[ihoriz].constBegin(); itOcc!=mOccupied[ihoriz].constEnd(); ++itOcc) + //TODO: truncate nets to rect might be range function + for (auto itNet = mNets.begin(); itNet != mNets.end(); ++itNet) + { + auto itWire = itNet->mWires.begin(); + while (itWire != itNet->mWires.end()) { - int iroad = itOcc.key(); - for (const NetLayoutJunctionRange& rng : itOcc.value()) - { - NetLayoutJunctionWire w = rng.toWire(ihoriz,iroad); - if (w.mFirst == NetLayoutJunctionRange::sMinInf) - { - if (w.mHorizontal==0) - w.mFirst = x0-1; - else - w.mFirst = y0-1; - } - if (w.mLast == NetLayoutJunctionRange::sMaxInf) - { - if (w.mHorizontal==0) - w.mLast = x1; - else - w.mLast = y1; - } - mNetsOutput[rng.netId()].addWire(w); - } + if (itWire->mRange.first() == NetLayoutJunctionRange::MinInf) + { + if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal) + itWire->mRange.setFirst(x0); + else + itWire->mRange.setFirst(y0); + } + if (itWire->mRange.last() == NetLayoutJunctionRange::MaxInf) + { + if (itWire->mIndex.hvIndex()==LaneIndex::Horizontal) + itWire->mRange.setLast(x1-1); + else + itWire->mRange.setLast(y1-1); + } + if (itWire->mRange.length() <=0) + itWire = itNet->mWires.erase(itWire); + else + ++itWire; } + } } - void NetLayoutJunction::fourWayJunctions(QHash::iterator& netIt) +#ifdef JUNCTION_DEBUG + void NetLayoutJunction::toScene(QGraphicsScene* scene) const { - QList wires[2]; - for (const NetLayoutJunctionWire& w : netIt.value().mWires) - wires[w.mHorizontal].append(w); + scene->setBackgroundBrush(QBrush(QColor::fromRgb(80,80,80))); + QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA, + FIRST + (mRect.y() - 0.5) * DELTA, + mRect.width() * DELTA, + mRect.height() * DELTA); + + float xscene0 = bg.left() < 100 ? bg.left() - 100 : 0; + float xscene1 = bg.right() > 900 ? bg.right() + 100 : 1000; + float yscene0 = bg.top() < 100 ? bg.top() - 100 : 0; + float yscene1 = bg.bottom() > 900 ? bg.bottom() + 100 : 1000; + scene->setSceneRect(xscene0,yscene0,xscene1,yscene1); - for (const NetLayoutJunctionWire& hw : wires[0]) + QGraphicsRectItem* item = new QGraphicsRectItem(bg); + item->setBrush(QBrush(Qt::black)); + scene->addItem(item); + + for (auto netIt = mNets.constBegin(); netIt != mNets.constEnd(); ++netIt) { - if (!hw.isEntry()) continue; - for (const NetLayoutJunctionWire& vw: wires[1]) + for(QPoint jp : netIt.value().junctionPoints()) { - if (!vw.isEntry()) continue; - NetLayoutJunctionWireIntersection pnt = hw.intersection(vw); - if (pnt.isValid()) - { - netIt->setJunctionPoint(pnt); - return; - } + QGraphicsEllipseItem* item = getEllipse(jp,netIt.key()); + scene->addItem(item); } } + + + for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) + { + int nEntries = mEntries.mEntries[dir.index()].size(); + for (int ientry=0; ientrysetPen(QPen(QBrush(col),3.)); + scene->addItem(item); + } + } } - void NetLayoutJunction::dump() const + void NetLayoutJunction::toSceneStep(QGraphicsScene* scene, int istep) { - qDebug() << "-net-"; - for (u32 id : mNetsInput.keys() ) + if (istep >= mOccupied.mHistory.size()) return; + + QRectF bg(FIRST + (mRect.x() - 0.5) * DELTA, + FIRST + (mRect.y() - 0.5) * DELTA, + mRect.width() * DELTA, + mRect.height() * DELTA); + + const QPair& pw = mOccupied.mHistory.at(istep); + QColor col = colorFromId(pw.first); + + float x0, x1, y0, y1; + + const LaneIndex& ri = pw.second.mIndex; + const NetLayoutJunctionRange& rng = pw.second.mRange; + if (ri.hvIndex()==LaneIndex::Horizontal) { - qDebug() << id << mNetsInput.value(id).toString(); + y0 = y1 = FIRST + ri.laneIndex() * DELTA; + x0 = FIRST + rng.first() * DELTA; + if (x0 < bg.left()) x0 = bg.left(); + x1 = FIRST + rng.last() * DELTA; + if (x1 > bg.right()) x1 = bg.right(); + qDebug() << "---" << ri.laneIndex() << rng.first() << rng.last(); } - qDebug() << mEntries.dump(); + else + { + x0 = x1 = FIRST + ri.laneIndex() * DELTA; + y0 = FIRST + rng.first() * DELTA; + if (y0 < bg.top()) y0 = bg.top(); + y1 = FIRST + rng.last() * DELTA; + if (y1 > bg.bottom()) y1 = bg.bottom(); + qDebug() << " | " << ri.laneIndex() << rng.first() << rng.last(); + } + QGraphicsLineItem* item = new QGraphicsLineItem(x0,y0,x1,y1); + item->setPen(QPen(QBrush(col),3.)); + scene->addItem(item); } +#endif void NetLayoutJunction::routeT() { - for (auto itNet=mNetsInput.begin(); itNet!=mNetsInput.end();++itNet) + for (auto itNet=mNets.begin(); itNet!=mNets.end();++itNet) { - if (itNet.value().numberEntries() == 3) + if (itNet.value().numberEntries() >= 3) { - int i0, i1, ilink, ihoriz; + int i0, i1, ilink; + LaneIndex::HVIndex itravers, imaindir; u32 reducedPattern; switch (itNet.value().pattern()) { @@ -246,71 +370,63 @@ namespace hal { i0 = 0; i1 = 1; ilink = 2; - ihoriz = 1; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 5 : 6; + itravers = LaneIndex::Vertical; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 6; break; case 11: // L D R i0 = 0; i1 = 1; ilink = 3; - ihoriz = 1; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 10 : 9; + itravers = LaneIndex::Vertical; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 9; break; case 13: // U L D i0 = 2; i1 = 3; ilink = 0; - ihoriz = 0; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 5 : 9; + itravers = LaneIndex::Horizontal; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 5 : 9; break; case 14: // U R D i0 = 2; i1 = 3; ilink = 1; - ihoriz = 0; - reducedPattern = itNet.value().roadNumber(i1) > itNet.value().roadNumber(i0) ? 10 : 6; + itravers = LaneIndex::Horizontal; + reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 6; break; default: return; } - int road0 = itNet.value().roadNumber(i0); - int road1 = itNet.value().roadNumber(i1); - int roadLink = itNet.value().roadNumber(ilink); - int jhoriz = 1-ihoriz; - int roadj; - if (canJoin(jhoriz,road0,itNet.key(),roadLink)) - roadj = road0; - else if (canJoin(jhoriz,road1,itNet.key(),roadLink)) - roadj = road1; - else + int roadLink = itNet.value().laneIndex(ilink); + imaindir = (itravers == LaneIndex::Horizontal ? LaneIndex::Vertical : LaneIndex::Horizontal); + QList mainWires = itNet.value().wireAtPos(roadLink,imaindir); + if (mainWires.isEmpty()) { - int* roadPtr = canJoinAny(jhoriz,itNet.key(),roadLink); - if (roadPtr) - { - roadj = *roadPtr; - delete roadPtr; - } - else + qDebug() << "T-join not found"; + return; + } + + int minlen = 0; + NetLayoutJunctionRange rngT = NetLayoutJunctionRange::entryRange(ilink,0,itNet.key()); + + for (const NetLayoutJunctionWire& nljw : mainWires) + { + NetLayoutJunctionRange rng = + NetLayoutJunctionRange::entryRange(ilink,nljw.mIndex.laneIndex(),itNet.key()); + if (!minlen || rng.length() < rngT.length()) { - qDebug() << "T-join not found"; - return; + rngT = rng; + minlen = rng.length(); } } - NetLayoutJunctionRange rngT = - NetLayoutJunctionRange::entryRange(ilink,roadj,itNet.key()); - if (conflict(ihoriz,roadLink,rngT)) + if (conflict(LaneIndex(itravers,roadLink),rngT)) itNet->setPattern(reducedPattern); else { - place(ihoriz,roadLink,rngT); + place(LaneIndex(itravers,roadLink),rngT); itNet->setPlaced(); - itNet->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - ihoriz?roadLink:roadj, - ihoriz?roadj:roadLink)); } } } @@ -323,8 +439,7 @@ namespace hal { for (auto it = mEntries.mEntries[dirHoriz.index()].begin(); it != mEntries.mEntries[dirHoriz.index()].end(); ++it) { - if (*it == 0) continue; - NetLayoutJunctionNet net = mNetsInput.value(*it); + NetLayoutJunctionNet net = mNets.value(*it); if (net.hasPattern(searchPattern) && !net.isPlaced()) routeSingleCorner(*it,dirHoriz,dirVertic); } @@ -332,8 +447,7 @@ namespace hal { for (auto it = mEntries.mEntries[dirHoriz.index()].rbegin(); it != mEntries.mEntries[dirHoriz.index()].rend(); ++it) { - if (*it == 0) continue; - NetLayoutJunctionNet net = mNetsInput.value(*it); + NetLayoutJunctionNet net = mNets.value(*it); if (net.hasPattern(searchPattern) && !net.isPlaced()) routeSingleCorner(*it,dirHoriz,dirVertic); } @@ -341,135 +455,120 @@ namespace hal { void NetLayoutJunction::routeAllStraight(NetLayoutDirection dirFrom, NetLayoutDirection dirTo) { - QHash straightConnected; + QMap straightConnected; u32 searchPattern = dirFrom.toPattern() | dirTo.toPattern(); - QSet connectedInput, connectedOutput; - QList detourIds; - for (u32 netId : mEntries.mEntries[dirFrom.index()]) { - if (netId==0) continue; - auto itNet = mNetsInput.find(netId); - Q_ASSERT(itNet != mNetsInput.end()); + auto itNet = mNets.find(netId); + Q_ASSERT(itNet != mNets.end()); +// qDebug () << "straight" << searchPattern << netId << itNet.value().hasPattern(searchPattern) << itNet.value().pattern(); if (itNet.value().hasPattern(searchPattern)) { - int iroadIn = itNet.value().roadNumber(dirFrom); - int iroadOut = itNet.value().roadNumber(dirTo); - if (connectedInput.contains(iroadOut) && connectedOutput.contains(iroadIn)) - { - // swap detected, cannot route directly - detourIds.append(netId); - continue; - } - routeSingleStraight(netId, (searchPattern==3?0:1), iroadIn, iroadOut); - straightConnected[iroadIn] = iroadOut; + int iroadIn = itNet.value().laneIndex(dirFrom); + int iroadOut = itNet.value().laneIndex(dirTo); + if (straightConnected.contains(iroadIn) && straightConnected.contains(iroadOut)) + routeSingleSwap(netId, (searchPattern==3?0:1), iroadIn, iroadOut); + else + routeSingleStraight(netId, (searchPattern==3?0:1), iroadIn, iroadOut); + ++straightConnected[iroadIn]; + ++straightConnected[iroadOut]; if (itNet.value().numberEntries() % 2 ==0) itNet->setPlaced(); - connectedInput.insert(iroadIn); - connectedOutput.insert(iroadOut); } } - - for (u32 netId : detourIds) - { - auto itNet = mNetsInput.find(netId); - Q_ASSERT(itNet != mNetsInput.end()); - int iroadIn = itNet.value().roadNumber(dirFrom); - int iroadOut = itNet.value().roadNumber(dirTo); - routeSingleDetour(netId, (searchPattern==3?0:1), iroadIn, iroadOut); - straightConnected[iroadIn] = iroadOut; - if (itNet.value().numberEntries() % 2 ==0) - itNet->setPlaced(); - } } - bool NetLayoutJunction::conflict(int ihoriz, int iroad, const NetLayoutJunctionRange& testRng) const + bool NetLayoutJunction::conflict(const LaneIndex&ri, const NetLayoutJunctionRange& testRng) const { - auto itConflict = mOccupied[ihoriz].find(iroad); - if (itConflict == mOccupied[ihoriz].end()) return false; + auto itConflict = mOccupied.find(ri); + if (itConflict == mOccupied.end()) return false; return itConflict.value().conflict(testRng); } - bool NetLayoutJunction::canJoin(int ihoriz, int iroad, u32 netId, int pos) const + bool NetLayoutJunction::canJoin(const LaneIndex &ri, u32 netId, int pos) const { - auto itJoin = mOccupied[ihoriz].find(iroad); - if (itJoin == mOccupied[ihoriz].end()) return false; + auto itJoin = mOccupied.find(ri); + if (itJoin == mOccupied.end()) return false; return itJoin.value().canJoin(netId,pos); } - int* NetLayoutJunction::canJoinAny(int ihoriz, u32 netId, int pos) const + void NetLayoutJunction::place(const LaneIndex &ri, const NetLayoutJunctionRange &range) { - for (auto itTry = mOccupied[ihoriz].constBegin(); itTry != mOccupied[ihoriz].constEnd(); ++itTry) + NetLayoutJunctionRange rng = range; + NetLayoutJunctionOccupiedHash::AddType added = mOccupied.addOrMerge(ri,rng); // might modify + + auto netIt = mNets.find(range.netId()); + Q_ASSERT(netIt!=mNets.end()); + NetLayoutJunctionWire nljw(rng,ri); + switch (added ) { - if (itTry.value().canJoin(netId,pos)) - { - int* retval = new int; - *retval = itTry.key(); - return retval; - } + case NetLayoutJunctionOccupiedHash::Added: + netIt->addWire(nljw); + break; + case NetLayoutJunctionOccupiedHash::Merged: + netIt->replaceWire(range,nljw); + break; + default: + break; } - return nullptr; - } - - void NetLayoutJunction::place(int ihoriz, int iroad, const NetLayoutJunctionRange &range) - { - mOccupied[ihoriz][iroad].append(range); - auto netIt = mNetsInput.find(range.netId()); - Q_ASSERT(netIt!=mNetsInput.end()); - netIt->addWire(NetLayoutJunctionWire(ihoriz,iroad, - range.endPosition(0), - range.endPosition(1))); } - void NetLayoutJunction::routeSingleDetour(u32 netId, int iMain, int iroadIn, int iroadOut) + void NetLayoutJunction::routeSingleSwap(u32 netId, int iMain, int iroadIn, int iroadOut) { int iJump = 1-iMain; int iroadJump0 = -1; int iroadJump1 = maxRoad[iJump]; int iroadDetour = maxRoad[iMain]; - int maxSearch = std::max(2*(maxRoad[0]+maxRoad[1]),12)*3; - int count = 0; - while (count++ < maxSearch) // break when route found + + LaneIndex riDetour(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadDetour); + LaneIndex riJump0(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump0); + LaneIndex riJump1(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump1); + LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn); + LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut); + + for (;;) // break when route found { - NetLayoutJunctionRange rngIn(netId, NetLayoutJunctionRange::sMinInf, iroadJump0); - NetLayoutJunctionRange rngJ0(netId, iroadIn, iroadDetour); - NetLayoutJunctionRange rngDt(netId, iroadJump0, iroadJump1); - NetLayoutJunctionRange rngJ1(netId, iroadOut, iroadDetour); - NetLayoutJunctionRange rngOut(netId, iroadJump1, NetLayoutJunctionRange::sMaxInf); - if (conflict(iMain,iroadDetour,rngDt)) + NetLayoutJunctionRange rngIn(netId, NetLayoutJunctionRange::MinInf, riJump0.laneIndex()); + NetLayoutJunctionRange rngJ0(netId, iroadIn, riDetour.laneIndex()); + NetLayoutJunctionRange rngDt(netId, riJump0.laneIndex(), riJump1.laneIndex()); + NetLayoutJunctionRange rngJ1(netId, iroadOut, riDetour.laneIndex()); + NetLayoutJunctionRange rngOut(netId, riJump1.laneIndex(), NetLayoutJunctionRange::MaxInf); + + + if (conflict(riDetour,rngDt)) { - iroadDetour ++; + ++riDetour; continue; } - if (conflict(iJump,iroadJump1,rngJ1) || - conflict(iMain,iroadOut,rngOut)) + if (conflict(riJump1,rngJ1) || + conflict(riMainOut,rngOut)) { - iroadJump1 ++; + ++riJump1; continue; } - if (conflict(iJump,iroadJump0,rngJ0) || - conflict(iMain,iroadIn,rngIn)) + if (conflict(riJump0,rngJ0) || + conflict(riMainIn,rngIn)) { - iroadJump0 --; + --riJump0; continue; } - place(iMain,iroadIn,rngIn); - place(iJump,iroadJump0,rngJ0); - place(iMain,iroadDetour,rngDt); - place(iJump,iroadJump1,rngJ1); - place(iMain,iroadOut,rngOut); + place(riMainIn,rngIn); + place(riJump0,rngJ0); + place(riDetour,rngDt); + place(riJump1,rngJ1); + place(riMainOut,rngOut); break; } } void NetLayoutJunction::routeSingleStraight(u32 netId, int iMain, int iroadIn, int iroadOut) - { + { int iJump = 1-iMain; if (iroadIn == iroadOut) { - NetLayoutJunctionRange rng(netId,NetLayoutJunctionRange::sMinInf, NetLayoutJunctionRange::sMaxInf); - place(iMain,iroadIn,rng); + NetLayoutJunctionRange rng(netId,NetLayoutJunctionRange::MinInf, NetLayoutJunctionRange::MaxInf); + place(LaneIndex(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn),rng); return; } int iroadLo = iroadIn; @@ -483,61 +582,92 @@ namespace hal { iroadJump = maxRoad[iJump]; isearchIncr = 1; } - int maxSearch = std::max(2*(maxRoad[0]+maxRoad[1]),12); for (;;iroadJump+=isearchIncr) { - if (iroadJump <= -maxSearch || - iroadJump >= maxSearch) + if (iroadJump <= NetLayoutJunctionRange::MinInf || + iroadJump >= NetLayoutJunctionRange::MaxInf) { - mError = StraightRouteError; + qDebug() << "cannot route straight" << (iMain ? "vertical" : "horizontal") + << netId << iroadIn << iroadOut; return; } NetLayoutJunctionRange rngIn(netId, - NetLayoutJunctionRange::sMinInf, + NetLayoutJunctionRange::MinInf, iroadJump); NetLayoutJunctionRange rngJump(netId, iroadLo, iroadHi); NetLayoutJunctionRange rngOut(netId, iroadJump, - NetLayoutJunctionRange::sMaxInf); + NetLayoutJunctionRange::MaxInf); + + LaneIndex riJump(iJump?LaneIndex::Vertical:LaneIndex::Horizontal,iroadJump); + LaneIndex riMainIn(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadIn); + LaneIndex riMainOut(iMain?LaneIndex::Vertical:LaneIndex::Horizontal,iroadOut); + if (!conflict(riJump,rngJump) && + !conflict(riMainOut,rngOut) && + !conflict(riMainIn,rngIn)) + { + place(riJump,rngJump); + place(riMainIn,rngIn); + place(riMainOut,rngOut); + break; + } + } + } + + NetLayoutJunctionOccupiedHash::AddType NetLayoutJunctionOccupiedHash::addOrMerge(const LaneIndex& ri, NetLayoutJunctionRange& rng) + { + // operator will create entry if not existing + NetLayoutJunctionOccupied& nljo = this->operator[](ri); - if (!conflict(iJump,iroadJump,rngJump) && - !conflict(iMain,iroadOut,rngOut) && - !conflict(iMain,iroadIn,rngIn)) + AddType retval = Added; + + for (auto it = nljo.begin(); it!= nljo.end(); ++it) + { + if (*it == rng) { - place(iJump,iroadJump,rngJump); - place(iMain,iroadIn,rngIn); - place(iMain,iroadOut,rngOut); + retval = None; + break; + } + if (it->canJoin(rng)) + { + it->expand(rng); + rng = (*it); + retval = Merged; break; } } + + if (retval == Added) + nljo.append(rng); + +#ifdef JUNCTION_DEBUG + mHistory.append(qMakePair(rng.netId(),NetLayoutJunctionWire(rng,ri))); +#endif + return retval; } void NetLayoutJunction::routeSingleCorner(u32 netId, NetLayoutDirection dirHoriz, NetLayoutDirection dirVertic) { - auto netIt = mNetsInput.find(netId); - Q_ASSERT(netIt != mNetsInput.end()); + auto netIt = mNets.find(netId); + Q_ASSERT(netIt != mNets.end()); - int iroadHoriz = netIt.value().roadNumber(dirHoriz); - int iroadVertic = netIt.value().roadNumber(dirVertic); + int iroadHoriz = netIt.value().laneIndex(dirHoriz); + int iroadVertic = netIt.value().laneIndex(dirVertic); + // Try to connect straight lines directly without detour NetLayoutJunctionRange rngH = NetLayoutJunctionRange::entryRange(dirHoriz,iroadVertic,netId); NetLayoutJunctionRange rngV = NetLayoutJunctionRange::entryRange(dirVertic,iroadHoriz,netId); - if (!conflict(0,iroadHoriz,rngH) && !conflict(1,iroadVertic,rngV)) + if (!conflict(LaneIndex::horizontal(iroadHoriz),rngH) && !conflict(LaneIndex::vertical(iroadVertic),rngV)) { - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - iroadVertic, - iroadHoriz), - NetLayoutJunctionWireIntersection::Endpoint); - mOccupied[0][iroadHoriz].append(rngH); - mOccupied[1][iroadVertic].append(rngV); + place(LaneIndex::horizontal(iroadHoriz),rngH); + place(LaneIndex::vertical(iroadVertic),rngV); netIt->setPlaced(); return; } + // OK, we need around corner detour int hcroad = dirVertic.isUp() ? -1 : mEntries.mEntries[dirHoriz.index()].size(); int hstep = dirVertic.isUp() ? -1 : 1; int vcroad = dirHoriz.isLeft() ? -1 : mEntries.mEntries[dirVertic.index()].size(); @@ -553,68 +683,42 @@ namespace hal { NetLayoutJunctionRange rngVe = NetLayoutJunctionRange::entryRange(dirVertic,hcroad,netId); - if (++icount > 12 && icount > 2*(maxRoad[0]+maxRoad[1])) + if (++icount > 42) { - mError = CornerRouteError; + qDebug() << "giving up"; return; } // qDebug() << "try" << netId << iroadHoriz << iroadVertic << hcroad << vcroad; - if (conflict(0,hcroad,rngHc) || conflict(1,iroadVertic,rngVe)) + if (conflict(LaneIndex::horizontal(hcroad),rngHc) || conflict(LaneIndex::vertical(iroadVertic),rngVe)) hcroad += hstep; - else if (conflict(1,vcroad,rngVc) || conflict(0,iroadHoriz,rngHe)) + else if (conflict(LaneIndex::vertical(vcroad),rngVc) || conflict(LaneIndex::horizontal(iroadHoriz),rngHe)) vcroad += vstep; else { - if(netIt->numberEntries()==3) - { - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - vcroad, - iroadHoriz), - NetLayoutJunctionWireIntersection::Verify); - netIt->setJunctionPoint( - NetLayoutJunctionWireIntersection( - true, - iroadVertic, - hcroad), - NetLayoutJunctionWireIntersection::Verify); - } - place(0,hcroad,rngHc); - place(1,vcroad,rngVc); - place(0,iroadHoriz,rngHe); - place(1,iroadVertic,rngVe); + place(LaneIndex::horizontal(hcroad),rngHc); + place(LaneIndex::vertical(vcroad),rngVc); + + place(LaneIndex::horizontal(iroadHoriz),rngHe); + place(LaneIndex::vertical(iroadVertic),rngVe); netIt->setPlaced(); break; } } } - NetLayoutJunctionHash::~NetLayoutJunctionHash() - { - clearAll(); - } - - void NetLayoutJunctionHash::clearAll() - { - for (NetLayoutJunction* nlj : values()) - delete nlj; - clear(); - } - NetLayoutJunctionNet::NetLayoutJunctionNet() : mPattern(0), mEntries(0), mPlaced(false) { for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) - mRoadNumber[dir.index()] = -1; + mLaneIndex[dir.index()] = -1; } - void NetLayoutJunctionNet::addEntry(NetLayoutDirection dir, int roadNo) + void NetLayoutJunctionNet::addEntry(NetLayoutDirection dir, int laneInx) { mPattern |= dir.toPattern(); - mRoadNumber[dir.index()] = roadNo; + mLaneIndex[dir.index()] = laneInx; ++mEntries; } @@ -623,49 +727,24 @@ namespace hal { return (mPattern & searchPattern) == searchPattern; } - void NetLayoutJunctionNet::setJunctionPoint(const NetLayoutJunctionWireIntersection& jp, - NetLayoutJunctionWireIntersection::PlacementType placement) + void NetLayoutJunctionNet::replaceWire(const NetLayoutJunctionRange &rng, const NetLayoutJunctionWire &wire) { - bool found = false; - - switch (placement) - { - case NetLayoutJunctionWireIntersection::Verify: - for (const NetLayoutJunctionWire& wire : mWires) + for (auto it = mWires.begin(); it!= mWires.end(); ++it) + if (rng == *it) { - if (wire.isEntry() && - ((wire.mRoad == jp.x() && wire.mHorizontal == 1) || - (wire.mRoad == jp.y() && wire.mHorizontal == 0)) - ) - { - found = true; - break; - } - } - if (!found) return; - mJunction = jp; - break; - case NetLayoutJunctionWireIntersection::Endpoint: - for (const NetLayoutJunctionWire& wire : mWires) - { - if (wire.isEntry() && wire.mRoad == jp.x() && wire.mHorizontal==1) - { - mJunction = NetLayoutJunctionWireIntersection(true, jp.x(), wire.centralEnd()); - return; - } - if (wire.isEntry() && wire.mRoad == jp.y() && wire.mHorizontal==0) - { - mJunction = NetLayoutJunctionWireIntersection(true, wire.centralEnd(), jp.y()); - return; - } + *it = wire; + return; } - break; - default: - mJunction = jp; - break; - } } + QList NetLayoutJunctionNet::wireAtPos(int pos, LaneIndex::HVIndex hvi) + { + QList retval; + for (auto it = mWires.begin(); it!= mWires.end(); ++it) + if (it->mIndex.hvIndex() == hvi && it->mRange.contains(pos)) + retval.append(*it); + return retval; + } QString NetLayoutJunctionNet::toString() const { @@ -676,45 +755,29 @@ namespace hal { if (mPattern & dir.toPattern()) { if (!retval.isEmpty()) retval += ":"; - retval += QString("%1%2").arg(dirChar[dir.index()]).arg(mRoadNumber[dir.index()]); + retval += QString("%1%2").arg(dirChar[dir.index()]).arg(mLaneIndex[dir.index()]); } } return retval; } - QGraphicsEllipseItem* NetLayoutJunctionWireIntersection::graphicsFactory(u32 netId) const - { - float dd = NetLayoutJunctionRange::sSceneDelta / 2.; - float x0 = NetLayoutJunctionRange::sSceneFirst + x() * NetLayoutJunctionRange::sSceneDelta - dd/2; - float y0 = NetLayoutJunctionRange::sSceneFirst + y() * NetLayoutJunctionRange::sSceneDelta - dd/2; - QGraphicsEllipseItem* retval = new QGraphicsEllipseItem(x0,y0,dd,dd); - retval->setBrush(colorFromId(netId)); - return retval; - } - - NetLayoutJunctionRange::NetLayoutJunctionRange(u32 netId_, int first, int last) : mNetId(netId_), mFirst(first), mLast(last) { - if (last mLast) mLast = other.mLast; } - void NetLayoutJunctionOccupied::add(const NetLayoutJunctionRange& rng) - { - for (auto it = begin(); it!= end(); ++it) - if (it->canJoin(rng)) - { - it->expand(rng); - return; - } - append(rng); - } - bool NetLayoutJunctionOccupied::canJoin(u32 netId, int pos) const { for (const NetLayoutJunctionRange& r : *this) - if (r.canJoin(netId, pos)) return true; + { + if (r.netId() != netId) continue; + if (r.contains(pos)) return true; + } return false; } @@ -798,44 +841,13 @@ namespace hal { return false; } - int NetLayoutJunctionWire::centralEnd() const - { - if (mFirst==NetLayoutJunctionRange::sMinInf) - return mLast; - return mFirst; - } - - void NetLayoutJunctionNet::addWire(const NetLayoutJunctionWire& wire) - { - for (const NetLayoutJunctionWire& w : mWires) - if (w.mHorizontal == wire.mHorizontal && - w.mRoad == wire.mRoad && - (w.mLast < wire.mFirst || w.mFirst > wire.mLast )) - { - qDebug() << "junction" << w.mHorizontal << w.mRoad << w.mFirst << w.mLast << wire.mFirst << wire.mLast; - } - mWires.append(wire); - } - bool NetLayoutJunctionWire::isEntry() const { - return mFirst == NetLayoutJunctionRange::sMinInf - || mLast == NetLayoutJunctionRange::sMaxInf; + return mRange.isEntry(0) || mRange.isEntry(1); } - NetLayoutJunctionWireIntersection NetLayoutJunctionWire::intersection(const NetLayoutJunctionWire &other) const - { - if (other.mFirst <= mRoad && mRoad <= other.mLast && - mFirst <= other.mRoad && other.mRoad <= mLast) - { - if (mHorizontal) - return NetLayoutJunctionWireIntersection(true,mRoad,other.mRoad); - return NetLayoutJunctionWireIntersection(true,other.mRoad,mRoad); - } - return NetLayoutJunctionWireIntersection(); - } - QString NetLayoutJunctionEntries::dump() const + QString NetLayoutJunctionEntries::toString() const { QString retval; for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) @@ -848,38 +860,17 @@ namespace hal { return retval; } - void NetLayoutJunctionEntries::dumpFile(const NetLayoutPoint& pnt) const + NetLayoutJunctionHash::~NetLayoutJunctionHash() { - QString filename("/tmp/junction"); - QDir().mkpath(filename); - QString columnStr; - int ix = pnt.x(); - if (ix < 0) - { - columnStr += "_"; - ix = -ix; - } - if (ix >= 26) columnStr += QString("%1").arg((char)('A'+ ix/26 - 1)); - columnStr += QString("%1").arg((char)('A'+ ix%26)); - int iy = pnt.y(); - if (iy < 0) - { - columnStr += "_"; - iy = -iy; - } - filename += "/" + columnStr + QString("%1.jjj").arg(iy); - QFile ff(filename); - if (!ff.open(QIODevice::WriteOnly)) return; - for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) - { - for (u32 id : mEntries[dir.index()]) - ff.write(" " + QByteArray::number(id)); - ff.write("\n"); - } + clearAll(); } - void NetLayoutJunctionEntries::setEntries(NetLayoutDirection dir, const QList& entries_) + void NetLayoutJunctionHash::clearAll() { - mEntries[dir.index()] = entries_; + for (NetLayoutJunction* nlj : values()) + delete nlj; + clear(); } + + uint qHash(const LaneIndex& ri) { return ri.mIndex; } } // namespace hal From 4ba80683a4ec73e17746ff099330eb2f98b56302 Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 23 Oct 2023 19:46:26 +0200 Subject: [PATCH 05/22] Threaded drawNet function --- .../graph_widget/layouters/graph_layouter.h | 25 ++ .../graph_widget/layouters/graph_layouter.cpp | 304 ++++++++++++------ 2 files changed, 233 insertions(+), 96 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index ffca73fa902..9cc7656c7a9 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -43,6 +43,7 @@ #include #include #include +#include namespace hal { @@ -59,6 +60,7 @@ namespace hal class NetLayoutJunctionEntries; class CommentSpeechBubble; class CommentEntry; + class DrawNetThread; /** * @ingroup graph-layouter @@ -75,6 +77,8 @@ namespace hal { Q_OBJECT + friend class DrawNetThread; + class SceneCoordinate { int minLane; @@ -340,6 +344,9 @@ namespace hal QMap mPositionToNodeMap; QMap mNodeToPositionRollback; + private Q_SLOTS: + void handleDrawThreadFinished(); + private: void clearLayoutData(); void clearComments(); @@ -479,5 +486,23 @@ namespace hal bool mOptimizeNetLayout; QList mCommentBubbles; + QSet mNetsToDraw; + QSet::const_iterator mNetIterator; + QList mDrawThreads; + QHash> mLaneMap; + }; + + class DrawNetThread : public QThread + { + Q_OBJECT + u32 mId; + GraphLayouter* mLayouter; + void drawJunction(); + void drawEndpoint(); + public: + StandardGraphicsNet::Lines mLines; + DrawNetThread(u32 id, GraphLayouter* parent) : QThread(parent), mId(id), mLayouter(parent) {;} + u32 id() const { return mId; } + void run() override; }; } // namespace hal diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 22c772d4f9e..a017d5fd496 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -632,7 +632,7 @@ namespace hal for (auto it = mJunctionEntries.constBegin(); it != mJunctionEntries.constEnd(); ++it) { // it.value().dumpFile(it.key()); - qDebug() << "Junction at" << it.key().x() << it.key().y(); + // qDebug() << "Junction at" << it.key().x() << it.key().y(); NetLayoutJunction* nlj = new NetLayoutJunction(it.value()); /* if (nlj->lastError() != NetLayoutJunction::Ok) @@ -1310,30 +1310,23 @@ namespace hal void GraphLayouter::alternateDrawNets() { // lane for given wire and net id - QHash> laneMap; for (auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it) { int ilane = 0; for (u32 id : it.value()) - laneMap[id].insert(it.key(), ilane++); + mLaneMap[id].insert(it.key(), ilane++); } int netCount = mParentContext->nets().size(); int percentCount = netCount / 93; int doneCount = 0; - for (const u32 id : mParentContext->nets()) + mNetsToDraw = mParentContext->nets(); + mNetIterator = mNetsToDraw.constBegin(); + while (mNetIterator != mNetsToDraw.constEnd()) { - ++doneCount; - if (percentCount) - { - if (doneCount % percentCount == 0) - mParentContext->layoutProgress(7 + doneCount / percentCount); - } - else - mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); - + u32 id = *(mNetIterator++); Net* n = gNetlist->get_net_by_id(id); if (!n) continue; @@ -1344,10 +1337,12 @@ namespace hal switch (epl.netType()) { case EndpointList::NoEndpoint: + ++doneCount; break; case EndpointList::SingleSource: case EndpointList::SingleDestination: case EndpointList::ConstantLevel: + ++doneCount; drawNetsIsolated(id, n, epl); break; ; @@ -1359,98 +1354,73 @@ namespace hal if (!regularNet) continue; - StandardGraphicsNet::Lines lines; - - const QHash& wMap = laneMap.value(id); - for (auto it = wMap.constBegin(); it != wMap.constEnd(); ++it) + if (mDrawThreads.size() < QThread::idealThreadCount()) { - NetLayoutPoint wFromPoint = it.key().endPoint(NetLayoutWire::SourcePoint); - NetLayoutPoint wToPoint = it.key().endPoint(NetLayoutWire::DestinationPoint); - NetLayoutJunction* j0 = mJunctionHash.value(wFromPoint); - NetLayoutJunction* j1 = mJunctionHash.value(wToPoint); - int ilane = it.value(); - int ix0 = wFromPoint.x(); - int iy0 = wFromPoint.y(); - int ix1 = wToPoint.x(); - int iy1 = wToPoint.y(); - - if (it.key().isHorizontal()) + ++doneCount; + if (percentCount) { - float x0 = j0 ? mCoordX[ix0].lanePosition(j0->rect().right()) : mCoordX[ix0].junctionExit(); - float x1 = j1 ? mCoordX[ix1].lanePosition(j1->rect().left()) : mCoordX[ix1].junctionEntry(); - float yy = mCoordY[iy0].lanePosition(ilane); - lines.appendHLine(x0, x1, yy); + if (doneCount % percentCount == 0) + mParentContext->layoutProgress(7 + doneCount / percentCount); } else - { - float y0, y1; - float xx = mCoordX[ix0].lanePosition(ilane); - if (wToPoint.isEndpoint()) - { - // netjunction -> endpoint - auto itEpc = mEndpointHash.find(wToPoint); - y0 = j0 ? mCoordY[iy0].lanePosition(j0->rect().bottom()) : mCoordY[iy0].junctionExit(); - y1 = itEpc != mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1->rect().top(), true) : mCoordY[iy1].junctionEntry(); - // if (itEpc==mEndpointHash.constEnd()) - // qDebug() << "xxx to endp" << wToPoint.x() << wToPoint.y() << y0 << y1; - } - else - { - // endpoint -> netjunction - auto itEpc = mEndpointHash.find(wFromPoint); - y0 = itEpc != mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0->rect().bottom(), true) : mCoordY[iy0].junctionExit(); - y1 = j1 ? mCoordY[iy1].lanePosition(j1->rect().top()) : mCoordY[iy1].junctionEntry(); - // if (itEpc==mEndpointHash.constEnd()) - // qDebug() << "xxx fr endp" << wFromPoint.x() << wFromPoint.y() << y0 << y1; - } - if (y1 > y0) - lines.appendVLine(xx, y0, y1); - } + mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); + + DrawNetThread* dnt = new DrawNetThread(id,this); + connect(dnt,&QThread::finished,this,&GraphLayouter::handleDrawThreadFinished); + mDrawThreads.append(dnt); + dnt->start(); } - drawNetsJunction(lines, id); - drawNetsEndpoint(lines, id); + qApp->processEvents(); + } - lines.mergeLines(mScene); + } - GraphicsNet* graphicsNet = nullptr; - switch (epl.netType()) - { - case EndpointList::HasGlobalEndpoint: - if (epl.hasInputArrow()) - { - StandardArrowNet* san = new StandardArrowNet(n, lines); - graphicsNet = san; - int yGridPos = mGlobalInputHash.value(id, -1); - Q_ASSERT(yGridPos >= 0); - const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); - san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(-1), epc.lanePosition(0, true))); - } - if (epl.hasOutputArrow()) - { - if (graphicsNet) mScene->addGraphItem(graphicsNet); - StandardArrowNet* san = new StandardArrowNet(n, lines); - graphicsNet = san; - int yGridPos = mGlobalOutputHash.value(id, -1); - Q_ASSERT(yGridPos >= 0); - QPoint pnt(mNodeBoundingBox.right() + 1, yGridPos * 2); - const EndpointCoordinate& epc = mEndpointHash.value(pnt); - const NetLayoutJunction* nlj = mJunctionHash.value(pnt); - Q_ASSERT(nlj); - san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right() + 1), epc.lanePosition(0, true))); - } - break; - case EndpointList::SourceAndDestination: - if (lines.nLines() > 0) - graphicsNet = new StandardGraphicsNet(n, lines); - break; - default: - Q_ASSERT(0 > 1); // should never occur - break; - } + void GraphLayouter::handleDrawThreadFinished() + { + DrawNetThread* dnt = static_cast(sender()); + Net* n = gNetlist->get_net_by_id(dnt->id()); + const EndpointList& epl = mWireEndpoint.value(dnt->id()); - if (graphicsNet) - mScene->addGraphItem(graphicsNet); + GraphicsNet* graphicsNet = nullptr; + switch (epl.netType()) + { + case EndpointList::HasGlobalEndpoint: + if (epl.hasInputArrow()) + { + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + graphicsNet = san; + int yGridPos = mGlobalInputHash.value(dnt->id(), -1); + Q_ASSERT(yGridPos >= 0); + const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); + san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(-1), epc.lanePosition(0, true))); + } + if (epl.hasOutputArrow()) + { + if (graphicsNet) mScene->addGraphItem(graphicsNet); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + graphicsNet = san; + int yGridPos = mGlobalOutputHash.value(dnt->id(), -1); + Q_ASSERT(yGridPos >= 0); + QPoint pnt(mNodeBoundingBox.right() + 1, yGridPos * 2); + const EndpointCoordinate& epc = mEndpointHash.value(pnt); + const NetLayoutJunction* nlj = mJunctionHash.value(pnt); + Q_ASSERT(nlj); + san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right() + 1), epc.lanePosition(0, true))); + } + break; + case EndpointList::SourceAndDestination: + if (dnt->mLines.nLines() > 0) + graphicsNet = new StandardGraphicsNet(n, dnt->mLines); + break; + default: + Q_ASSERT(0 > 1); // should never occur + break; } + + if (graphicsNet) + mScene->addGraphItem(graphicsNet); + + mDrawThreads.removeAll(dnt); } void GraphLayouter::drawNetsIsolated(u32 id, Net* n, const EndpointList& epl) @@ -2890,4 +2860,146 @@ namespace hal { mOptimizeNetLayout = enabled; } + + void DrawNetThread::run() + { + Net* n = gNetlist->get_net_by_id(mId); + if (!n) + return; + + const QHash& wMap = mLayouter->mLaneMap.value(mId); + for (auto it = wMap.constBegin(); it != wMap.constEnd(); ++it) + { + NetLayoutPoint wFromPoint = it.key().endPoint(NetLayoutWire::SourcePoint); + NetLayoutPoint wToPoint = it.key().endPoint(NetLayoutWire::DestinationPoint); + NetLayoutJunction* j0 = mLayouter->mJunctionHash.value(wFromPoint); + NetLayoutJunction* j1 = mLayouter->mJunctionHash.value(wToPoint); + int ilane = it.value(); + int ix0 = wFromPoint.x(); + int iy0 = wFromPoint.y(); + int ix1 = wToPoint.x(); + int iy1 = wToPoint.y(); + + if (it.key().isHorizontal()) + { + float x0 = j0 ? mLayouter->mCoordX[ix0].lanePosition(j0->rect().right()) : mLayouter->mCoordX[ix0].junctionExit(); + float x1 = j1 ? mLayouter->mCoordX[ix1].lanePosition(j1->rect().left()) : mLayouter->mCoordX[ix1].junctionEntry(); + float yy = mLayouter->mCoordY[iy0].lanePosition(ilane); + mLines.appendHLine(x0, x1, yy); + } + else + { + float y0, y1; + float xx = mLayouter->mCoordX[ix0].lanePosition(ilane); + if (wToPoint.isEndpoint()) + { + // netjunction -> endpoint + auto itEpc = mLayouter->mEndpointHash.find(wToPoint); + y0 = j0 ? mLayouter->mCoordY[iy0].lanePosition(j0->rect().bottom()) : mLayouter->mCoordY[iy0].junctionExit(); + y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1->rect().top(), true) : mLayouter->mCoordY[iy1].junctionEntry(); + // if (itEpc==mEndpointHash.constEnd()) + // qDebug() << "xxx to endp" << wToPoint.x() << wToPoint.y() << y0 << y1; + } + else + { + // endpoint -> netjunction + auto itEpc = mLayouter->mEndpointHash.find(wFromPoint); + y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0->rect().bottom(), true) : mLayouter->mCoordY[iy0].junctionExit(); + y1 = j1 ? mLayouter->mCoordY[iy1].lanePosition(j1->rect().top()) : mLayouter->mCoordY[iy1].junctionEntry(); + // if (itEpc==mEndpointHash.constEnd()) + // qDebug() << "xxx fr endp" << wFromPoint.x() << wFromPoint.y() << y0 << y1; + } + if (y1 > y0) + mLines.appendVLine(xx, y0, y1); + } + } + drawJunction(); + drawEndpoint(); + } + + void DrawNetThread::drawJunction() + { + for (auto jt = mLayouter->mJunctionHash.constBegin(); jt != mLayouter->mJunctionHash.constEnd(); ++jt) + { + auto epcIt = mLayouter->mEndpointHash.find(jt.key()); + int x = jt.key().x(); + int y = jt.key().y(); + bool isEndpoint = (y % 2 == 0); + + for (const NetLayoutJunctionWire& jw : jt.value()->netById(mId).mWires) + { + int li = jw.mIndex.laneIndex(); + if (jw.mIndex.isHorizontal()) + { + Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint); + float x0 = mLayouter->mCoordX.value(x).lanePosition(jw.mRange.first()); + float x1 = mLayouter->mCoordX.value(x).lanePosition(jw.mRange.last()); + float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mLayouter->mCoordY.value(y).lanePosition(li); + mLines.appendHLine(x0, x1, yy); + } + else + { + float y0, y1; + if (!isEndpoint) + { + y0 = mLayouter->mCoordY.value(y).lanePosition(jw.mRange.first()); + y1 = mLayouter->mCoordY.value(y).lanePosition(jw.mRange.last()); + } + else if (epcIt != mLayouter->mEndpointHash.constEnd()) + { + y0 = epcIt.value().lanePosition(jw.mRange.first(), true); + y1 = epcIt.value().lanePosition(jw.mRange.last(), true); + } + else + { + y0 = mLayouter->mCoordY.value(y).junctionEntry(); + y1 = mLayouter->mCoordY.value(y).junctionExit(); + if (y1 <= y0) + y1 = y0 + 1; + } + float xx = mLayouter->mCoordX.value(x).lanePosition(li); + mLines.appendVLine(xx, y0, y1); + } + } + } + } + + void DrawNetThread::drawEndpoint() + { + for (auto it = mLayouter->mEndpointHash.constBegin(); it != mLayouter->mEndpointHash.constEnd(); ++it) + { + const GraphLayouter::EndpointCoordinate& epc = it.value(); + + QList inputsById = epc.inputPinIndex(mId); + QList outputsById = epc.outputPinIndex(mId); + if (inputsById.isEmpty() && outputsById.isEmpty()) + continue; + + const NetLayoutJunction* nlj = mLayouter->mJunctionHash.value(it.key()); + const GraphLayouter::SceneCoordinate& xScenePos = mLayouter->mCoordX.value(it.key().x()); + float xjLeft = xScenePos.lanePosition(nlj->rect().left()); + float xjRight = xScenePos.lanePosition(nlj->rect().right()); + Q_ASSERT(nlj); + + for (int inpInx : inputsById) + { + if (xjRight >= epc.xInput()) + { + // don't complain if "input" is in fact global output pin + auto ityOut = mLayouter->mGlobalOutputHash.find(mId); + if (ityOut == mLayouter->mGlobalOutputHash.constEnd() || QPoint(mLayouter->mNodeBoundingBox.right() + 1, 2 * ityOut.value()) != it.key()) + qDebug() << "cannot connect input pin" << mId << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput(); + } + else + mLines.appendHLine(xjRight, epc.xInput(), epc.lanePosition(inpInx, true)); + } + for (int outInx : outputsById) + { + if (epc.xOutput() >= xjLeft) + qDebug() << "cannot connect output pin" << mId << it.key().x() << it.key().y() / 2 << xjLeft << epc.xOutput(); + else + mLines.appendHLine(epc.xOutput(), xjLeft, epc.lanePosition(outInx, true)); + } + } + } } // namespace hal From d7cf2e02d5f50b4ae2a3502d5fe2b00f366e3765 Mon Sep 17 00:00:00 2001 From: joern274 Date: Tue, 24 Oct 2023 08:14:37 +0200 Subject: [PATCH 06/22] Bugfix: check for focus disallowed delete action triggered from toolbar --- plugins/gui/src/grouping/grouping_manager_widget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/gui/src/grouping/grouping_manager_widget.cpp b/plugins/gui/src/grouping/grouping_manager_widget.cpp index 7a19e6e76b0..73f785aeb82 100644 --- a/plugins/gui/src/grouping/grouping_manager_widget.cpp +++ b/plugins/gui/src/grouping/grouping_manager_widget.cpp @@ -520,7 +520,8 @@ namespace hal void GroupingManagerWidget::handleDeleteGroupingClicked() { - if (!hasFocus() && !mGroupingTableView->hasFocus()) return; + if (sender() != mDeleteAction && + !hasFocus() && !mGroupingTableView->hasFocus()) return; QModelIndex current = mGroupingTableView->currentIndex(); if (!current.isValid()) return; From 12d34923ef8615833bcb586cc85a6915c36d5ea6 Mon Sep 17 00:00:00 2001 From: joern274 Date: Fri, 27 Oct 2023 20:01:51 +0200 Subject: [PATCH 07/22] Bugfixes + Faster calculation of junction knots --- .../items/nets/standard_graphics_net.h | 2 +- .../graph_widget/layouters/graph_layouter.h | 20 ++- .../layouters/net_layout_junction.h | 23 +++- .../items/nets/standard_graphics_net.cpp | 24 +--- .../graph_widget/layouters/graph_layouter.cpp | 123 +++++++++++++----- .../layouters/net_layout_junction.cpp | 100 ++++++++++---- 6 files changed, 201 insertions(+), 91 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h index b85e743dc9c..1a392a912ef 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h @@ -129,7 +129,7 @@ namespace hal * @param n - The undelying net of the StandardGraphicsNet * @param l - The lines this GraphicsNet consists of */ - StandardGraphicsNet(Net* n, const Lines& l); + StandardGraphicsNet(Net* n, const Lines& l, const QList& knots = QList()); /** * Draws the StandardGraphicsNet in the scene. diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index 9cc7656c7a9..71f85050010 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -60,6 +60,7 @@ namespace hal class NetLayoutJunctionEntries; class CommentSpeechBubble; class CommentEntry; + class JunctionThread; class DrawNetThread; /** @@ -345,7 +346,8 @@ namespace hal QMap mNodeToPositionRollback; private Q_SLOTS: - void handleDrawThreadFinished(); + void handleDrawNetThreadFinished(); + void handleJunctionThreadFinished(); private: void clearLayoutData(); @@ -488,7 +490,8 @@ namespace hal QList mCommentBubbles; QSet mNetsToDraw; QSet::const_iterator mNetIterator; - QList mDrawThreads; + QList mDrawNetThreads; + QList mJunctionThreads; QHash> mLaneMap; }; @@ -501,8 +504,21 @@ namespace hal void drawEndpoint(); public: StandardGraphicsNet::Lines mLines; + QList mKnots; DrawNetThread(u32 id, GraphLayouter* parent) : QThread(parent), mId(id), mLayouter(parent) {;} u32 id() const { return mId; } void run() override; }; + + class JunctionThread : public QThread + { + Q_OBJECT + public: + NetLayoutPoint mNetLayoutPoint; + NetLayoutJunctionEntries mEntries; + NetLayoutJunction* mJunction; + JunctionThread(const NetLayoutPoint& nlp, const NetLayoutJunctionEntries& entr) + : mNetLayoutPoint(nlp), mEntries(entr), mJunction(nullptr) {;} + void run() override; + }; } // namespace hal diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index 3ba33ba072e..cfbd096cf97 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -19,8 +19,6 @@ const int DELTA = 20; const int FIRST = 400; const int GAP = 200; -QColor colorFromId(u32 netId); - namespace hal { /** @@ -279,6 +277,14 @@ namespace hal { * String output for debugging purpose */ QString toString() const; + + /** + * Dump junction entries to file to debug junction routing + * @param pnt Net grid point + */ + void dumpFile(const NetLayoutPoint& pnt) const; + + static QString gridPointName(const QPoint& p); }; /** @@ -318,7 +324,7 @@ namespace hal { bool mPlaced; public: QList mWires; - QList mJunctions; + QList mKnots; NetLayoutJunctionNet(); void addEntry(NetLayoutDirection dir, int laneInx); @@ -339,7 +345,7 @@ namespace hal { void setPlaced() { mPlaced = true; } void addWire(const NetLayoutJunctionWire& wire) { mWires.append(wire); } void replaceWire(const NetLayoutJunctionRange& rng, const NetLayoutJunctionWire& wire); - QList junctionPoints() const { return mJunctions; } + QList junctionKnots() const { return mKnots; } }; /** @@ -385,6 +391,9 @@ namespace hal { void dump() const; NetLayoutJunctionNet netById(u32 id) const { return mNets.value(id); } + enum ErrorType {StraightRouteError = -3, TRouteError = -2, CornerRouteError = -1, Ok = 0 }; + ErrorType lastError() const { return mError; } + #ifdef JUNCTION_DEBUG void toScene(QGraphicsScene* scene) const; void toSceneStep(QGraphicsScene* scene, int istep); @@ -422,6 +431,7 @@ namespace hal { QHash mNets; NetLayoutJunctionOccupiedHash mOccupied; int maxRoad[2]; + ErrorType mError; }; class NetLayoutJunctionHash : public QHash @@ -435,3 +445,8 @@ namespace hal { uint qHash(const LaneIndex& ri); } +#ifdef JUNCTION_DEBUG + void setColorMap(const hal::NetLayoutJunctionEntries& entries); + QColor colorFromId(u32 netId); +#endif + diff --git a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp index 0dee11df7d3..95d6b57c3cf 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp @@ -76,28 +76,12 @@ namespace hal sAlpha = 1; } - StandardGraphicsNet::StandardGraphicsNet(Net* n, const Lines& l) : GraphicsNet(n) + StandardGraphicsNet::StandardGraphicsNet(Net* n, const Lines& l, const QList &knots) : GraphicsNet(n) { - for (const HLine& h : l.mHLines) + for (const QPointF& point : knots) { - for (const VLine& v : l.mVLines) - { - if (h.mSmallX <= v.x && v.x <= h.mBigX) - if (v.mSmallY < h.y && h.y < v.mBigY) - { - QPointF point(v.x, h.y); - mSplits.append(point); - mShape.addEllipse(point, sSplitRadius, sSplitRadius); - } - - if (v.mSmallY <= h.y && h.y <= v.mBigY) - if (h.mSmallX < v.x && v.x < h.mBigX) - { - QPointF point(v.x, h.y); - mSplits.append(point); - mShape.addEllipse(point, sSplitRadius, sSplitRadius); - } - } + mSplits.append(point); + mShape.addEllipse(point, sSplitRadius, sSplitRadius); } qreal smallest_x = std::numeric_limits::max(); diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index a017d5fd496..a14ee68e931 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -629,16 +629,18 @@ namespace hal mEndpointHash[pnt].setInputPins(netIds, 0, 0); } - for (auto it = mJunctionEntries.constBegin(); it != mJunctionEntries.constEnd(); ++it) + auto it = mJunctionEntries.constBegin(); + while (it != mJunctionEntries.constEnd() || !mJunctionThreads.isEmpty()) { - // it.value().dumpFile(it.key()); - // qDebug() << "Junction at" << it.key().x() << it.key().y(); - NetLayoutJunction* nlj = new NetLayoutJunction(it.value()); - /* - if (nlj->lastError() != NetLayoutJunction::Ok) - qDebug() << "Junction route error" << nlj->lastError() << it.key(); - */ - mJunctionHash.insert(it.key(), nlj); + if (it != mJunctionEntries.constEnd() && mJunctionThreads.size() < QThread::idealThreadCount()) + { + JunctionThread* jt = new JunctionThread(it.key(), it.value()); + connect(jt,&QThread::finished,this,&GraphLayouter::handleJunctionThreadFinished); + mJunctionThreads.append(jt); + jt->start(); + ++it; + } + qApp->processEvents(); } } @@ -1324,9 +1326,39 @@ namespace hal mNetsToDraw = mParentContext->nets(); mNetIterator = mNetsToDraw.constBegin(); - while (mNetIterator != mNetsToDraw.constEnd()) + + + + enum LoopState { LoopInit, CanStartThread, WaitForSlot, WaitForLastThread, LoopDone } loopState = LoopInit; + while (loopState != LoopDone) { + if (mNetIterator != mNetsToDraw.constEnd()) + { + if (mDrawNetThreads.size() < QThread::idealThreadCount()) + loopState = CanStartThread; + else + loopState = WaitForSlot; + } + else + { + if (mDrawNetThreads.isEmpty()) + loopState = LoopDone; + else + loopState = WaitForLastThread; + } + + if (loopState == LoopDone) + break; + + if (loopState == WaitForLastThread || loopState == WaitForSlot) + { + qApp->processEvents(); + continue; + } + + Q_ASSERT(loopState == CanStartThread); u32 id = *(mNetIterator++); + Net* n = gNetlist->get_net_by_id(id); if (!n) continue; @@ -1354,28 +1386,31 @@ namespace hal if (!regularNet) continue; - if (mDrawThreads.size() < QThread::idealThreadCount()) + ++doneCount; + if (percentCount) { - ++doneCount; - if (percentCount) - { - if (doneCount % percentCount == 0) - mParentContext->layoutProgress(7 + doneCount / percentCount); - } - else - mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); - - DrawNetThread* dnt = new DrawNetThread(id,this); - connect(dnt,&QThread::finished,this,&GraphLayouter::handleDrawThreadFinished); - mDrawThreads.append(dnt); - dnt->start(); + if (doneCount % percentCount == 0) + mParentContext->layoutProgress(7 + doneCount / percentCount); } - qApp->processEvents(); + else + mParentContext->layoutProgress(7 + (int)floor(92. * doneCount / netCount)); + + DrawNetThread* dnt = new DrawNetThread(id,this); + connect(dnt,&QThread::finished,this,&GraphLayouter::handleDrawNetThreadFinished); + mDrawNetThreads.append(dnt); + dnt->start(); } + } + void GraphLayouter::handleJunctionThreadFinished() + { + JunctionThread* jt = static_cast(sender()); + mJunctionHash.insert(jt->mNetLayoutPoint,jt->mJunction); + mJunctionThreads.removeAll(jt); + jt->deleteLater(); } - void GraphLayouter::handleDrawThreadFinished() + void GraphLayouter::handleDrawNetThreadFinished() { DrawNetThread* dnt = static_cast(sender()); Net* n = gNetlist->get_net_by_id(dnt->id()); @@ -1410,7 +1445,7 @@ namespace hal break; case EndpointList::SourceAndDestination: if (dnt->mLines.nLines() > 0) - graphicsNet = new StandardGraphicsNet(n, dnt->mLines); + graphicsNet = new StandardGraphicsNet(n, dnt->mLines, dnt->mKnots); break; default: Q_ASSERT(0 > 1); // should never occur @@ -1420,7 +1455,8 @@ namespace hal if (graphicsNet) mScene->addGraphItem(graphicsNet); - mDrawThreads.removeAll(dnt); + mDrawNetThreads.removeAll(dnt); + dnt->deleteLater(); } void GraphLayouter::drawNetsIsolated(u32 id, Net* n, const EndpointList& epl) @@ -2861,6 +2897,11 @@ namespace hal mOptimizeNetLayout = enabled; } + void JunctionThread::run() + { + mJunction = new NetLayoutJunction(mEntries); + } + void DrawNetThread::run() { Net* n = gNetlist->get_net_by_id(mId); @@ -2926,15 +2967,18 @@ namespace hal int y = jt.key().y(); bool isEndpoint = (y % 2 == 0); + const GraphLayouter::SceneCoordinate& scX = mLayouter->mCoordX.value(x); + const GraphLayouter::SceneCoordinate& scY = mLayouter->mCoordY.value(y); + for (const NetLayoutJunctionWire& jw : jt.value()->netById(mId).mWires) { int li = jw.mIndex.laneIndex(); if (jw.mIndex.isHorizontal()) { Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint); - float x0 = mLayouter->mCoordX.value(x).lanePosition(jw.mRange.first()); - float x1 = mLayouter->mCoordX.value(x).lanePosition(jw.mRange.last()); - float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mLayouter->mCoordY.value(y).lanePosition(li); + float x0 = scX.lanePosition(jw.mRange.first()); + float x1 = scX.lanePosition(jw.mRange.last()); + float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : scY.lanePosition(li); mLines.appendHLine(x0, x1, yy); } else @@ -2942,8 +2986,8 @@ namespace hal float y0, y1; if (!isEndpoint) { - y0 = mLayouter->mCoordY.value(y).lanePosition(jw.mRange.first()); - y1 = mLayouter->mCoordY.value(y).lanePosition(jw.mRange.last()); + y0 = scY.lanePosition(jw.mRange.first()); + y1 = scY.lanePosition(jw.mRange.last()); } else if (epcIt != mLayouter->mEndpointHash.constEnd()) { @@ -2952,15 +2996,22 @@ namespace hal } else { - y0 = mLayouter->mCoordY.value(y).junctionEntry(); - y1 = mLayouter->mCoordY.value(y).junctionExit(); + y0 = scY.junctionEntry(); + y1 = scY.junctionExit(); if (y1 <= y0) y1 = y0 + 1; } - float xx = mLayouter->mCoordX.value(x).lanePosition(li); + float xx = scX.lanePosition(li); mLines.appendVLine(xx, y0, y1); } } + + for (const QPoint& pnt : jt.value()->netById(mId).mKnots) + { + float x = scX.lanePosition(pnt.x()); + float y = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : scY.lanePosition(pnt.y()); + mKnots.append(QPointF(x,y)); + } } } diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index e0b2f484541..ae9d6fe3942 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -11,8 +11,63 @@ #include #include #include +#include #ifdef JUNCTION_DEBUG +QMap debugColorMap; + +QColor colorFromId(u32 netId) +{ + QColor retval = debugColorMap.value(netId); + if (!retval.isValid()) + return QColor("white"); + return retval; +} + +void setColorMap(const hal::NetLayoutJunctionEntries& entries) +{ + debugColorMap.clear(); + + QMap pattern; + for (int i=0; i<4; i++) + { + int mask = 1 << i; + for (u32 id : entries.mEntries[i]) + pattern[id] |= mask; + } + QSet danglingWire = { 1, 2, 4, 8}; + int count = 0; + + for (auto it = pattern.begin(); it != pattern.end(); ++it) + { + if (danglingWire.contains(it.value())) + { + debugColorMap[it.key()] = QColor::fromRgb(23,25,29); + continue; + } + + int hue = count++ * 25; + if (hue > 255) + { + int cc = (count-10)%20; + int cd = (count-10)/20; + int h = cc * 10; + int s = 80 - cd*40; + int v = 255; + qDebug() << cc << cd << h << s << v; + if (s <= 0) + { + int g = (20*count) % 128 + 128; + debugColorMap[it.key()] = QColor::fromRgb(g,g,g); + } + else + debugColorMap[it.key()] = QColor::fromHsv(h,s,v); + } + else + debugColorMap[it.key()] = QColor::fromHsv(hue,255,255); + } +} + QGraphicsEllipseItem* getEllipse(QPoint p, u32 netId) { float dd = DELTA / 2.; @@ -24,21 +79,10 @@ QGraphicsEllipseItem* getEllipse(QPoint p, u32 netId) } #endif -QColor colorFromId(u32 netId) -{ - int hue = (netId-1) * 25; - if (hue > 255) - { - int gray = (hue - 256) % 160 + 95; - return QColor::fromRgb(gray+1,gray,gray); - } - return QColor::fromHsv(hue,255,255); -} - namespace hal { NetLayoutJunction::NetLayoutJunction(const NetLayoutJunctionEntries& entries) - : mEntries(entries) + : mEntries(entries), mError(Ok) { memset(maxRoad,0,sizeof(maxRoad)); for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) @@ -86,7 +130,7 @@ namespace hal { for (const NetLayoutJunctionWire& vn : vNets) if ((hn.mRange.innerPos(vn.mIndex.laneIndex()) && vn.mRange.contains(hn.mIndex.laneIndex())) || (hn.mRange.contains(vn.mIndex.laneIndex()) && vn.mRange.innerPos(hn.mIndex.laneIndex()))) - it->mJunctions.append(QPoint(vn.mIndex.laneIndex(),hn.mIndex.laneIndex())); + it->mKnots.append(QPoint(vn.mIndex.laneIndex(),hn.mIndex.laneIndex())); } } @@ -395,7 +439,7 @@ namespace hal { reducedPattern = itNet.value().laneIndex(i1) > itNet.value().laneIndex(i0) ? 10 : 6; break; default: - return; + continue; } int roadLink = itNet.value().laneIndex(ilink); @@ -404,7 +448,7 @@ namespace hal { if (mainWires.isEmpty()) { qDebug() << "T-join not found"; - return; + continue; } int minlen = 0; @@ -674,6 +718,9 @@ namespace hal { int vstep = dirHoriz.isLeft() ? -1 : 1; int icount = 0; + int tryMax = 2 * mOccupied.size(); + for (int i=0; i<4; i++) + tryMax += 2* mEntries.mEntries[i].size(); for(;;) { NetLayoutJunctionRange rngVc(netId,iroadHoriz,hcroad); @@ -683,9 +730,10 @@ namespace hal { NetLayoutJunctionRange rngVe = NetLayoutJunctionRange::entryRange(dirVertic,hcroad,netId); - if (++icount > 42) + if (++icount > tryMax) { qDebug() << "giving up"; + mError = CornerRouteError; return; } @@ -708,6 +756,14 @@ namespace hal { } } + void NetLayoutJunctionHash::clearAll() + { + for (NetLayoutJunction* nlj : values()) + delete nlj; + clear(); + } + + NetLayoutJunctionNet::NetLayoutJunctionNet() : mPattern(0), mEntries(0), mPlaced(false) { @@ -860,17 +916,5 @@ namespace hal { return retval; } - NetLayoutJunctionHash::~NetLayoutJunctionHash() - { - clearAll(); - } - - void NetLayoutJunctionHash::clearAll() - { - for (NetLayoutJunction* nlj : values()) - delete nlj; - clear(); - } - uint qHash(const LaneIndex& ri) { return ri.mIndex; } } // namespace hal From 8a3eb4807a7b377234b82b4d90bfb8346f5f85fb Mon Sep 17 00:00:00 2001 From: joern274 Date: Sun, 29 Oct 2023 21:27:44 +0100 Subject: [PATCH 08/22] Added dump junction feature for debugging --- .../gui/graph_widget/graph_context_manager.h | 2 +- .../graph_widget/layouters/graph_layouter.h | 63 +- .../layouters/net_layout_junction.h | 3 +- .../graph_widget/graph_context_manager.cpp | 10 +- .../graph_widget/layouters/graph_layouter.cpp | 1639 +---------------- .../layouters/net_layout_junction.cpp | 15 + 6 files changed, 67 insertions(+), 1665 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/graph_context_manager.h b/plugins/gui/include/gui/graph_widget/graph_context_manager.h index a0e84ba974a..494e14bddfc 100644 --- a/plugins/gui/include/gui/graph_widget/graph_context_manager.h +++ b/plugins/gui/include/gui/graph_widget/graph_context_manager.h @@ -394,7 +394,7 @@ namespace hal u32 mMaxContextId; void dump(const QString& title, u32 mid, u32 xid) const; SettingsItemCheckbox* mSettingDebugGrid; - SettingsItemCheckbox* mSettingNetLayout; + SettingsItemCheckbox* mSettingDumpJunction; SettingsItemCheckbox* mSettingParseLayout; SettingsItemCheckbox* mSettingLayoutBoxes; }; diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index 71f85050010..096cb1ec4e5 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -314,8 +314,8 @@ namespace hal bool done() const; - bool optimizeNetLayoutEnabled(); - void setOptimizeNetLayoutEnabled(bool enbabled); + bool dumpJunctionEnabled(); + void setDumpJunctionEnabled(bool enabled); QVector xValues() const; QVector yValues() const; @@ -353,23 +353,14 @@ namespace hal void clearLayoutData(); void clearComments(); void createBoxes(); - void calculateNets(); void getWireHash(); void findMaxBoxDimensions(); - void alternateMaxChannelLanes(); void findMaxChannelLanes(); - void calculateMaxChannelDimensions(); void calculateJunctionMinDistance(); - void alternateGateOffsets(); void calculateGateOffsets(); - void alternatePlaceGates(); void placeGates(); - void resetRoadsAndJunctions(); void drawNets(); - void alternateDrawNets(); void drawComments(); - void drawNetsJunction(StandardGraphicsNet::Lines& lines, u32 id); - void drawNetsEndpoint(StandardGraphicsNet::Lines& lines, u32 id); void drawNetsIsolated(u32 id, Net* n, const EndpointList& epl); void updateSceneRect(); static bool verifyModulePort(Net* n, const Node& modNode, bool isModInput); @@ -384,72 +375,24 @@ namespace hal bool vRoadJumpPossible(const int x1, const int x2, const int y) const; bool vRoadJumpPossible(const Road* const r1, const Road* const r2) const; - Road* getHRoad(const int x, const int y); - Road* getVRoad(const int x, const int y); Junction* getJunction(const int x, const int y); qreal hRoadHeight(const unsigned int mLanes) const; qreal vRoadWidth(const unsigned int mLanes) const; - qreal sceneYForHChannelLane(const int y, const unsigned int lane) const; - qreal sceneXForVChannelLane(const int x, const unsigned int lane) const; - - qreal sceneXForCloseLeftLaneChange(const int channel_x, unsigned int lane_change) const; - qreal sceneXForFarLeftLaneChange(const int channel_x, unsigned int lane_change) const; - - qreal sceneXForCloseRightLaneChange(const int channel_x, unsigned int lane_change) const; - qreal sceneXForFarRightLaneChange(const int channel_x, unsigned int lane_change) const; - - qreal sceneYForCloseTopLaneChange(const int channel_y, unsigned int lane_change) const; - qreal sceneYForFarTopLaneChange(const int channel_y, unsigned int lane_change) const; - - qreal sceneYForCloseBottomLaneChange(const int channel_y, unsigned int lane_change) const; - qreal sceneYForFarBottomLaneChange(const int channel_y, unsigned int lane_change) const; - - qreal sceneXForCloseLeftLaneChange(const Junction* const j) const; - qreal sceneXForFarLeftLaneChange(const Junction* const j) const; - - qreal sceneXForCloseRightLaneChange(const Junction* const j) const; - qreal sceneXForFarRightLaneChange(const Junction* const j) const; - - qreal sceneYForCloseTopLaneChange(const Junction* const j) const; - qreal sceneYForFarTopLaneChange(const Junction* const j) const; - - qreal sceneYForCloseBottomLaneChange(const Junction* const j) const; - qreal sceneYForFarBottomLaneChange(const Junction* const j) const; - void commitUsedPaths(const UsedPaths& used); static bool isConstNet(const Net* n); NodeBoxes mBoxes; - QHash mHRoads; - QHash mVRoads; QHash mJunctions; QMap mMaxNodeWidthForX; QMap mMaxNodeHeightForY; - QMap mMaxVChannelLanesForX; - QMap mMaxHChannelLanesForY; - - QMap mMaxVChannelLeftSpacingForX; - QMap mMaxVChannelRightSpacingForX; - QMap mMaxHChannelTopSpacingForY; - QMap mMaxHChannelBottomSpacingForY; - - QMap mMaxVChannelWidthForX; - QMap mMaxHChannelHeightForY; - QMap mNodeOffsetForX; QMap mNodeOffsetForY; - QMap mMaxLeftJunctionSpacingForX; - QMap mMaxRightJunctionSpacingForX; - - QMap mMaxTopJunctionSpacingForY; - QMap mMaxBottomJunctionSpacingForY; - QMap mMaxLeftIoPaddingForChannelX; QMap mMaxRightIoPaddingForChannelX; @@ -486,7 +429,7 @@ namespace hal QHash mGlobalInputHash; QHash mGlobalOutputHash; - bool mOptimizeNetLayout; + bool mDumpJunctions; QList mCommentBubbles; QSet mNetsToDraw; QSet::const_iterator mNetIterator; diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index cfbd096cf97..b8cd7df6da5 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -282,7 +282,7 @@ namespace hal { * Dump junction entries to file to debug junction routing * @param pnt Net grid point */ - void dumpFile(const NetLayoutPoint& pnt) const; + void dumpToFile(const QPoint& pnt) const; static QString gridPointName(const QPoint& p); }; @@ -388,7 +388,6 @@ namespace hal { NetLayoutJunction(const NetLayoutJunctionEntries& entries); ~NetLayoutJunction() {;} QRect rect() const { return mRect; } - void dump() const; NetLayoutJunctionNet netById(u32 id) const { return mNets.value(id); } enum ErrorType {StraightRouteError = -3, TRouteError = -2, CornerRouteError = -1, Ok = 0 }; diff --git a/plugins/gui/src/graph_widget/graph_context_manager.cpp b/plugins/gui/src/graph_widget/graph_context_manager.cpp index 4e6b888afda..a0be39acec9 100644 --- a/plugins/gui/src/graph_widget/graph_context_manager.cpp +++ b/plugins/gui/src/graph_widget/graph_context_manager.cpp @@ -38,7 +38,11 @@ namespace hal "eXpert Settings:Debug", "Specifies whether the debug grid is displayed in the Graph View. The gird represents the scene as the layouter interprets it."); - mSettingNetLayout = new SettingsItemCheckbox("Optimize Net Layout", "graph_view/layout_nets", true, "Graph View", "Net optimization - not fully tested yet."); + mSettingDumpJunction = new SettingsItemCheckbox("Dump Junction Data", + "debug/junction", + false, + "eXpert Settings:Debug", + "Dump input data from junction router to file 'junction_data.txt' for external debugging."); mSettingParseLayout = new SettingsItemCheckbox("Apply Parsed Position", "graph_view/layout_parse", true, "Graph View", "Use parsed verilog coordinates if available."); @@ -512,11 +516,11 @@ namespace hal GraphLayouter* GraphContextManager::getDefaultLayouter(GraphContext* const context) const { StandardGraphLayouter* layouter = new StandardGraphLayouter(context); - layouter->setOptimizeNetLayoutEnabled(mSettingNetLayout->value().toBool()); + layouter->setDumpJunctionEnabled(mSettingDumpJunction->value().toBool()); layouter->setParseLayoutEnabled(mSettingParseLayout->value().toBool()); layouter->setLayoutBoxesEnabled(mSettingLayoutBoxes->value().toBool()); - connect(mSettingNetLayout, &SettingsItemCheckbox::boolChanged, layouter, &GraphLayouter::setOptimizeNetLayoutEnabled); + connect(mSettingDumpJunction, &SettingsItemCheckbox::boolChanged, layouter, &GraphLayouter::setDumpJunctionEnabled); connect(mSettingParseLayout, &SettingsItemCheckbox::boolChanged, layouter, &StandardGraphLayouter::setParseLayoutEnabled); connect(mSettingLayoutBoxes, &SettingsItemCheckbox::boolChanged, layouter, &StandardGraphLayouter::setLayoutBoxesEnabled); diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index a14ee68e931..d5823310c7d 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -36,14 +36,13 @@ namespace hal } const static qreal sLaneSpacing = 10; - const static qreal sJunctionPadding = 10; const static qreal sHRoadPadding = 10; const static qreal sVRoadPadding = 10; const static qreal sMinimumVChannelWidth = 20; const static qreal sMinimumHChannelHeight = 20; GraphLayouter::GraphLayouter(GraphContext* context, QObject* parent) - : QObject(parent), mScene(new GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mOptimizeNetLayout(true) + : QObject(parent), mScene(new GraphicsScene(this)), mParentContext(context), mDone(false), mRollbackStatus(0), mDumpJunctions(true) { SelectionDetailsWidget* details = gContentManager->getSelectionDetailsWidget(); if (details) @@ -212,24 +211,32 @@ namespace hal return mYValues.last() + (inx - mYValues.size() - 1) * defaultGridHeight(); } - void GraphLayouter::alternateLayout() + void GraphLayouter::layout() { + QElapsedTimer timer; + timer.start(); + mParentContext->layoutProgress(0); + mScene->deleteAllItems(); + clearLayoutData(); + + createBoxes(); + mParentContext->layoutProgress(1); getWireHash(); mParentContext->layoutProgress(2); findMaxBoxDimensions(); mParentContext->layoutProgress(3); - alternateMaxChannelLanes(); + findMaxChannelLanes(); mParentContext->layoutProgress(4); calculateJunctionMinDistance(); mParentContext->layoutProgress(5); - alternateGateOffsets(); + calculateGateOffsets(); mParentContext->layoutProgress(6); - alternatePlaceGates(); + placeGates(); mParentContext->layoutProgress(7); mDone = true; - alternateDrawNets(); + drawNets(); drawComments(); updateSceneRect(); @@ -240,42 +247,13 @@ namespace hal mScene->debugSetLayouterGrid(xValues(), yValues(), defaultGridHeight(), defaultGridWidth()); #endif mRollbackStatus = 0; - } - void GraphLayouter::layout() - { - QElapsedTimer timer; - timer.start(); - mParentContext->layoutProgress(0); - mScene->deleteAllItems(); - clearLayoutData(); + qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); - createBoxes(); - if (mOptimizeNetLayout) - { - alternateLayout(); - qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); - return; - } - calculateNets(); - findMaxBoxDimensions(); - findMaxChannelLanes(); - resetRoadsAndJunctions(); - calculateMaxChannelDimensions(); - calculateGateOffsets(); - placeGates(); - mDone = true; - drawNets(); - updateSceneRect(); - mScene->moveNetsToBackground(); - mScene->handleExternSelectionChanged(nullptr); + return; -#ifdef GUI_DEBUG_GRID - mScene->debugSetLayouterGrid(xValues(), yValues(), defaultGridHeight(), defaultGridWidth()); -#endif - mRollbackStatus = 0; - qDebug() << "elapsed time (classic) layout [ms]" << timer.elapsed(); + mDone = true; } void GraphLayouter::prepareRollback() @@ -319,14 +297,6 @@ namespace hal mBoxes.clearBoxes(); clearComments(); - for (const GraphLayouter::Road* r : mHRoads.values()) - delete r; - mHRoads.clear(); - - for (const GraphLayouter::Road* r : mVRoads.values()) - delete r; - mVRoads.clear(); - for (const GraphLayouter::Junction* j : mJunctions.values()) delete j; mJunctions.clear(); @@ -334,26 +304,9 @@ namespace hal mMaxNodeWidthForX.clear(); mMaxNodeHeightForY.clear(); - mMaxVChannelLanesForX.clear(); - mMaxHChannelLanesForY.clear(); - - mMaxVChannelLeftSpacingForX.clear(); - mMaxVChannelRightSpacingForX.clear(); - mMaxHChannelTopSpacingForY.clear(); - mMaxHChannelBottomSpacingForY.clear(); - - mMaxVChannelWidthForX.clear(); - mMaxHChannelHeightForY.clear(); - mNodeOffsetForX.clear(); mNodeOffsetForY.clear(); - mMaxLeftJunctionSpacingForX.clear(); - mMaxRightJunctionSpacingForX.clear(); - - mMaxTopJunctionSpacingForY.clear(); - mMaxBottomJunctionSpacingForY.clear(); - mMaxLeftIoPaddingForChannelX.clear(); mMaxRightIoPaddingForChannelX.clear(); @@ -634,6 +587,8 @@ namespace hal { if (it != mJunctionEntries.constEnd() && mJunctionThreads.size() < QThread::idealThreadCount()) { + if (mDumpJunctions) + it.value().dumpToFile(it.key()); JunctionThread* jt = new JunctionThread(it.key(), it.value()); connect(jt,&QThread::finished,this,&GraphLayouter::handleJunctionThreadFinished); mJunctionThreads.append(jt); @@ -644,280 +599,6 @@ namespace hal } } - void GraphLayouter::calculateNets() - { - for (const u32 id : mParentContext->nets()) - { - Net* n = gNetlist->get_net_by_id(id); - assert(n); - - if (n->is_unrouted()) - continue; - - UsedPaths used; - - for (Endpoint* src : n->get_sources()) - { - // FIND SRC BOX - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - NodeBox* src_box = mBoxes.boxForNode(node); - assert(src_box); - - // FOR EVERY DST - for (Endpoint* dst : n->get_destinations()) - { - // FIND DST BOX - node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - if (node.isNull()) - continue; - - NodeBox* dst_box = mBoxes.boxForNode(node); - assert(dst_box); - - // ROAD BASED DISTANCE (x_distance - 1) - const int x_distance = dst_box->x() - src_box->x() - 1; - const int y_distance = dst_box->y() - src_box->y(); - - if (!y_distance && vRoadJumpPossible(src_box->x() + 1, dst_box->x(), src_box->y())) - { - // SPECIAL CASE INDIRECT HORIZONTAL NEIGHBORS - Road* dst_v_road = getVRoad(dst_box->x(), dst_box->y()); - used.mVRoads.insert(dst_v_road); - continue; - } - - Road* src_v_road = getVRoad(src_box->x() + 1, src_box->y()); - - if (!(x_distance || y_distance)) - { - // SPECIAL CASE DIRECT HORIZONTAL NEIGHBORS - used.mVRoads.insert(src_v_road); - continue; - } - - // NORMAL CASE - // CONNECT SRC TO V ROAD, TRAVEL X DISTANCE, TRAVEL Y DISTANCE, CONNECT V ROAD TO DST - used.mVRoads.insert(src_v_road); - - Junction* initial_junction = nullptr; - int remaining_y_distance = y_distance; - - if (y_distance < 0) - { - // TRAVEL UP - initial_junction = getJunction(src_v_road->x, src_v_road->y); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - if (src_v_road->mLanes < initial_junction->mVLanes) - used.mCloseBottomJunctions.insert(initial_junction); - else - used.mFarBottomJunctions.insert(initial_junction); - } - } - else - { - // TRAVEL DOWN - initial_junction = getJunction(src_v_road->x, src_v_road->y + 1); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - if (src_v_road->mLanes < initial_junction->mVLanes) - used.mCloseTopJunctions.insert(initial_junction); - else - used.mFarTopJunctions.insert(initial_junction); - } - - if (!y_distance) - remaining_y_distance = -1; - } - - used.mVJunctions.insert(initial_junction); - - Junction* last_junction = initial_junction; - - if (x_distance) - { - used.mHJunctions.insert(initial_junction); - - int remaining_x_distance = x_distance; - - // TRAVEL REMAINING X DISTANCE - while (remaining_x_distance) - { - Road* r = nullptr; - Junction* j = nullptr; - - if (x_distance > 0) - { - // TRAVEL RIGHT - r = getHRoad(last_junction->x, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - if (last_junction->mHLanes < r->mLanes) - used.mFarRightJunctions.insert(last_junction); - else - used.mCloseRightJunctions.insert(last_junction); - } - - j = getJunction(last_junction->x + 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - if (r->mLanes < j->mHLanes) - used.mCloseLeftJunctions.insert(j); - else - used.mFarLeftJunctions.insert(j); - } - - --remaining_x_distance; - } - else - { - // TRAVEL LEFT - r = getHRoad(last_junction->x - 1, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - if (last_junction->mHLanes < r->mLanes) - used.mFarLeftJunctions.insert(last_junction); - else - used.mCloseLeftJunctions.insert(last_junction); - } - - j = getJunction(last_junction->x - 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - if (r->mLanes < j->mHLanes) - used.mCloseRightJunctions.insert(j); - else - used.mFarRightJunctions.insert(j); - } - - ++remaining_x_distance; - } - - used.mHRoads.insert(r); - used.mHJunctions.insert(j); - - last_junction = j; - } - - used.mVJunctions.insert(last_junction); - } - - // TRAVEL REMAINING Y DISTANCE - if (remaining_y_distance > 0) - { - while (remaining_y_distance != 1) - { - // TRAVEL DOWN - Road* r = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != r->mLanes) - { - if (last_junction->mVLanes < r->mLanes) - used.mFarBottomJunctions.insert(last_junction); - else - used.mCloseBottomJunctions.insert(last_junction); - } - - Junction* j = getJunction(last_junction->x, last_junction->y + 1); - - if (r->mLanes != j->mVLanes) - { - if (r->mLanes < j->mVLanes) - used.mCloseTopJunctions.insert(j); - else - used.mFarTopJunctions.insert(j); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - --remaining_y_distance; - } - } - else - { - while (remaining_y_distance != -1) - { - // TRAVEL UP - Road* r = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != r->mLanes) - { - if (last_junction->mVLanes < r->mLanes) - used.mFarTopJunctions.insert(last_junction); - else - used.mCloseTopJunctions.insert(last_junction); - } - - Junction* j = getJunction(last_junction->x, last_junction->y - 1); - - if (r->mLanes != j->mVLanes) - { - if (r->mLanes < j->mVLanes) - used.mCloseBottomJunctions.insert(j); - else - used.mFarBottomJunctions.insert(j); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - ++remaining_y_distance; - } - } - - Road* dst_road = nullptr; - - if (y_distance > 0) - { - // TRAVEL DOWN - dst_road = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != dst_road->mLanes) - { - if (last_junction->mVLanes < dst_road->mLanes) - used.mFarBottomJunctions.insert(last_junction); - else - used.mCloseBottomJunctions.insert(last_junction); - } - } - else - { - // TRAVEL UP - dst_road = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != dst_road->mLanes) - { - if (last_junction->mVLanes < dst_road->mLanes) - used.mFarTopJunctions.insert(last_junction); - else - used.mCloseTopJunctions.insert(last_junction); - } - } - - used.mVJunctions.insert(last_junction); - used.mVRoads.insert(dst_road); - } - } - - commitUsedPaths(used); - } - } - void GraphLayouter::findMaxBoxDimensions() { for (const NodeBox* box : mBoxes) @@ -946,7 +627,7 @@ namespace hal } } - void GraphLayouter::alternateMaxChannelLanes() + void GraphLayouter::findMaxChannelLanes() { // maximum parallel wires for atomic network for (auto it = mWireHash.constBegin(); it != mWireHash.constEnd(); ++it) @@ -993,123 +674,6 @@ namespace hal } } - void GraphLayouter::findMaxChannelLanes() - { - for (const Road* r : mVRoads.values()) - storeMax(mMaxVChannelLanesForX, r->x, r->mLanes); - - for (const Road* r : mHRoads.values()) - storeMax(mMaxHChannelLanesForY, r->y, r->mLanes); - - for (const Junction* j : mJunctions.values()) - { - storeMax(mMaxVChannelLanesForX, j->x, j->mVLanes); - storeMax(mMaxHChannelLanesForY, j->y, j->mHLanes); - } - } - - void GraphLayouter::resetRoadsAndJunctions() - { - for (Road* r : mHRoads.values()) - r->mLanes = 0; - - for (Road* r : mVRoads.values()) - r->mLanes = 0; - - for (Junction* j : mJunctions.values()) - { - // LEFT - unsigned int combined_lane_changes = j->mCloseLeftLaneChanges + j->mFarLeftLaneChanges; - qreal spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxLeftJunctionSpacingForX, j->x, spacing); - - // RIGHT - combined_lane_changes = j->mCloseRightLaneChanges + j->mFarRightLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxRightJunctionSpacingForX, j->x, spacing); - - // TOP - combined_lane_changes = j->mCloseTopLaneChanges + j->mFarTopLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxTopJunctionSpacingForY, j->y, spacing); - - // BOTTOM - combined_lane_changes = j->mCloseBottomLaneChanges + j->mFarBottomLaneChanges; - spacing = 0; - - if (combined_lane_changes) - spacing = (combined_lane_changes - 1) * sLaneSpacing + sJunctionPadding; - - storeMax(mMaxBottomJunctionSpacingForY, j->y, spacing); - - j->mHLanes = 0; - j->mVLanes = 0; - - j->mCloseLeftLaneChanges = 0; - j->mCloseRightLaneChanges = 0; - j->mCloseTopLaneChanges = 0; - j->mCloseBottomLaneChanges = 0; - - j->mFarLeftLaneChanges = 0; - j->mFarRightLaneChanges = 0; - j->mFarTopLaneChanges = 0; - j->mFarBottomLaneChanges = 0; - } - } - - void GraphLayouter::calculateMaxChannelDimensions() - { - auto i = mMaxVChannelLanesForX.constBegin(); - while (i != mMaxVChannelLanesForX.constEnd()) - { - qreal left_spacing = std::max(sVRoadPadding + mMaxLeftIoPaddingForChannelX.value(i.key()), mMaxLeftJunctionSpacingForX.value(i.key())); - mMaxVChannelLeftSpacingForX.insert(i.key(), left_spacing); - - qreal right_spacing = std::max(sVRoadPadding + mMaxRightIoPaddingForChannelX.value(i.key()), mMaxRightJunctionSpacingForX.value(i.key())); - mMaxVChannelRightSpacingForX.insert(i.key(), right_spacing); - - qreal width = left_spacing + right_spacing; - - if (i.value()) - width += (i.value() - 1) * sLaneSpacing; - - mMaxVChannelWidthForX.insert(i.key(), std::max(width, sMinimumVChannelWidth)); - - ++i; - } - - i = mMaxHChannelLanesForY.constBegin(); - while (i != mMaxHChannelLanesForY.constEnd()) - { - qreal top_spacing = std::max(sHRoadPadding, mMaxTopJunctionSpacingForY.value(i.key())); - mMaxHChannelTopSpacingForY.insert(i.key(), top_spacing); - - qreal bottom_spacing = std::max(sHRoadPadding, mMaxBottomJunctionSpacingForY.value(i.key())); - mMaxHChannelBottomSpacingForY.insert(i.key(), bottom_spacing); - - qreal height = top_spacing + bottom_spacing; - - if (i.value()) - height += (i.value() - 1) * sLaneSpacing; - - mMaxHChannelHeightForY.insert(i.key(), std::max(height, sMinimumHChannelHeight)); - - ++i; - } - } - void GraphLayouter::calculateJunctionMinDistance() { for (auto itJun = mJunctionHash.constBegin(); itJun != mJunctionHash.constEnd(); ++itJun) @@ -1140,7 +704,7 @@ namespace hal } } - void GraphLayouter::alternateGateOffsets() + void GraphLayouter::calculateGateOffsets() { QHash xInputPadding; QHash xOutputPadding; @@ -1216,48 +780,7 @@ namespace hal } } - void GraphLayouter::calculateGateOffsets() - { - mNodeOffsetForX.insert(0, 0); - mNodeOffsetForY.insert(0, 0); - - mXValues.append(0); - mYValues.append(0); - - if (mMaxXIndex) - for (int i = 1; i <= mMaxXIndex; ++i) - { - qreal offset = mNodeOffsetForX.value(i - 1) + mMaxNodeWidthForX.value(i - 1) + std::max(mMaxVChannelWidthForX.value(i), sMinimumVChannelWidth); - mNodeOffsetForX.insert(i, offset); - mXValues.append(offset); - } - - if (mMinXIndex) - for (int i = -1; i >= mMinXIndex; --i) - { - qreal offset = mNodeOffsetForX.value(i + 1) - mMaxNodeWidthForX.value(i) - std::max(mMaxVChannelWidthForX.value(i + 1), sMinimumVChannelWidth); - mNodeOffsetForX.insert(i, offset); - mXValues.prepend(offset); - } - - if (mMaxYIndex) - for (int i = 1; i <= mMaxYIndex; ++i) - { - qreal offset = mNodeOffsetForY.value(i - 1) + mMaxNodeHeightForY.value(i - 1) + std::max(mMaxHChannelHeightForY.value(i), sMinimumHChannelHeight); - mNodeOffsetForY.insert(i, offset); - mYValues.append(offset); - } - - if (mMinYIndex) - for (int i = -1; i >= mMinYIndex; --i) - { - qreal offset = mNodeOffsetForY.value(i + 1) - mMaxNodeHeightForY.value(i) - std::max(mMaxHChannelHeightForY.value(i + 1), sMinimumHChannelHeight); - mNodeOffsetForY.insert(i, offset); - mYValues.prepend(offset); - } - } - - void GraphLayouter::alternatePlaceGates() + void GraphLayouter::placeGates() { for (const NodeBox* box : mBoxes) { @@ -1285,15 +808,6 @@ namespace hal } } - void GraphLayouter::placeGates() - { - for (NodeBox* box : mBoxes) - { - box->setItemPosition(mNodeOffsetForX.value(box->x()), mNodeOffsetForY.value(box->y())); - mScene->addGraphItem(box->item()); - } - } - void GraphLayouter::drawComments() { for (NodeBox* box : mBoxes) @@ -1309,7 +823,7 @@ namespace hal } } - void GraphLayouter::alternateDrawNets() + void GraphLayouter::drawNets() { // lane for given wire and net id @@ -1498,890 +1012,25 @@ namespace hal mScene->addGraphItem(net_item); } - void GraphLayouter::drawNetsEndpoint(StandardGraphicsNet::Lines& lines, u32 id) + void GraphLayouter::updateSceneRect() { - for (auto it = mEndpointHash.constBegin(); it != mEndpointHash.constEnd(); ++it) - { - const EndpointCoordinate& epc = it.value(); - - QList inputsById = epc.inputPinIndex(id); - QList outputsById = epc.outputPinIndex(id); - if (inputsById.isEmpty() && outputsById.isEmpty()) - continue; + // SCENE RECT STUFF BEHAVES WEIRDLY, FURTHER RESEARCH REQUIRED + //QRectF rect = mScene->sceneRect(); - const NetLayoutJunction* nlj = mJunctionHash.value(it.key()); - const SceneCoordinate& xScenePos = mCoordX.value(it.key().x()); - float xjLeft = xScenePos.lanePosition(nlj->rect().left()); - float xjRight = xScenePos.lanePosition(nlj->rect().right()); - Q_ASSERT(nlj); + QRectF rect(mScene->itemsBoundingRect()); + rect.adjust(-200, -200, 200, 200); + mScene->setSceneRect(rect); + } - for (int inpInx : inputsById) - { - if (xjRight >= epc.xInput()) - { - // don't complain if "input" is in fact global output pin - auto ityOut = mGlobalOutputHash.find(id); - if (ityOut == mGlobalOutputHash.constEnd() || QPoint(mNodeBoundingBox.right() + 1, 2 * ityOut.value()) != it.key()) - qDebug() << "cannot connect input pin" << id << it.key().x() << it.key().y() / 2 << xjRight << epc.xInput(); - } - else - lines.appendHLine(xjRight, epc.xInput(), epc.lanePosition(inpInx, true)); - } - for (int outInx : outputsById) - { - if (epc.xOutput() >= xjLeft) - qDebug() << "cannot connect output pin" << id << it.key().x() << it.key().y() / 2 << xjLeft << epc.xOutput(); - else - lines.appendHLine(epc.xOutput(), xjLeft, epc.lanePosition(outInx, true)); - } - } + bool GraphLayouter::boxExists(const int x, const int y) const + { + return mBoxes.boxForPoint(QPoint(x, y)) != nullptr; } - void GraphLayouter::drawNetsJunction(StandardGraphicsNet::Lines& lines, u32 id) + bool GraphLayouter::hRoadJumpPossible(const int x, const int y1, const int y2) const { - for (auto jt = mJunctionHash.constBegin(); jt != mJunctionHash.constEnd(); ++jt) - { - auto epcIt = mEndpointHash.find(jt.key()); - int x = jt.key().x(); - int y = jt.key().y(); - bool isEndpoint = (y % 2 == 0); - - for (const NetLayoutJunctionWire& jw : jt.value()->netById(id).mWires) - { - int li = jw.mIndex.laneIndex(); - if (jw.mIndex.isHorizontal()) - { - Q_ASSERT(epcIt != mEndpointHash.constEnd() || !isEndpoint); - float x0 = mCoordX.value(x).lanePosition(jw.mRange.first()); - float x1 = mCoordX.value(x).lanePosition(jw.mRange.last()); - float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mCoordY.value(y).lanePosition(li); - lines.appendHLine(x0, x1, yy); - } - else - { - float y0, y1; - if (!isEndpoint) - { - y0 = mCoordY.value(y).lanePosition(jw.mRange.first()); - y1 = mCoordY.value(y).lanePosition(jw.mRange.last()); - } - else if (epcIt != mEndpointHash.constEnd()) - { - y0 = epcIt.value().lanePosition(jw.mRange.first(), true); - y1 = epcIt.value().lanePosition(jw.mRange.last(), true); - } - else - { - y0 = mCoordY.value(y).junctionEntry(); - y1 = mCoordY.value(y).junctionExit(); - if (y1 <= y0) - y1 = y0 + 1; - } - float xx = mCoordX.value(x).lanePosition(li); - lines.appendVLine(xx, y0, y1); - } - } - } - } - - void GraphLayouter::drawNets() - { - // ROADS AND JUNCTIONS FILLED LEFT TO RIGHT, TOP TO BOTTOM - for (const u32 id : mParentContext->nets()) - { - Net* n = gNetlist->get_net_by_id(id); - assert(n); - - QSet outputAssigned; - - if (n->is_unrouted()) - { - // HANDLE GLOBAL NETS - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* src : n->get_sources()) - { - if (src->get_gate()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb && !outputAssigned.contains(nb)) - { - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - outputAssigned.insert(nb); - } - } - } - - QSet inputAssigned; - - for (Endpoint* dst : n->get_destinations()) - { - if (dst->get_gate()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb && !inputAssigned.contains(nb)) - { - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - inputAssigned.insert(nb); - } - } - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - continue; - } - - bool use_label = isConstNet(n); - - if (use_label) - { - LabeledSeparatedNet* net_item = new LabeledSeparatedNet(n, QString::fromStdString(n->get_name())); - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (!node.isNull()) - { - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - } - } - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - // incomplete_net: existing destination or source of net not visible - // bool incomplete_net = false; - - bool src_found = false; - bool dst_found = false; - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (!node.isNull()) - src_found = true; - // else incomplete_net = true; - } - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (!node.isNull()) - dst_found = true; - // else incomplete_net = true; - } - - if (src_found && !dst_found) - { - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* src : n->get_sources()) - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addOutput(nb->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - if (!src_found && dst_found) - { - ArrowSeparatedNet* net_item = new ArrowSeparatedNet(n); - - for (Endpoint* dst : n->get_destinations()) - { - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - net_item->addInput(nb->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name()))); - } - - net_item->finalize(); - mScene->addGraphItem(net_item); - - continue; - } - - // HANDLE NORMAL NETS - UsedPaths used; - StandardGraphicsNet::Lines lines; - - // FOR EVERY SRC - for (Endpoint* src : n->get_sources()) - { - // FIND SRC BOX - const NodeBox* src_box = nullptr; - { - Node node = mParentContext->nodeForGate(src->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - src_box = nb; - } - assert(src_box); - - const QPointF src_pin_position = src_box->item()->getOutputScenePosition(n->get_id(), QString::fromStdString(src->get_pin()->get_name())); - - // FOR EVERY DST - for (Endpoint* dst : n->get_destinations()) - { - // FIND DST BOX - const NodeBox* dst_box = nullptr; - - Node node = mParentContext->nodeForGate(dst->get_gate()->get_id()); - - if (node.isNull()) - continue; - - const NodeBox* nb = mBoxes.boxForNode(node); - if (nb) - dst_box = nb; - - assert(dst_box); - - // don't attempt to loop back a module output into its input - // (if this triggers, we found the net because it also has - // destinations outside the module) - if (src_box == dst_box && src_box->type() == Node::Module) - continue; - - QPointF dst_pin_position = dst_box->item()->getInputScenePosition(n->get_id(), QString::fromStdString(dst->get_pin()->get_name())); - - // ROAD BASED DISTANCE (x_distance - 1) - const int x_distance = dst_box->x() - src_box->x() - 1; - const int y_distance = dst_box->y() - src_box->y(); - - if (!y_distance && vRoadJumpPossible(src_box->x() + 1, dst_box->x(), src_box->y())) - { - // SPECIAL CASE INDIRECT HORIZONTAL NEIGHBORS - Road* dst_v_road = getVRoad(dst_box->x(), dst_box->y()); - - qreal x = sceneXForVChannelLane(dst_v_road->x, dst_v_road->mLanes); - - lines.appendHLine(src_pin_position.x(), x, src_pin_position.y()); - - if (src_pin_position.y() < dst_pin_position.y()) - lines.appendVLine(x, src_pin_position.y(), dst_pin_position.y()); - else if (src_pin_position.y() > dst_pin_position.y()) - lines.appendVLine(x, dst_pin_position.y(), src_pin_position.y()); - - lines.appendHLine(x, dst_pin_position.x(), dst_pin_position.y()); - - used.mVRoads.insert(dst_v_road); - continue; - } - - Road* src_v_road = getVRoad(src_box->x() + 1, src_box->y()); - - if (!(x_distance || y_distance)) - { - // SPECIAL CASE DIRECT HORIZONTAL NEIGHBORS - qreal x = sceneXForVChannelLane(src_v_road->x, src_v_road->mLanes); - - lines.appendHLine(src_pin_position.x(), x, src_pin_position.y()); - - if (src_pin_position.y() < dst_pin_position.y()) - lines.appendVLine(x, src_pin_position.y(), dst_pin_position.y()); - else if (src_pin_position.y() > dst_pin_position.y()) - lines.appendVLine(x, dst_pin_position.y(), src_pin_position.y()); - - lines.appendHLine(x, dst_pin_position.x(), dst_pin_position.y()); - - used.mVRoads.insert(src_v_road); - continue; - } - - // NORMAL CASE - // CONNECT SRC TO V ROAD, TRAVEL X DISTANCE, TRAVEL Y DISTANCE, CONNECT V ROAD TO DST - QPointF current_position(src_pin_position); - current_position.setX(sceneXForVChannelLane(src_v_road->x, src_v_road->mLanes)); - lines.appendHLine(src_pin_position.x(), current_position.x(), src_pin_position.y()); - used.mVRoads.insert(src_v_road); - - Junction* initial_junction = nullptr; - int remaining_y_distance = y_distance; - - if (y_distance < 0) - { - // TRAVEL UP - initial_junction = getJunction(src_v_road->x, src_v_road->y); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - // R -> J - if (src_v_road->mLanes < initial_junction->mVLanes) - { - // POS - qreal y = sceneYForCloseBottomLaneChange(initial_junction->y, initial_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseBottomJunctions.insert(initial_junction); - } - else - { - // NEG - qreal y = sceneYForFarBottomLaneChange(initial_junction->y, initial_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarBottomJunctions.insert(initial_junction); - } - - qreal x = sceneXForVChannelLane(initial_junction->x, initial_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - else - { - // TRAVEL DOWN - initial_junction = getJunction(src_v_road->x, src_v_road->y + 1); - - if (src_v_road->mLanes != initial_junction->mVLanes) - { - // R -> J - if (src_v_road->mLanes < initial_junction->mVLanes) - { - // POS - qreal y = sceneYForCloseTopLaneChange(initial_junction->y, initial_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseTopJunctions.insert(initial_junction); - } - else - { - // NEG - qreal y = sceneYForFarTopLaneChange(initial_junction->y, initial_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarTopJunctions.insert(initial_junction); - } - - qreal x = sceneXForVChannelLane(initial_junction->x, initial_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - if (!y_distance) - remaining_y_distance = -1; - } - - used.mVJunctions.insert(initial_junction); - - Junction* last_junction = initial_junction; - - if (x_distance) - { - { - qreal y = sceneYForHChannelLane(initial_junction->y, initial_junction->mHLanes); - - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - used.mHJunctions.insert(initial_junction); - } - - int remaining_x_distance = x_distance; - - // TRAVEL REMAINING X DISTANCE - while (remaining_x_distance) - { - Road* r = nullptr; - Junction* j = nullptr; - - if (x_distance > 0) - { - // TRAVEL RIGHT - r = getHRoad(last_junction->x, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - // J -> R - if (last_junction->mHLanes < r->mLanes) - { - // POS - qreal x = sceneXForFarRightLaneChange(last_junction->x, last_junction->mFarRightLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mFarRightJunctions.insert(last_junction); - } - else - { - // NEG - qreal x = sceneXForCloseRightLaneChange(last_junction->x, last_junction->mCloseRightLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mCloseRightJunctions.insert(last_junction); - } - - qreal y = sceneYForHChannelLane(r->y, r->mLanes); - - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - j = getJunction(last_junction->x + 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - // R -> J - if (r->mLanes < j->mHLanes) - { - // POS - qreal x = sceneXForCloseLeftLaneChange(j->x, j->mCloseLeftLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mCloseLeftJunctions.insert(j); - } - else - { - // NEG - qreal x = sceneXForFarLeftLaneChange(j->x, j->mFarLeftLaneChanges); - lines.appendHLine(current_position.x(), x, current_position.y()); - current_position.setX(x); - used.mFarLeftJunctions.insert(j); - } - - qreal y = sceneYForHChannelLane(j->y, j->mHLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - --remaining_x_distance; - } - else - { - // TRAVEL LEFT - r = getHRoad(last_junction->x - 1, last_junction->y); - - if (last_junction->mHLanes != r->mLanes) - { - // J -> R - if (last_junction->mHLanes < r->mLanes) - { - // POS - qreal x = sceneXForFarLeftLaneChange(last_junction->x, last_junction->mFarLeftLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mFarLeftJunctions.insert(last_junction); - } - else - { - // NEG - qreal x = sceneXForCloseLeftLaneChange(last_junction->x, last_junction->mCloseLeftLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mCloseLeftJunctions.insert(last_junction); - } - - qreal y = sceneYForHChannelLane(r->y, r->mLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - j = getJunction(last_junction->x - 1, last_junction->y); - - if (r->mLanes != j->mHLanes) - { - // R -> J - if (r->mLanes < j->mHLanes) - { - // POS - qreal x = sceneXForCloseRightLaneChange(j->x, j->mCloseRightLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mCloseRightJunctions.insert(j); - } - else - { - // NEG - qreal x = sceneXForFarRightLaneChange(j->x, j->mFarRightLaneChanges); - lines.appendHLine(x, current_position.x(), current_position.y()); - current_position.setX(x); - used.mFarRightJunctions.insert(j); - } - - qreal y = sceneYForHChannelLane(j->y, j->mHLanes); - - // DUPLICATE CODE ? - if (current_position.y() < y) - lines.appendVLine(current_position.x(), current_position.y(), y); - else - lines.appendVLine(current_position.x(), y, current_position.y()); - - current_position.setY(y); - } - - ++remaining_x_distance; - } - - used.mHRoads.insert(r); - used.mHJunctions.insert(j); - - last_junction = j; - } - - qreal x = sceneXForVChannelLane(last_junction->x, last_junction->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - used.mVJunctions.insert(last_junction); - } - - // TRAVEL REMAINING Y DISTANCE - if (remaining_y_distance > 0) - { - while (remaining_y_distance != 1) - { - // TRAVEL DOWN - Road* r = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != r->mLanes) - { - // J -> R - if (last_junction->mVLanes < r->mLanes) - { - // POS - qreal y = sceneYForFarBottomLaneChange(last_junction->y, last_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarBottomJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseBottomLaneChange(last_junction->y, last_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseBottomJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(r->x, r->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - Junction* j = getJunction(last_junction->x, last_junction->y + 1); - - if (r->mLanes != j->mVLanes) - { - // R -> J - if (r->mLanes < j->mVLanes) - { - // POS - qreal y = sceneYForCloseTopLaneChange(j->y, j->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseTopJunctions.insert(j); - } - else - { - // NEG - qreal y = sceneYForFarTopLaneChange(j->y, j->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarTopJunctions.insert(j); - } - - qreal x = sceneXForVChannelLane(j->x, j->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - --remaining_y_distance; - } - } - else - { - while (remaining_y_distance != -1) - { - // TRAVEL UP - Road* r = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != r->mLanes) - { - // J -> R - if (last_junction->mVLanes < r->mLanes) - { - // POS - qreal y = sceneYForFarTopLaneChange(last_junction->y, last_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarTopJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseTopLaneChange(last_junction->y, last_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseTopJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(r->x, r->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - Junction* j = getJunction(last_junction->x, last_junction->y - 1); - - if (r->mLanes != j->mVLanes) - { - // R -> J - if (r->mLanes < j->mVLanes) - { - // POS - qreal y = sceneYForCloseBottomLaneChange(j->y, j->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseBottomJunctions.insert(j); - } - else - { - // NEG - qreal y = sceneYForFarBottomLaneChange(j->y, j->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarBottomJunctions.insert(j); - } - - qreal x = sceneXForVChannelLane(j->x, j->mVLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - - used.mVRoads.insert(r); - used.mVJunctions.insert(j); - - last_junction = j; - - ++remaining_y_distance; - } - } - - Road* dst_road = nullptr; - - if (y_distance > 0) - { - // TRAVEL DOWN - dst_road = getVRoad(last_junction->x, last_junction->y); - - if (last_junction->mVLanes != dst_road->mLanes) - { - // J -> R - if (last_junction->mVLanes < dst_road->mLanes) - { - // POS - qreal y = sceneYForFarBottomLaneChange(last_junction->y, last_junction->mFarBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mFarBottomJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseBottomLaneChange(last_junction->y, last_junction->mCloseBottomLaneChanges); - lines.appendVLine(current_position.x(), current_position.y(), y); - current_position.setY(y); - used.mCloseBottomJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(dst_road->x, dst_road->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - else - { - // TRAVEL UP - dst_road = getVRoad(last_junction->x, last_junction->y - 1); - - if (last_junction->mVLanes != dst_road->mLanes) - { - // J -> R - if (last_junction->mVLanes < dst_road->mLanes) - { - // POS - qreal y = sceneYForFarTopLaneChange(last_junction->y, last_junction->mFarTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mFarTopJunctions.insert(last_junction); - } - else - { - // NEG - qreal y = sceneYForCloseTopLaneChange(last_junction->y, last_junction->mCloseTopLaneChanges); - lines.appendVLine(current_position.x(), y, current_position.y()); - current_position.setY(y); - used.mCloseTopJunctions.insert(last_junction); - } - - qreal x = sceneXForVChannelLane(dst_road->x, dst_road->mLanes); - - if (current_position.x() < x) - lines.appendHLine(current_position.x(), x, current_position.y()); - else - lines.appendHLine(x, current_position.x(), current_position.y()); - - current_position.setX(x); - } - } - - used.mVJunctions.insert(last_junction); - - if (current_position.y() < dst_pin_position.y()) - lines.appendVLine(current_position.x(), current_position.y(), dst_pin_position.y()); - else - lines.appendVLine(current_position.x(), dst_pin_position.y(), current_position.y()); - - current_position.setY(dst_pin_position.y()); - - used.mVRoads.insert(dst_road); - - lines.appendHLine(current_position.x(), dst_pin_position.x(), current_position.y()); - - current_position = src_pin_position; - } - } - - lines.mergeLines(mScene); - if (lines.nLines() > 0) - { - StandardGraphicsNet* GraphicsNet = new StandardGraphicsNet(n, lines); - mScene->addGraphItem(GraphicsNet); - } - commitUsedPaths(used); - } - } - - void GraphLayouter::updateSceneRect() - { - // SCENE RECT STUFF BEHAVES WEIRDLY, FURTHER RESEARCH REQUIRED - //QRectF rect = mScene->sceneRect(); - - QRectF rect(mScene->itemsBoundingRect()); - rect.adjust(-200, -200, 200, 200); - mScene->setSceneRect(rect); - } - - bool GraphLayouter::boxExists(const int x, const int y) const - { - return mBoxes.boxForPoint(QPoint(x, y)) != nullptr; - } - - bool GraphLayouter::hRoadJumpPossible(const int x, const int y1, const int y2) const - { - if (y1 == y2) - return false; + if (y1 == y2) + return false; int bottom_y = y1; int difference = y1 - y2; @@ -2446,30 +1095,6 @@ namespace hal return vRoadJumpPossible(r1->x, r2->x, r1->y); } - GraphLayouter::Road* GraphLayouter::getHRoad(const int x, const int y) - { - QPoint p(x, y); - auto it = mHRoads.find(p); - if (it != mHRoads.end()) - return it.value(); - - GraphLayouter::Road* r = new Road(x, y); - mHRoads.insert(p, r); - return r; - } - - GraphLayouter::Road* GraphLayouter::getVRoad(const int x, const int y) - { - QPoint p(x, y); - auto it = mVRoads.find(p); - if (it != mVRoads.end()) - return it.value(); - - GraphLayouter::Road* r = new Road(x, y); - mVRoads.insert(p, r); - return r; - } - GraphLayouter::Junction* GraphLayouter::getJunction(const int x, const int y) { QPoint p(x, y); @@ -2506,192 +1131,8 @@ namespace hal return width; } - qreal GraphLayouter::sceneYForHChannelLane(const int y, const unsigned int lane) const - { - // LINES NUMBERED FROM 0 - assert(mNodeOffsetForY.contains(y) || mNodeOffsetForY.contains(y - 1)); - - const qreal offset = lane * sLaneSpacing; - - if (y == 0) - return mNodeOffsetForY.value(y) - mMaxHChannelHeightForY.value(y) + mMaxHChannelTopSpacingForY.value(y) + offset; - else - return mNodeOffsetForY.value(y - 1) + mMaxNodeHeightForY.value(y - 1) + mMaxHChannelTopSpacingForY.value(y) + offset; - } - - qreal GraphLayouter::sceneXForVChannelLane(const int x, const unsigned int lane) const - { - // LINES NUMBERED FROM 0 - assert(mNodeOffsetForX.contains(x) || mNodeOffsetForX.contains(x - 1)); - - const qreal offset = lane * sLaneSpacing; - - if (mNodeOffsetForX.contains(x)) - return mNodeOffsetForX.value(x) - mMaxVChannelWidthForX.value(x) + mMaxVChannelLeftSpacingForX.value(x) + offset; - else - return mNodeOffsetForX.value(x - 1) + mMaxNodeWidthForX.value(x - 1) + mMaxVChannelLeftSpacingForX.value(x) + offset; - } - - qreal GraphLayouter::sceneXForCloseLeftLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelWidthForX.value(channel_x) + mMaxVChannelLeftSpacingForX.value(channel_x) - sJunctionPadding - lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelLeftSpacingForX.value(channel_x) - sJunctionPadding - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForFarLeftLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelWidthForX.value(channel_x) + mMaxVChannelLeftSpacingForX.value(channel_x) - mMaxLeftJunctionSpacingForX.value(channel_x) - + lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelLeftSpacingForX.value(channel_x) - mMaxLeftJunctionSpacingForX.value(channel_x) - + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForCloseRightLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) + sJunctionPadding + lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelWidthForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) - + sJunctionPadding + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForFarRightLaneChange(const int channel_x, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - assert(mNodeOffsetForX.contains(channel_x) || mNodeOffsetForX.contains(channel_x - 1)); - - if (mNodeOffsetForX.contains(channel_x)) - return mNodeOffsetForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) + mMaxRightJunctionSpacingForX.value(channel_x) - lane_change * sLaneSpacing; - else - return mNodeOffsetForX.value(channel_x - 1) + mMaxNodeWidthForX.value(channel_x - 1) + mMaxVChannelWidthForX.value(channel_x) - mMaxVChannelRightSpacingForX.value(channel_x) - + mMaxRightJunctionSpacingForX.value(channel_x) - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForCloseTopLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelHeightForY.value(channel_y) + mMaxHChannelTopSpacingForY.value(channel_y) - sJunctionPadding - lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelTopSpacingForY.value(channel_y) - sJunctionPadding - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForFarTopLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelHeightForY.value(channel_y) + mMaxHChannelTopSpacingForY.value(channel_y) - mMaxTopJunctionSpacingForY.value(channel_y) - + lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelTopSpacingForY.value(channel_y) - mMaxTopJunctionSpacingForY.value(channel_y) - + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForCloseBottomLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) + sJunctionPadding + lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelHeightForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) - + sJunctionPadding + lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneYForFarBottomLaneChange(const int channel_y, unsigned int lane_change) const - { - // LANE CHANGES COUNTED FROM 0 - if (channel_y == 0) - return mNodeOffsetForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) + mMaxBottomJunctionSpacingForY.value(channel_y) - lane_change * sLaneSpacing; - else - return mNodeOffsetForY.value(channel_y - 1) + mMaxNodeHeightForY.value(channel_y - 1) + mMaxHChannelHeightForY.value(channel_y) - mMaxHChannelBottomSpacingForY.value(channel_y) - + mMaxBottomJunctionSpacingForY.value(channel_y) - lane_change * sLaneSpacing; - } - - qreal GraphLayouter::sceneXForCloseLeftLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForCloseLeftLaneChange(j->x, j->mCloseLeftLaneChanges); - } - - qreal GraphLayouter::sceneXForFarLeftLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForFarLeftLaneChange(j->x, j->mFarLeftLaneChanges); - } - - qreal GraphLayouter::sceneXForCloseRightLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForCloseRightLaneChange(j->x, j->mCloseRightLaneChanges); - } - - qreal GraphLayouter::sceneXForFarRightLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneXForFarRightLaneChange(j->x, j->mFarRightLaneChanges); - } - - qreal GraphLayouter::sceneYForCloseTopLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForCloseTopLaneChange(j->y, j->mCloseTopLaneChanges); - } - - qreal GraphLayouter::sceneYForFarTopLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForFarTopLaneChange(j->y, j->mFarTopLaneChanges); - } - - qreal GraphLayouter::sceneYForCloseBottomLaneChange(const Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForCloseBottomLaneChange(j->y, j->mCloseBottomLaneChanges); - } - - qreal GraphLayouter::sceneYForFarBottomLaneChange(const GraphLayouter::Junction* const j) const - { - // CONVENIENCE METHOD - assert(j); - - return sceneYForFarBottomLaneChange(j->y, j->mFarBottomLaneChanges); - } - void GraphLayouter::commitUsedPaths(const UsedPaths& used) { - for (Road* r : used.mHRoads) - r->mLanes += 1; - - for (Road* r : used.mVRoads) - r->mLanes += 1; - for (Junction* j : used.mHJunctions) j->mHLanes += 1; @@ -2887,14 +1328,14 @@ namespace hal return false; } - bool GraphLayouter::optimizeNetLayoutEnabled() + bool GraphLayouter::dumpJunctionEnabled() { - return mOptimizeNetLayout; + return mDumpJunctions; } - void GraphLayouter::setOptimizeNetLayoutEnabled(bool enabled) + void GraphLayouter::setDumpJunctionEnabled(bool enabled) { - mOptimizeNetLayout = enabled; + mDumpJunctions = enabled; } void JunctionThread::run() diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index ae9d6fe3942..1fd6dbd5429 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "hal_core/netlist/project_manager.h" #ifdef JUNCTION_DEBUG QMap debugColorMap; @@ -902,6 +903,20 @@ namespace hal { return mRange.isEntry(0) || mRange.isEntry(1); } + void NetLayoutJunctionEntries::dumpToFile(const QPoint &pnt) const + { + QFile ff(QString::fromStdString(ProjectManager::instance()->get_project_directory().get_filename("junction_data.txt").string())); + if (!ff.open(QIODevice::WriteOnly | QIODevice::Append)) return; + QTextStream xout(&ff); + xout << "(" << pnt.x() << "," << pnt.y() << ")\n"; + for (NetLayoutDirection dir(0); !dir.isMax(); ++dir) + { + for (u32 id : mEntries[dir.index()]) + xout << " " << id; + xout << "\n"; + } + xout.flush(); + } QString NetLayoutJunctionEntries::toString() const { From 8bb81dec587b8a0694a62717942e9f06c5e93cd4 Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 30 Oct 2023 14:20:09 +0100 Subject: [PATCH 09/22] Bugfix and removal of dead routines --- .../graph_widget/layouters/graph_layouter.h | 43 --------------- .../graph_widget/layouters/net_layout_point.h | 2 +- .../graph_widget/layouters/graph_layouter.cpp | 53 +------------------ .../layouters/net_layout_point.cpp | 7 ++- 4 files changed, 9 insertions(+), 96 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index 096cb1ec4e5..c00f33c6065 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -208,48 +208,10 @@ namespace hal unsigned int mLanes = 0; }; - struct Junction - { - Junction(const int x_coordinate, const int y_coordinate) - : x(x_coordinate), y(y_coordinate), mHLanes(0), mVLanes(0), mCloseLeftLaneChanges(0), mCloseRightLaneChanges(0), mCloseTopLaneChanges(0), mCloseBottomLaneChanges(0), - mFarLeftLaneChanges(0), mFarRightLaneChanges(0), mFarTopLaneChanges(0), mFarBottomLaneChanges(0) - { - } - - int x; - int y; - - unsigned int mHLanes = 0; - unsigned int mVLanes = 0; - - unsigned int mCloseLeftLaneChanges = 0; - unsigned int mCloseRightLaneChanges = 0; - unsigned int mCloseTopLaneChanges = 0; - unsigned int mCloseBottomLaneChanges = 0; - - unsigned int mFarLeftLaneChanges = 0; - unsigned int mFarRightLaneChanges = 0; - unsigned int mFarTopLaneChanges = 0; - unsigned int mFarBottomLaneChanges = 0; - }; - struct UsedPaths { QSet mHRoads; QSet mVRoads; - - QSet mHJunctions; - QSet mVJunctions; - - QSet mCloseLeftJunctions; - QSet mCloseRightJunctions; - QSet mCloseTopJunctions; - QSet mCloseBottomJunctions; - - QSet mFarLeftJunctions; - QSet mFarRightJunctions; - QSet mFarTopJunctions; - QSet mFarBottomJunctions; }; public: @@ -375,18 +337,13 @@ namespace hal bool vRoadJumpPossible(const int x1, const int x2, const int y) const; bool vRoadJumpPossible(const Road* const r1, const Road* const r2) const; - Junction* getJunction(const int x, const int y); - qreal hRoadHeight(const unsigned int mLanes) const; qreal vRoadWidth(const unsigned int mLanes) const; - void commitUsedPaths(const UsedPaths& used); static bool isConstNet(const Net* n); NodeBoxes mBoxes; - QHash mJunctions; - QMap mMaxNodeWidthForX; QMap mMaxNodeHeightForY; diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h index 1bb753d6dc7..1bb0eaaa8dd 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_point.h @@ -102,6 +102,7 @@ namespace hal { bool isEndpoint() const { return mIsEndpoint; } bool isHorizontal() const { return mDir.isHorizontal(); } bool operator==(const NetLayoutWire& other) const; + QString toString() const; private: NetLayoutPoint mPoint; NetLayoutDirection mDir; @@ -151,7 +152,6 @@ namespace hal { public: NetLayoutConnectionFactory(const QList& sources, const QList& destinations); QList points() const { return mPoints; } - QList mJunctions; NetLayoutConnection* connection; void dump(const QString& stub) const; private: diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index d5823310c7d..7e63beb8fb9 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -297,10 +297,6 @@ namespace hal mBoxes.clearBoxes(); clearComments(); - for (const GraphLayouter::Junction* j : mJunctions.values()) - delete j; - mJunctions.clear(); - mMaxNodeWidthForX.clear(); mMaxNodeHeightForY.clear(); @@ -337,6 +333,8 @@ namespace hal mNodeBoundingBox = QRect(); mViewInput.clear(); mViewOutput.clear(); + + mLaneMap.clear(); } void GraphLayouter::createBoxes() @@ -1095,20 +1093,6 @@ namespace hal return vRoadJumpPossible(r1->x, r2->x, r1->y); } - GraphLayouter::Junction* GraphLayouter::getJunction(const int x, const int y) - { - QPoint p(x, y); - auto it = mJunctions.find(p); - if (it != mJunctions.end()) - { - return it.value(); - } - - GraphLayouter::Junction* j = new Junction(x, y); - mJunctions.insert(p, j); - return j; - } - qreal GraphLayouter::hRoadHeight(const unsigned int mLanes) const { // LANES COUNTED FROM 1 @@ -1131,39 +1115,6 @@ namespace hal return width; } - void GraphLayouter::commitUsedPaths(const UsedPaths& used) - { - for (Junction* j : used.mHJunctions) - j->mHLanes += 1; - - for (Junction* j : used.mVJunctions) - j->mVLanes += 1; - - for (Junction* j : used.mCloseLeftJunctions) - j->mCloseLeftLaneChanges += 1; - - for (Junction* j : used.mCloseRightJunctions) - j->mCloseRightLaneChanges += 1; - - for (Junction* j : used.mCloseTopJunctions) - j->mCloseTopLaneChanges += 1; - - for (Junction* j : used.mCloseBottomJunctions) - j->mCloseBottomLaneChanges += 1; - - for (Junction* j : used.mFarLeftJunctions) - j->mFarLeftLaneChanges += 1; - - for (Junction* j : used.mFarRightJunctions) - j->mFarRightLaneChanges += 1; - - for (Junction* j : used.mFarTopJunctions) - j->mFarTopLaneChanges += 1; - - for (Junction* j : used.mFarBottomJunctions) - j->mFarBottomLaneChanges += 1; - } - void GraphLayouter::SceneCoordinate::testMinMax(int ilane) { if (ilane < minLane) diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp index 00335a13e16..4d4e0478699 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_point.cpp @@ -203,6 +203,12 @@ bool NetLayoutWire::operator==(const NetLayoutWire& other) const mIsEndpoint==other.mIsEndpoint); } +QString NetLayoutWire::toString() const +{ + static const char* cdir = "LRUD"; + return QString("<%1,%2>-%3-%4").arg(mPoint.x()).arg(mPoint.y()).arg(cdir[mDir.index()]).arg(mIsEndpoint?'X':'-'); +} + QGraphicsLineItem* NetLayoutWire::graphicsFactory() const { if (mDir.isNull()) return nullptr; @@ -405,7 +411,6 @@ NetLayoutConnectionFactory::NetLayoutConnectionFactory(const QList Date: Wed, 1 Nov 2023 10:08:51 +0100 Subject: [PATCH 10/22] fixed Python documentation --- src/python_bindings/bindings/module.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/python_bindings/bindings/module.cpp b/src/python_bindings/bindings/module.cpp index 59f93e59df7..730166d4c0d 100644 --- a/src/python_bindings/bindings/module.cpp +++ b/src/python_bindings/bindings/module.cpp @@ -263,20 +263,20 @@ namespace hal )"); py_module.def_property_readonly("input_nets", &Module::get_input_nets, R"( - A list of all nets that are either a global input to the netlist or have at least one source outside of the module. + A set of all nets that are either a global input to the netlist or have at least one source outside of the module. - :type: list[hal_py.Net] + :type: set[hal_py.Net] )"); py_module.def("get_input_nets", &Module::get_input_nets, R"( Get all nets that are either a global input to the netlist or have at least one source outside of the module. - :returns: A list of input nets. - :rtype: list[hal_py.Net] + :returns: A set of input nets. + :rtype: set[hal_py.Net] )"); py_module.def_property_readonly("output_nets", &Module::get_output_nets, R"( - A list of all nets that are either a global output to the netlist or have at least one destination outside of the module. + A set of all nets that are either a global output to the netlist or have at least one destination outside of the module. :type: set[hal_py.Net] )"); @@ -284,21 +284,21 @@ namespace hal py_module.def("get_output_nets", &Module::get_output_nets, R"( Get all nets that are either a global output to the netlist or have at least one destination outside of the module. - :returns: A list of output nets. - :rtype: list[hal_py.Net] + :returns: A set of output nets. + :rtype: set[hal_py.Net] )"); py_module.def_property_readonly("internal_nets", &Module::get_internal_nets, R"( - A list of all nets that have at least one source and one destination within the module, including its submodules. The result may contain nets that are also regarded as input or output nets. + A set of all nets that have at least one source and one destination within the module, including its submodules. The result may contain nets that are also regarded as input or output nets. - :type: list[hal_py.Net] + :type: set[hal_py.Net] )"); py_module.def("get_internal_nets", &Module::get_internal_nets, R"( Get all nets that have at least one source and one destination within the module, including its submodules. The result may contain nets that are also regarded as input or output nets. - :returns: A list of internal nets. - :rtype: list[hal_py.Net] + :returns: A set of internal nets. + :rtype: set[hal_py.Net] )"); py_module.def("is_input_net", &Module::is_input_net, py::arg("net"), R"( From 154587dac94e49916883ac94bbe9bb13827bb736 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 2 Nov 2023 07:10:04 +0100 Subject: [PATCH 11/22] Removing unsupported 'pip3 install' from setup script --- install_dependencies.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/install_dependencies.sh b/install_dependencies.sh index efe6c41636e..510bc6e961e 100755 --- a/install_dependencies.sh +++ b/install_dependencies.sh @@ -76,10 +76,9 @@ elif [[ "$platform" == 'linux' ]]; then libqt5svg5-dev libqt5svg5* ninja-build lcov gcovr python3-sphinx \ doxygen python3-sphinx-rtd-theme python3-jedi python3-pip \ pybind11-dev python3-pybind11 rapidjson-dev libspdlog-dev libz3-dev z3 \ - libreadline-dev apport \ + libreadline-dev apport python3-dateutil \ $additional_deps \ graphviz libomp-dev libsuitesparse-dev # For documentation - sudo pip3 install -r requirements.txt elif [[ "$distribution" == "Arch" ]]; then yay -S --needed base-devel lsb-release git verilator cmake boost-libs pkgconf \ qt5-base python ccache autoconf libsodium qt5-svg ninja lcov \ @@ -97,7 +96,7 @@ elif [[ "$platform" == 'docker' ]]; then libpython3-dev ccache autoconf autotools-dev libsodium-dev \ libqt5svg5-dev libqt5svg5* ninja-build lcov gcovr python3-sphinx \ doxygen python3-sphinx-rtd-theme python3-jedi python3-pip \ - pybind11-dev python3-pybind11 rapidjson-dev libspdlog-dev libz3-dev libreadline-dev \ + pybind11-dev python3-pybind11 python3-dateutil rapidjson-dev \ + libspdlog-dev libz3-dev libreadline-dev \ graphviz libomp-dev libsuitesparse-dev # For documentation - pip3 install -r requirements.txt fi From 7a30175642a166d3780ef77e6820dbdcc4f05f13 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 2 Nov 2023 11:23:47 +0100 Subject: [PATCH 12/22] ScrollbarAsNeeded option set for data tab --- plugins/gui/src/selection_details_widget/data_table_widget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/gui/src/selection_details_widget/data_table_widget.cpp b/plugins/gui/src/selection_details_widget/data_table_widget.cpp index d51eb4f7ef2..6844b0373dc 100644 --- a/plugins/gui/src/selection_details_widget/data_table_widget.cpp +++ b/plugins/gui/src/selection_details_widget/data_table_widget.cpp @@ -23,6 +23,7 @@ namespace hal this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); this->verticalHeader()->setVisible(false); this->horizontalHeader()->setVisible(true); + this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setFrameStyle(QFrame::NoFrame); connect(this, &QTableView::customContextMenuRequested, this, &DataTableWidget::handleContextMenuRequest); @@ -120,6 +121,7 @@ namespace hal this->setWordWrap(true); this->resizeRowsToContents(); + /* // Configure the widget height int h = horizontalHeader()->height(); for (int i = 0; i < mDataTableModel->rowCount(); i++) @@ -127,6 +129,7 @@ namespace hal setMaximumHeight(h); setMinimumHeight(h); + */ } void DataTableWidget::changePropertyRequested(DataTableModel::propertyType prop) From 81908412992a329851e02141541e929efad30ed2 Mon Sep 17 00:00:00 2001 From: SJulianS Date: Thu, 2 Nov 2023 16:14:33 +0100 Subject: [PATCH 13/22] default destructor missing --- .../include/gui/graph_widget/layouters/net_layout_junction.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index b8cd7df6da5..ec396c1bec0 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -436,8 +436,8 @@ namespace hal { class NetLayoutJunctionHash : public QHash { public: - NetLayoutJunctionHash() {;} - ~NetLayoutJunctionHash(); + NetLayoutJunctionHash() = default; + ~NetLayoutJunctionHash() = default; void clearAll(); }; From cff610b51cb3bfec949cce315347f6488af2ce55 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 2 Nov 2023 22:01:33 +0100 Subject: [PATCH 14/22] Bugfix for junction range merging --- .../layouters/net_layout_junction.h | 23 ++++++++++++-- .../layouters/net_layout_junction.cpp | 31 +++++++++++-------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h index ec396c1bec0..4cb5d01d650 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h +++ b/plugins/gui/include/gui/graph_widget/layouters/net_layout_junction.h @@ -364,15 +364,32 @@ namespace hal { class NetLayoutJunctionOccupiedHash : public QHash { public: - enum AddType { None, Added, Merged }; + /** + * Result class for addOrMerge() function + * If range was merged, old and new range will be returned + * otherwise these values are not set (nullptr) + */ + class AddOrMerge + { + public: + enum Type { Added, Merged, AlreadyExisting } mType; + NetLayoutJunctionRange* mOldRange; + NetLayoutJunctionRange* mNewRange; + AddOrMerge() : mType(Added), mOldRange(nullptr), mNewRange(nullptr) {;} + ~AddOrMerge() + { + if (mOldRange) delete mOldRange; + if (mNewRange) delete mNewRange; + } + }; /** * Adds new entry for range or merges it * @param ri Road index where to add - * @param rng Range to add, will be modified on merge + * @param rng Range to add * @return see AddType above. */ - AddType addOrMerge(const LaneIndex &ri, NetLayoutJunctionRange& rng); + AddOrMerge addOrMerge(const LaneIndex &ri, const NetLayoutJunctionRange& rng); #ifdef JUNCTION_DEBUG QList> mHistory; diff --git a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp index 1fd6dbd5429..d48f9815cf9 100644 --- a/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp +++ b/plugins/gui/src/graph_widget/layouters/net_layout_junction.cpp @@ -540,20 +540,24 @@ namespace hal { void NetLayoutJunction::place(const LaneIndex &ri, const NetLayoutJunctionRange &range) { - NetLayoutJunctionRange rng = range; - NetLayoutJunctionOccupiedHash::AddType added = mOccupied.addOrMerge(ri,rng); // might modify + NetLayoutJunctionOccupiedHash::AddOrMerge aom = mOccupied.addOrMerge(ri,range); auto netIt = mNets.find(range.netId()); Q_ASSERT(netIt!=mNets.end()); - NetLayoutJunctionWire nljw(rng,ri); - switch (added ) + switch (aom.mType ) { - case NetLayoutJunctionOccupiedHash::Added: + case NetLayoutJunctionOccupiedHash::AddOrMerge::Added: + { + NetLayoutJunctionWire nljw(range,ri); netIt->addWire(nljw); break; - case NetLayoutJunctionOccupiedHash::Merged: - netIt->replaceWire(range,nljw); + } + case NetLayoutJunctionOccupiedHash::AddOrMerge::Merged: + { + NetLayoutJunctionWire nljw(*aom.mNewRange,ri); + netIt->replaceWire(*aom.mOldRange,nljw); break; + } default: break; } @@ -659,30 +663,31 @@ namespace hal { } } - NetLayoutJunctionOccupiedHash::AddType NetLayoutJunctionOccupiedHash::addOrMerge(const LaneIndex& ri, NetLayoutJunctionRange& rng) + NetLayoutJunctionOccupiedHash::AddOrMerge NetLayoutJunctionOccupiedHash::addOrMerge(const LaneIndex& ri, const NetLayoutJunctionRange &rng) { // operator will create entry if not existing NetLayoutJunctionOccupied& nljo = this->operator[](ri); - AddType retval = Added; + AddOrMerge retval; for (auto it = nljo.begin(); it!= nljo.end(); ++it) { if (*it == rng) { - retval = None; + retval.mType = AddOrMerge::AlreadyExisting; break; } if (it->canJoin(rng)) { + retval.mOldRange = new NetLayoutJunctionRange(*it); it->expand(rng); - rng = (*it); - retval = Merged; + retval.mNewRange = new NetLayoutJunctionRange(*it); + retval.mType = AddOrMerge::Merged; break; } } - if (retval == Added) + if (retval.mType == AddOrMerge::Added) nljo.append(rng); #ifdef JUNCTION_DEBUG From c506a1e35fa363f7d298c43438f12ea73388b307 Mon Sep 17 00:00:00 2001 From: "julian.speith" Date: Tue, 7 Nov 2023 15:46:58 +0100 Subject: [PATCH 15/22] changelog update --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435e774d4fe..177cd7429f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased] * miscellaneous - * added GUI PluginParameter type 'ComboBox' for parameters that can be requested from plugin - * added GUI PluginParameter types 'Module' and 'Gated' for parameters that can be requested from plugin + * added GUI PluginParameter type `ComboBox` for parameters that can be requested from plugin + * added GUI PluginParameter types `Module` and `Gated` for parameters that can be requested from plugin * added `Show content` button to `Groupings` widget to show content of grouping as a list * added flag which python editor tab is active when serializing project * added `GateType::delete_pin_group` and `GateType::assign_pin_to_group` to enable more operations on pin groups of gate pins * added extended gate library picker when importing a netlist + * added parameter `force_name` to enforce pin (group) renaming to `Module::set_pin_name`, `Module::set_pin_group_name`, `Module::create_pin`, and `Module::create_pin_group` * changed supported input file formats for import from hard coded list to list provided by loadable parser plugins * changed behavior of import netlist dialog, suggest only non-existing directory names and loop until an acceptable name was entered * changed appearance and behavior of import project dialog, make sure existing hal projects don't get overwritten @@ -22,6 +23,8 @@ All notable changes to this project will be documented in this file. * fixed order of pins within pin groups not being properly handled for modules and gate types * fixed netlist parsers assigning gate pins in wrong order (compensated by the bug above, imported netlists were still correct) * fixed wrong order of pins within pin groups in provided gate libraries + * fixed format string handling of enums in log outputs + * fixed no scrollbar shown in `Data` tab of `Selection Details` widget ## [4.2.0](v4.2.0) - 2023-05-24 10:02:04-07:00 (urgency: medium) * GUI plugin manager From 898bc7e765d9b0525f0cef8322524e123a527b6e Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 9 Nov 2023 12:50:58 +0100 Subject: [PATCH 16/22] Bugfix: class StandardArrowNet adapted for new layout algorithm --- .../graph_widget/items/nets/standard_arrow_net.h | 2 +- .../graph_widget/items/nets/standard_arrow_net.cpp | 4 ++-- .../src/graph_widget/layouters/graph_layouter.cpp | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h index 3ce91f2e26d..dcd374af447 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h @@ -47,7 +47,7 @@ namespace hal { * @param n - The underlying net * @param l - The lines this GraphicsNet consists of */ - StandardArrowNet(Net* n, const Lines& l); + StandardArrowNet(Net* n, const Lines& l, const QList& knots = QList()); /** * Adds an input position. * diff --git a/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp index f7f91750de8..25251225ba8 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_arrow_net.cpp @@ -2,8 +2,8 @@ namespace hal { - StandardArrowNet::StandardArrowNet(Net* n, const Lines &l) - : StandardGraphicsNet(n,l), mArrowNet(n) + StandardArrowNet::StandardArrowNet(Net* n, const Lines &l, const QList& knots) + : StandardGraphicsNet(n,l,knots), mArrowNet(n) {;} void StandardArrowNet::setInputPosition(const QPointF& pos) diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 7e63beb8fb9..4c25cbf2915 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -934,17 +934,17 @@ namespace hal case EndpointList::HasGlobalEndpoint: if (epl.hasInputArrow()) { - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); graphicsNet = san; int yGridPos = mGlobalInputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); - san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(-1), epc.lanePosition(0, true))); + san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(0), epc.lanePosition(0, true))); } if (epl.hasOutputArrow()) { if (graphicsNet) mScene->addGraphItem(graphicsNet); - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); graphicsNet = san; int yGridPos = mGlobalOutputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); @@ -952,7 +952,7 @@ namespace hal const EndpointCoordinate& epc = mEndpointHash.value(pnt); const NetLayoutJunction* nlj = mJunctionHash.value(pnt); Q_ASSERT(nlj); - san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right() + 1), epc.lanePosition(0, true))); + san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right()), epc.lanePosition(0, true))); } break; case EndpointList::SourceAndDestination: @@ -1400,9 +1400,9 @@ namespace hal for (const QPoint& pnt : jt.value()->netById(mId).mKnots) { - float x = scX.lanePosition(pnt.x()); - float y = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : scY.lanePosition(pnt.y()); - mKnots.append(QPointF(x,y)); + float xp = scX.lanePosition(pnt.x()); + float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : scY.lanePosition(pnt.y()); + mKnots.append(QPointF(xp,yp)); } } } From 46257bef88e9e9d0e98922fb46de73d4a18d9960 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 9 Nov 2023 15:20:07 +0100 Subject: [PATCH 17/22] Using array instead of map for scene coordinate lookup --- .../items/nets/standard_graphics_net.h | 5 - .../graph_widget/layouters/graph_layouter.h | 13 +++ .../items/nets/standard_graphics_net.cpp | 94 ------------------- .../graph_widget/layouters/graph_layouter.cpp | 84 +++++++++++------ 4 files changed, 67 insertions(+), 129 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h index 1a392a912ef..1204abaa21a 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_graphics_net.h @@ -93,11 +93,6 @@ namespace hal */ void appendVLine(const qreal x, const qreal mSmallY, const qreal mBigY); - /** - * Merges all horizontal and vertical lines so that overlapping lines are replaced by only a single line. - */ - void mergeLines(QGraphicsScene* sc); - /** * Gets the total amount of lines (includes horizontal AND vertical lines). * diff --git a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h index c00f33c6065..9324227d717 100644 --- a/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h +++ b/plugins/gui/include/gui/graph_widget/layouters/graph_layouter.h @@ -120,6 +120,16 @@ namespace hal float xBoxOffset() const; }; + class SceneCoordinateArray + { + float* mArray; + int mFirstIndex; + public: + SceneCoordinateArray(const QMap& inputMap); + ~SceneCoordinateArray(); + float lanePosition(int igrid, int ilane) const; + }; + class EndpointCoordinate { float mYoffset; @@ -393,6 +403,9 @@ namespace hal QList mDrawNetThreads; QList mJunctionThreads; QHash> mLaneMap; + + SceneCoordinateArray* mCoordArrayX; + SceneCoordinateArray* mCoordArrayY; }; class DrawNetThread : public QThread diff --git a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp index 95d6b57c3cf..11da9520887 100644 --- a/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp +++ b/plugins/gui/src/graph_widget/items/nets/standard_graphics_net.cpp @@ -191,98 +191,4 @@ namespace hal mVLines.append(VLine{x, mSmallY, mBigY}); } - - void StandardGraphicsNet::Lines::mergeLines(QGraphicsScene *sc) - { - qDebug() << "optimal number threads" << QThread::idealThreadCount(); - QVector merged_h_lines; - QVector merged_v_lines; - - for (const HLine& h : mHLines) - { - QVector overlaps; - - for (int i = 0; i < merged_h_lines.size(); ++i) - if (h.y == merged_h_lines.at(i).y) - { - if (h.mBigX < merged_h_lines.at(i).mSmallX || merged_h_lines.at(i).mBigX < h.mSmallX) - continue; - - qreal x0 = merged_h_lines.at(i).mSmallX > h.mSmallX ? merged_h_lines.at(i).mSmallX : h.mSmallX; - qreal x1 = merged_h_lines.at(i).mBigX < h.mBigX ? merged_h_lines.at(i).mBigX : h.mBigX; - - qDebug() << "h-ov" << h.y << x0 << x1; - sc->addLine(x0,h.y,x1,h.y,QPen(Qt::yellow)); - overlaps.append(i); - } - - if (overlaps.isEmpty()) - merged_h_lines.append(h); - else - { - qreal smallest_x = h.mSmallX; - qreal biggest_x = h.mBigX; - - for (int i = 0; i < overlaps.size(); ++i) - { - int index = overlaps.at(i) - i; - - if (merged_h_lines.at(index).mSmallX < smallest_x) - smallest_x = merged_h_lines.at(index).mSmallX; - - if (merged_h_lines.at(index).mBigX > biggest_x) - biggest_x = merged_h_lines.at(index).mBigX; - - merged_h_lines.remove(index); - } - - merged_h_lines.append(HLine{smallest_x, biggest_x, h.y}); - } - } - - for (const VLine& v : mVLines) - { - QVector overlaps; - - for (int i = 0; i < merged_v_lines.size(); ++i) - if (v.x == merged_v_lines.at(i).x) - { - if (v.mBigY < merged_v_lines.at(i).mSmallY || merged_v_lines.at(i).mBigY < v.mSmallY) - continue; - - qreal y0 = merged_v_lines.at(i).mSmallY > v.mSmallY ? merged_v_lines.at(i).mSmallY : v.mSmallY; - qreal y1 = merged_v_lines.at(i).mBigY < v.mBigY ? merged_v_lines.at(i).mBigY : v.mBigY; - - qDebug() << "v-ov" << v.x << y0 << y1; - sc->addLine(v.x,y0,v.x,y1,QPen(Qt::red)); - overlaps.append(i); - } - - if (overlaps.isEmpty()) - merged_v_lines.append(v); - else - { - qreal smallest_y = v.mSmallY; - qreal biggest_y = v.mBigY; - - for (int i = 0; i < overlaps.size(); ++i) - { - int index = overlaps.at(i) - i; - - if (merged_v_lines.at(index).mSmallY < smallest_y) - smallest_y = merged_v_lines.at(index).mSmallY; - - if (merged_v_lines.at(index).mBigY > biggest_y) - biggest_y = merged_v_lines.at(index).mBigY; - - merged_v_lines.remove(index); - } - - merged_v_lines.append(VLine{v.x, smallest_y, biggest_y}); - } - } - - mHLines = merged_h_lines; - mVLines = merged_v_lines; - } } // namespace hal diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 4c25cbf2915..15e3c70f9f6 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -233,9 +233,12 @@ namespace hal mParentContext->layoutProgress(5); calculateGateOffsets(); mParentContext->layoutProgress(6); + + mCoordArrayX = new SceneCoordinateArray(mCoordX); + mCoordArrayY = new SceneCoordinateArray(mCoordY); + placeGates(); mParentContext->layoutProgress(7); - mDone = true; drawNets(); drawComments(); updateSceneRect(); @@ -250,9 +253,8 @@ namespace hal qDebug() << "elapsed time (experimental new) layout [ms]" << timer.elapsed(); - - return; - + delete mCoordArrayX; + delete mCoordArrayY; mDone = true; } @@ -934,17 +936,17 @@ namespace hal case EndpointList::HasGlobalEndpoint: if (epl.hasInputArrow()) { - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); graphicsNet = san; int yGridPos = mGlobalInputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); - san->setInputPosition(QPointF(mCoordX.value(mNodeBoundingBox.left()).lanePosition(0), epc.lanePosition(0, true))); + san->setInputPosition(QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.left(),-1), epc.lanePosition(0, true))); } if (epl.hasOutputArrow()) { if (graphicsNet) mScene->addGraphItem(graphicsNet); - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); graphicsNet = san; int yGridPos = mGlobalOutputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); @@ -952,7 +954,7 @@ namespace hal const EndpointCoordinate& epc = mEndpointHash.value(pnt); const NetLayoutJunction* nlj = mJunctionHash.value(pnt); Q_ASSERT(nlj); - san->setOutputPosition(QPointF(mCoordX.value(pnt.x()).lanePosition(nlj->rect().right()), epc.lanePosition(0, true))); + san->setOutputPosition(QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj->rect().right() + 1), epc.lanePosition(0, true))); } break; case EndpointList::SourceAndDestination: @@ -1160,6 +1162,31 @@ namespace hal return junctionExit() + sHRoadPadding + mPadding; } + GraphLayouter::SceneCoordinateArray::SceneCoordinateArray(const QMap& inputMap) + : mArray(nullptr), mFirstIndex(0) + { + if (!inputMap.isEmpty()) + { + mArray = new float[inputMap.size()]; + auto it = inputMap.constBegin(); + mFirstIndex = it.key(); + for (int i = 0; it != inputMap.constEnd(); ++it) + { + mArray[i++] = it.value().lanePosition(0); + } + } + } + + GraphLayouter::SceneCoordinateArray::~SceneCoordinateArray() + { + if (mArray) delete [] mArray; + } + + float GraphLayouter::SceneCoordinateArray::lanePosition(int igrid, int ilane) const + { + return mArray[igrid-mFirstIndex] + ilane * sLaneSpacing; + } + float GraphLayouter::EndpointCoordinate::lanePosition(int ilane, bool absolute) const { float y0 = absolute ? mYoffset : mTopPin; @@ -1315,20 +1342,20 @@ namespace hal if (it.key().isHorizontal()) { - float x0 = j0 ? mLayouter->mCoordX[ix0].lanePosition(j0->rect().right()) : mLayouter->mCoordX[ix0].junctionExit(); - float x1 = j1 ? mLayouter->mCoordX[ix1].lanePosition(j1->rect().left()) : mLayouter->mCoordX[ix1].junctionEntry(); - float yy = mLayouter->mCoordY[iy0].lanePosition(ilane); + float x0 = j0 ? mLayouter->mCoordArrayX->lanePosition(ix0,j0->rect().right()) : mLayouter->mCoordX[ix0].junctionExit(); + float x1 = j1 ? mLayouter->mCoordArrayX->lanePosition(ix1,j1->rect().left()) : mLayouter->mCoordX[ix1].junctionEntry(); + float yy = mLayouter->mCoordArrayY->lanePosition(iy0,ilane); mLines.appendHLine(x0, x1, yy); } else { float y0, y1; - float xx = mLayouter->mCoordX[ix0].lanePosition(ilane); + float xx = mLayouter->mCoordArrayX->lanePosition(ix0,ilane); if (wToPoint.isEndpoint()) { // netjunction -> endpoint auto itEpc = mLayouter->mEndpointHash.find(wToPoint); - y0 = j0 ? mLayouter->mCoordY[iy0].lanePosition(j0->rect().bottom()) : mLayouter->mCoordY[iy0].junctionExit(); + y0 = j0 ? mLayouter->mCoordArrayY->lanePosition(iy0,j0->rect().bottom()) : mLayouter->mCoordY[iy0].junctionExit(); y1 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j1->rect().top(), true) : mLayouter->mCoordY[iy1].junctionEntry(); // if (itEpc==mEndpointHash.constEnd()) // qDebug() << "xxx to endp" << wToPoint.x() << wToPoint.y() << y0 << y1; @@ -1338,7 +1365,7 @@ namespace hal // endpoint -> netjunction auto itEpc = mLayouter->mEndpointHash.find(wFromPoint); y0 = itEpc != mLayouter->mEndpointHash.constEnd() ? itEpc.value().lanePosition(j0->rect().bottom(), true) : mLayouter->mCoordY[iy0].junctionExit(); - y1 = j1 ? mLayouter->mCoordY[iy1].lanePosition(j1->rect().top()) : mLayouter->mCoordY[iy1].junctionEntry(); + y1 = j1 ? mLayouter->mCoordArrayY->lanePosition(iy1,j1->rect().top()) : mLayouter->mCoordY[iy1].junctionEntry(); // if (itEpc==mEndpointHash.constEnd()) // qDebug() << "xxx fr endp" << wFromPoint.x() << wFromPoint.y() << y0 << y1; } @@ -1359,18 +1386,15 @@ namespace hal int y = jt.key().y(); bool isEndpoint = (y % 2 == 0); - const GraphLayouter::SceneCoordinate& scX = mLayouter->mCoordX.value(x); - const GraphLayouter::SceneCoordinate& scY = mLayouter->mCoordY.value(y); - for (const NetLayoutJunctionWire& jw : jt.value()->netById(mId).mWires) { int li = jw.mIndex.laneIndex(); if (jw.mIndex.isHorizontal()) { Q_ASSERT(epcIt != mLayouter->mEndpointHash.constEnd() || !isEndpoint); - float x0 = scX.lanePosition(jw.mRange.first()); - float x1 = scX.lanePosition(jw.mRange.last()); - float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : scY.lanePosition(li); + float x0 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.first()); + float x1 = mLayouter->mCoordArrayX->lanePosition(x,jw.mRange.last()); + float yy = isEndpoint ? epcIt.value().lanePosition(li, true) : mLayouter->mCoordArrayY->lanePosition(y,li); mLines.appendHLine(x0, x1, yy); } else @@ -1378,8 +1402,8 @@ namespace hal float y0, y1; if (!isEndpoint) { - y0 = scY.lanePosition(jw.mRange.first()); - y1 = scY.lanePosition(jw.mRange.last()); + y0 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.first()); + y1 = mLayouter->mCoordArrayY->lanePosition(y,jw.mRange.last()); } else if (epcIt != mLayouter->mEndpointHash.constEnd()) { @@ -1388,20 +1412,20 @@ namespace hal } else { - y0 = scY.junctionEntry(); - y1 = scY.junctionExit(); + y0 = mLayouter->mCoordY.value(y).junctionEntry(); + y1 = mLayouter->mCoordY.value(y).junctionExit(); if (y1 <= y0) y1 = y0 + 1; } - float xx = scX.lanePosition(li); + float xx = mLayouter->mCoordArrayX->lanePosition(x,li); mLines.appendVLine(xx, y0, y1); } } for (const QPoint& pnt : jt.value()->netById(mId).mKnots) { - float xp = scX.lanePosition(pnt.x()); - float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : scY.lanePosition(pnt.y()); + float xp = mLayouter->mCoordArrayX->lanePosition(x,pnt.x()); + float yp = isEndpoint ? epcIt.value().lanePosition(pnt.y(), true) : mLayouter->mCoordArrayY->lanePosition(y,pnt.y()); mKnots.append(QPointF(xp,yp)); } } @@ -1419,9 +1443,9 @@ namespace hal continue; const NetLayoutJunction* nlj = mLayouter->mJunctionHash.value(it.key()); - const GraphLayouter::SceneCoordinate& xScenePos = mLayouter->mCoordX.value(it.key().x()); - float xjLeft = xScenePos.lanePosition(nlj->rect().left()); - float xjRight = xScenePos.lanePosition(nlj->rect().right()); + int ix = it.key().x(); + float xjLeft = mLayouter->mCoordArrayX->lanePosition(ix,nlj->rect().left()); + float xjRight = mLayouter->mCoordArrayX->lanePosition(ix,nlj->rect().right()); Q_ASSERT(nlj); for (int inpInx : inputsById) From 17367313e754d9b23d807e2ad30fb80392aa8088 Mon Sep 17 00:00:00 2001 From: joern274 Date: Thu, 9 Nov 2023 21:01:22 +0100 Subject: [PATCH 18/22] changelog update --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 177cd7429f6..573dce28391 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,14 +9,17 @@ All notable changes to this project will be documented in this file. * added flag which python editor tab is active when serializing project * added `GateType::delete_pin_group` and `GateType::assign_pin_to_group` to enable more operations on pin groups of gate pins * added extended gate library picker when importing a netlist + * added keyboard shortcut for delete-item action from toolbar * added parameter `force_name` to enforce pin (group) renaming to `Module::set_pin_name`, `Module::set_pin_group_name`, `Module::create_pin`, and `Module::create_pin_group` * changed supported input file formats for import from hard coded list to list provided by loadable parser plugins * changed behavior of import netlist dialog, suggest only non-existing directory names and loop until an acceptable name was entered * changed appearance and behavior of import project dialog, make sure existing hal projects don't get overwritten + * changed installation script policy to install Python packages (omit 'pip install' which would need virtual environment) * bugfixes * fixed colors in Python Console when switching between color schemes * fixed pybind of `Module::get_gates` * fixed Python script execution abort button disappearing when switching tabs + * fixed Python interpreter crash due to release of GIL semaphore before cleanup is done * fixed segfault when deleting a module for which an exclusive view exists * fixed not loading all plugins if the GUI is not in control * fixed Verilog writer not being a dependency of Verilator plugin @@ -24,7 +27,16 @@ All notable changes to this project will be documented in this file. * fixed netlist parsers assigning gate pins in wrong order (compensated by the bug above, imported netlists were still correct) * fixed wrong order of pins within pin groups in provided gate libraries * fixed format string handling of enums in log outputs + * fixed restoring user assigned module colors from project file * fixed no scrollbar shown in `Data` tab of `Selection Details` widget + * fixed problems in GUI plugin management caused by addressing plugins by absolute path + * fixed several bugs related to moving node boxes in GUI by drag'n'drop + +* refactored layouter module + * switched to multithreaded algorithm + * boosted performance by using classes with faster memory access + * removed layouter code used prior to version 3.1.0 - thus removing the setting option to use that code + * added setting option to dump junction layout input data for experts to debug in case of layout errors ## [4.2.0](v4.2.0) - 2023-05-24 10:02:04-07:00 (urgency: medium) * GUI plugin manager From d2c4aad6ae99422364a230e99c1b5e07876e89c1 Mon Sep 17 00:00:00 2001 From: SJulianS Date: Mon, 13 Nov 2023 13:59:04 +0100 Subject: [PATCH 19/22] WIP fast finite set implementation --- .../decorators/netlist_traversal_decorator.h | 20 ++-- include/hal_core/utilities/finite_set.h | 61 ++++++++++ .../netlist_traversal_decorator.cpp | 24 ++-- .../bindings/netlist_traversal_decorator.cpp | 4 +- src/utilities/finite_set.cpp | 108 ++++++++++++++++++ 5 files changed, 193 insertions(+), 24 deletions(-) create mode 100644 include/hal_core/utilities/finite_set.h create mode 100644 src/utilities/finite_set.cpp diff --git a/include/hal_core/netlist/decorators/netlist_traversal_decorator.h b/include/hal_core/netlist/decorators/netlist_traversal_decorator.h index 6fecd885208..8c037536276 100644 --- a/include/hal_core/netlist/decorators/netlist_traversal_decorator.h +++ b/include/hal_core/netlist/decorators/netlist_traversal_decorator.h @@ -87,11 +87,11 @@ namespace hal * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. * @returns The next gates fulfilling the target gate filter condition. */ - Result> get_next_gates_fancy(const Net* net, - bool successors, - const std::function& target_gate_filter, - const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) const; + Result> get_next_gates_fancy(const Net* net, + bool successors, + const std::function& target_gate_filter, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; /** * Starting from the given gate, traverse the netlist and return only the successor/predecessor gates for which the `target_gate_filter` evaluates to `true`. @@ -105,11 +105,11 @@ namespace hal * @param[in] entry_endpoint_filter - Filter condition that determines whether to stop traversal on a successor/predecessor endpoint. * @returns The next gates fulfilling the target gate filter condition. */ - Result> get_next_gates_fancy(const Gate* gate, - bool successors, - const std::function& target_gate_filter, - const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) const; + Result> get_next_gates_fancy(const Gate* gate, + bool successors, + const std::function& target_gate_filter, + const std::function& exit_endpoint_filter = nullptr, + const std::function& entry_endpoint_filter = nullptr) const; private: const Netlist& m_netlist; diff --git a/include/hal_core/utilities/finite_set.h b/include/hal_core/utilities/finite_set.h new file mode 100644 index 00000000000..043093d5047 --- /dev/null +++ b/include/hal_core/utilities/finite_set.h @@ -0,0 +1,61 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" + +#include +#include + +namespace hal +{ + template + struct FiniteSet + { + FiniteSet(const u32 size); + + bool operator==(const FiniteSet& rhs) const; + bool operator<(const FiniteSet& rhs) const; + FiniteSet operator&(const FiniteSet& rhs) const; // intersect + FiniteSet operator|(const FiniteSet& rhs) const; // union + FiniteSet operator-(const FiniteSet& rhs) const; // difference + FiniteSet operator^(const FiniteSet& rhs) const; // symmetric difference + + bool is_disjoint(const FiniteSet& rhs) const; + bool is_subset(const FiniteSet& rhs) const; + bool is_superset(const FiniteSet& rhs) const; + + bool insert(const u32 index); + bool erase(const u32 index); + bool contains(const u32 index); + + u32 m_size; + std::vector m_content; + + private: + void initialize(); + }; +} // namespace hal diff --git a/src/netlist/decorators/netlist_traversal_decorator.cpp b/src/netlist/decorators/netlist_traversal_decorator.cpp index da18988ed4c..250e4876252 100644 --- a/src/netlist/decorators/netlist_traversal_decorator.cpp +++ b/src/netlist/decorators/netlist_traversal_decorator.cpp @@ -138,11 +138,11 @@ namespace hal return OK(res); } - Result> NetlistTraversalDecorator::get_next_gates_fancy(const Net* net, - bool successors, - const std::function& target_gate_filter, - const std::function& exit_endpoint_filter, - const std::function& entry_endpoint_filter) const + Result> NetlistTraversalDecorator::get_next_gates_fancy(const Net* net, + bool successors, + const std::function& target_gate_filter, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const { if (net == nullptr) { @@ -157,7 +157,7 @@ namespace hal std::unordered_set visited; std::vector stack = {net}; std::vector previous; - std::unordered_set res; + std::set res; while (!stack.empty()) { const Net* current = stack.back(); @@ -217,11 +217,11 @@ namespace hal return OK(res); } - Result> NetlistTraversalDecorator::get_next_gates_fancy(const Gate* gate, - bool successors, - const std::function& target_gate_filter, - const std::function& exit_endpoint_filter, - const std::function& entry_endpoint_filter) const + Result> NetlistTraversalDecorator::get_next_gates_fancy(const Gate* gate, + bool successors, + const std::function& target_gate_filter, + const std::function& exit_endpoint_filter, + const std::function& entry_endpoint_filter) const { if (gate == nullptr) { @@ -233,7 +233,7 @@ namespace hal return ERR("net does not belong to netlist"); } - std::unordered_set res; + std::set res; for (const auto* exit_ep : successors ? gate->get_fan_out_endpoints() : gate->get_fan_in_endpoints()) { if (exit_endpoint_filter != nullptr && !exit_endpoint_filter(exit_ep, 0)) diff --git a/src/python_bindings/bindings/netlist_traversal_decorator.cpp b/src/python_bindings/bindings/netlist_traversal_decorator.cpp index 055716cb3eb..808eaf536b3 100644 --- a/src/python_bindings/bindings/netlist_traversal_decorator.cpp +++ b/src/python_bindings/bindings/netlist_traversal_decorator.cpp @@ -93,7 +93,7 @@ namespace hal bool successors, const std::function& target_gate_filter, const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) -> std::optional> { + const std::function& entry_endpoint_filter = nullptr) -> std::optional> { auto res = self.get_next_gates_fancy(net, successors, target_gate_filter, exit_endpoint_filter, entry_endpoint_filter); if (res.is_ok()) { @@ -131,7 +131,7 @@ namespace hal bool successors, const std::function& target_gate_filter, const std::function& exit_endpoint_filter = nullptr, - const std::function& entry_endpoint_filter = nullptr) -> std::optional> { + const std::function& entry_endpoint_filter = nullptr) -> std::optional> { auto res = self.get_next_gates_fancy(gate, successors, target_gate_filter, exit_endpoint_filter, entry_endpoint_filter); if (res.is_ok()) { diff --git a/src/utilities/finite_set.cpp b/src/utilities/finite_set.cpp new file mode 100644 index 00000000000..faaf0d26891 --- /dev/null +++ b/src/utilities/finite_set.cpp @@ -0,0 +1,108 @@ +#include "hal_core/utilities/finite_set.h" + +namespace hal +{ + template + FiniteSet::FiniteSet(const u32 size) : m_size(size) + { + m_content = std::vector((m_size / 64) + 1, 0); + } + + template + bool FiniteSet::operator==(const FiniteSet& rhs) const + { + return m_content == rhs.m_content; + } + + template + bool FiniteSet::operator<(const FiniteSet& rhs) const + { + return m_content < rhs.m_content; + } + + template + FiniteSet FiniteSet::operator&(const FiniteSet& rhs) const + { + FiniteSet res(m_size); + for (u32 i = 0; i < m_size; i++) + { + res.m_content[i] = m_content[i] & rhs.m_content[i]; + } + return std::move(res); + } + + template + FiniteSet FiniteSet::operator|(const FiniteSet& rhs) const + { + FiniteSet res(m_size); + for (u32 i = 0; i < m_size; i++) + { + res.m_content[i] = m_content[i] | rhs.m_content[i]; + } + return std::move(res); + } + + template + FiniteSet FiniteSet::operator-(const FiniteSet& rhs) const + { + FiniteSet res(m_size); + for (u32 i = 0; i < m_size; i++) + { + res.m_content[i] = m_content[i] & ~rhs.m_content[i]; + } + return std::move(res); + } + + template + FiniteSet FiniteSet::operator^(const FiniteSet& rhs) const + { + FiniteSet res(m_size); + for (u32 i = 0; i < m_size; i++) + { + res.m_content[i] = m_content[i] ^ rhs.m_content[i]; + } + return std::move(res); + } + + template + bool FiniteSet::is_disjoint(const FiniteSet& rhs) const + { + // TODO implement + return false; + } + + template + bool FiniteSet::is_subset(const FiniteSet& rhs) const + { + // TODO implement + return false; + } + + template + bool FiniteSet::is_superset(const FiniteSet& rhs) const + { + // TODO implement + return false; + } + + template + bool FiniteSet::insert(const u32 index) + { + // TODO implement + return false; + } + + template + bool FiniteSet::erase(const u32 index) + { + // TODO implement + return false; + } + + template + bool FiniteSet::contains(const u32 index) + { + // TODO implement + return false; + } +} // namespace hal \ No newline at end of file From 1445f28b070460a1e7360a14b25e79040611f091 Mon Sep 17 00:00:00 2001 From: SJulianS Date: Mon, 13 Nov 2023 16:07:08 +0100 Subject: [PATCH 20/22] finished finite set and added tests --- include/hal_core/utilities/finite_set.h | 9 +- src/utilities/finite_set.cpp | 133 +++++++++++-------- tests/core/utils.cpp | 168 ++++++++++++++++++++++++ 3 files changed, 249 insertions(+), 61 deletions(-) diff --git a/include/hal_core/utilities/finite_set.h b/include/hal_core/utilities/finite_set.h index 043093d5047..88d405dd18d 100644 --- a/include/hal_core/utilities/finite_set.h +++ b/include/hal_core/utilities/finite_set.h @@ -32,17 +32,16 @@ namespace hal { - template struct FiniteSet { FiniteSet(const u32 size); bool operator==(const FiniteSet& rhs) const; bool operator<(const FiniteSet& rhs) const; - FiniteSet operator&(const FiniteSet& rhs) const; // intersect - FiniteSet operator|(const FiniteSet& rhs) const; // union - FiniteSet operator-(const FiniteSet& rhs) const; // difference - FiniteSet operator^(const FiniteSet& rhs) const; // symmetric difference + FiniteSet operator&(const FiniteSet& rhs) const; // intersect + FiniteSet operator|(const FiniteSet& rhs) const; // union + FiniteSet operator-(const FiniteSet& rhs) const; // difference + FiniteSet operator^(const FiniteSet& rhs) const; // symmetric difference bool is_disjoint(const FiniteSet& rhs) const; bool is_subset(const FiniteSet& rhs) const; diff --git a/src/utilities/finite_set.cpp b/src/utilities/finite_set.cpp index faaf0d26891..da535df4b9f 100644 --- a/src/utilities/finite_set.cpp +++ b/src/utilities/finite_set.cpp @@ -1,108 +1,129 @@ #include "hal_core/utilities/finite_set.h" - +#include namespace hal { - template - FiniteSet::FiniteSet(const u32 size) : m_size(size) + FiniteSet::FiniteSet(const u32 size) : m_size(size) { - m_content = std::vector((m_size / 64) + 1, 0); + m_content = std::vector(((m_size - 1) >> 6) + 1, 0); } - template - bool FiniteSet::operator==(const FiniteSet& rhs) const + bool FiniteSet::operator==(const FiniteSet& rhs) const { return m_content == rhs.m_content; } - template - bool FiniteSet::operator<(const FiniteSet& rhs) const + bool FiniteSet::operator<(const FiniteSet& rhs) const { return m_content < rhs.m_content; } - template - FiniteSet FiniteSet::operator&(const FiniteSet& rhs) const + FiniteSet FiniteSet::operator&(const FiniteSet& rhs) const { - FiniteSet res(m_size); - for (u32 i = 0; i < m_size; i++) + FiniteSet res(m_size); + for (u32 i = 0; i < m_content.size(); i++) { - res.m_content[i] = m_content[i] & rhs.m_content[i]; + res.m_content.at(i) = m_content.at(i) & rhs.m_content.at(i); } - return std::move(res); + return res; } - template - FiniteSet FiniteSet::operator|(const FiniteSet& rhs) const + FiniteSet FiniteSet::operator|(const FiniteSet& rhs) const { - FiniteSet res(m_size); - for (u32 i = 0; i < m_size; i++) + FiniteSet res(m_size); + for (u32 i = 0; i < m_content.size(); i++) { - res.m_content[i] = m_content[i] | rhs.m_content[i]; + res.m_content.at(i) = m_content.at(i) | rhs.m_content.at(i); } - return std::move(res); + return res; } - template - FiniteSet FiniteSet::operator-(const FiniteSet& rhs) const + FiniteSet FiniteSet::operator-(const FiniteSet& rhs) const { - FiniteSet res(m_size); - for (u32 i = 0; i < m_size; i++) + FiniteSet res(m_size); + for (u32 i = 0; i < m_content.size(); i++) { - res.m_content[i] = m_content[i] & ~rhs.m_content[i]; + res.m_content.at(i) = m_content.at(i) & ~rhs.m_content.at(i); } - return std::move(res); + return res; } - template - FiniteSet FiniteSet::operator^(const FiniteSet& rhs) const + FiniteSet FiniteSet::operator^(const FiniteSet& rhs) const { - FiniteSet res(m_size); - for (u32 i = 0; i < m_size; i++) + FiniteSet res(m_size); + for (u32 i = 0; i < m_content.size(); i++) { - res.m_content[i] = m_content[i] ^ rhs.m_content[i]; + res.m_content.at(i) = m_content.at(i) ^ rhs.m_content.at(i); } - return std::move(res); + return res; } - template - bool FiniteSet::is_disjoint(const FiniteSet& rhs) const + bool FiniteSet::is_disjoint(const FiniteSet& rhs) const { - // TODO implement - return false; + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != 0) + { + return false; + } + } + return true; } - template - bool FiniteSet::is_subset(const FiniteSet& rhs) const + bool FiniteSet::is_subset(const FiniteSet& rhs) const { - // TODO implement - return false; + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != m_content.at(i)) + { + return false; + } + } + return true; } - template - bool FiniteSet::is_superset(const FiniteSet& rhs) const + bool FiniteSet::is_superset(const FiniteSet& rhs) const { - // TODO implement - return false; + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != rhs.m_content.at(i)) + { + return false; + } + } + return true; } - template - bool FiniteSet::insert(const u32 index) + bool FiniteSet::insert(const u32 index) { - // TODO implement - return false; + if (index >= m_size) + { + return false; + } + + m_content.at(index >> 6) ^= (u64)1 << (index & 0x3F); + + return true; } - template - bool FiniteSet::erase(const u32 index) + bool FiniteSet::erase(const u32 index) { - // TODO implement - return false; + if (index >= m_size) + { + return false; + } + + m_content.at(index >> 6) &= ~((u64)1 << (index & 0x3F)); + + return true; } - template - bool FiniteSet::contains(const u32 index) + bool FiniteSet::contains(const u32 index) { - // TODO implement - return false; + if (index >= m_size) + { + return false; + } + + return (m_content.at(index >> 6) & (u64)1 << (index & 0x3F)) != 0; } } // namespace hal \ No newline at end of file diff --git a/tests/core/utils.cpp b/tests/core/utils.cpp index 568c917afb5..fa73ab9d468 100644 --- a/tests/core/utils.cpp +++ b/tests/core/utils.cpp @@ -1,5 +1,6 @@ #include "netlist_test_utils.h" #include "test_def.h" +#include "hal_core/utilities/finite_set.h" #include "gtest/gtest.h" #include "hal_core/utilities/log.h" @@ -642,4 +643,171 @@ namespace hal { TEST_END } + + /** + * Testing FiniteSet + * + * Classes: FiniteSet + */ + TEST_F(UtilsTest, check_finite_set) + { + TEST_START + { + FiniteSet set_16(16); + FiniteSet set_64(64); + FiniteSet set_128(128); + + ASSERT_EQ(set_16.m_size, 16); + ASSERT_EQ(set_16.m_content.size(), 1); + + ASSERT_EQ(set_64.m_size, 64); + ASSERT_EQ(set_64.m_content.size(), 1); + + ASSERT_EQ(set_128.m_size, 128); + ASSERT_EQ(set_128.m_content.size(), 2); + + EXPECT_FALSE(set_16.contains(10)); + EXPECT_EQ(set_16.m_content.at(0), (u64)0); + EXPECT_TRUE(set_16.insert(10)); + EXPECT_TRUE(set_16.contains(10)); + EXPECT_EQ(set_16.m_content.at(0), ((u64)1) << 10); + EXPECT_TRUE(set_16.erase(10)); + EXPECT_FALSE(set_16.contains(10)); + EXPECT_EQ(set_16.m_content.at(0), (u64)0); + + EXPECT_FALSE(set_64.contains(63)); + EXPECT_EQ(set_64.m_content.at(0), (u64)0); + EXPECT_TRUE(set_64.insert(63)); + EXPECT_TRUE(set_64.contains(63)); + EXPECT_EQ(set_64.m_content.at(0), ((u64)1) << 63); + EXPECT_TRUE(set_64.erase(63)); + EXPECT_FALSE(set_64.contains(63)); + EXPECT_EQ(set_64.m_content.at(0), (u64)0); + + EXPECT_FALSE(set_128.contains(63)); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.insert(63)); + EXPECT_TRUE(set_128.contains(63)); + EXPECT_EQ(set_128.m_content.at(0), ((u64)1) << 63); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.erase(63)); + EXPECT_FALSE(set_128.contains(63)); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + + EXPECT_FALSE(set_128.contains(100)); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.insert(100)); + EXPECT_TRUE(set_128.contains(100)); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), ((u64)1) << 36); + EXPECT_TRUE(set_128.erase(100)); + EXPECT_FALSE(set_128.contains(100)); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + } + { + FiniteSet set_a(128); + FiniteSet set_b(128); + + EXPECT_TRUE(set_a == set_b); + + EXPECT_EQ(set_a.m_content.at(0), (u64)0); + EXPECT_EQ(set_a.m_content.at(1), (u64)0); + EXPECT_EQ(set_b.m_content.at(0), (u64)0); + EXPECT_EQ(set_b.m_content.at(1), (u64)0); + + set_a.insert(10); + set_b.insert(10); + + EXPECT_EQ(set_a.m_content.at(0), ((u64)1) << 10); + EXPECT_EQ(set_a.m_content.at(1), (u64)0); + EXPECT_EQ(set_b.m_content.at(0), ((u64)1) << 10); + EXPECT_EQ(set_b.m_content.at(1), (u64)0); + + EXPECT_TRUE(set_a == set_b); + EXPECT_TRUE(set_a.is_subset(set_b)); + EXPECT_TRUE(set_b.is_subset(set_a)); + EXPECT_TRUE(set_a.is_superset(set_b)); + EXPECT_TRUE(set_b.is_superset(set_a)); + EXPECT_FALSE(set_a.is_disjoint(set_b)); + EXPECT_FALSE(set_b.is_disjoint(set_a)); + + set_b.insert(70); + + EXPECT_EQ(set_a.m_content.at(0), ((u64)1) << 10); + EXPECT_EQ(set_a.m_content.at(1), (u64)0); + EXPECT_EQ(set_b.m_content.at(0), ((u64)1) << 10); + EXPECT_EQ(set_b.m_content.at(1), ((u64)1) << 6); + + EXPECT_FALSE(set_a == set_b); + EXPECT_TRUE(set_a.is_subset(set_b)); + EXPECT_FALSE(set_b.is_subset(set_a)); + EXPECT_FALSE(set_a.is_superset(set_b)); + EXPECT_TRUE(set_b.is_superset(set_a)); + EXPECT_FALSE(set_a.is_disjoint(set_b)); + EXPECT_FALSE(set_b.is_disjoint(set_a)); + + EXPECT_TRUE(set_b.erase(10)); + + EXPECT_FALSE(set_a == set_b); + EXPECT_FALSE(set_a.is_subset(set_b)); + EXPECT_FALSE(set_b.is_subset(set_a)); + EXPECT_FALSE(set_a.is_superset(set_b)); + EXPECT_FALSE(set_b.is_superset(set_a)); + EXPECT_TRUE(set_a.is_disjoint(set_b)); + EXPECT_TRUE(set_b.is_disjoint(set_a)); + } + { + FiniteSet set_a(128); + FiniteSet set_b(128); + FiniteSet set_c(128); + FiniteSet set_d(128); + + set_a.insert(10); + set_b.insert(10); + set_b.insert(70); + set_c.insert(70); + set_d.insert(70); + set_d.insert(110); + + auto res_intersect = set_a & set_b; + EXPECT_TRUE(set_a.contains(10)); + EXPECT_FALSE(set_a.contains(70)); + EXPECT_TRUE(set_b.contains(10)); + EXPECT_TRUE(set_b.contains(70)); + EXPECT_TRUE(res_intersect.contains(10)); + EXPECT_FALSE(res_intersect.contains(70)); + + auto res_union = set_a | set_c; + EXPECT_TRUE(set_a.contains(10)); + EXPECT_FALSE(set_a.contains(70)); + EXPECT_FALSE(set_c.contains(10)); + EXPECT_TRUE(set_c.contains(70)); + EXPECT_TRUE(res_union.contains(10)); + EXPECT_TRUE(res_union.contains(70)); + + auto res_difference_1 = set_b - set_d; + auto res_difference_2 = set_d - set_b; + auto res_sym_difference = set_b ^ set_d; + EXPECT_TRUE(set_b.contains(10)); + EXPECT_TRUE(set_b.contains(70)); + EXPECT_FALSE(set_b.contains(110)); + EXPECT_FALSE(set_d.contains(10)); + EXPECT_TRUE(set_d.contains(70)); + EXPECT_TRUE(set_d.contains(110)); + EXPECT_TRUE(res_difference_1.contains(10)); + EXPECT_FALSE(res_difference_1.contains(70)); + EXPECT_FALSE(res_difference_1.contains(110)); + EXPECT_FALSE(res_difference_2.contains(10)); + EXPECT_FALSE(res_difference_2.contains(70)); + EXPECT_TRUE(res_difference_2.contains(110)); + EXPECT_TRUE(res_sym_difference.contains(10)); + EXPECT_FALSE(res_sym_difference.contains(70)); + EXPECT_TRUE(res_sym_difference.contains(110)); + } + TEST_END + } } //namespace hal From 0d1ff5f5f60654d3f608d26e2d9ae97b6982b4d9 Mon Sep 17 00:00:00 2001 From: joern274 Date: Mon, 13 Nov 2023 19:22:09 +0100 Subject: [PATCH 21/22] Bugfix: routing of global inputs and outputs --- .../gui/graph_widget/items/nets/standard_arrow_net.h | 2 +- plugins/gui/src/graph_widget/layouters/graph_layouter.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h index dcd374af447..a4f5c22395a 100644 --- a/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h +++ b/plugins/gui/include/gui/graph_widget/items/nets/standard_arrow_net.h @@ -67,7 +67,7 @@ namespace hal { * * @param v - The visuals to set. */ - virtual void setVisuals(const Visuals& v); + virtual void setVisuals(const Visuals& v) override; /** * Overwritten qt function to draw the net. diff --git a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp index 15e3c70f9f6..095acd758cc 100644 --- a/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp +++ b/plugins/gui/src/graph_widget/layouters/graph_layouter.cpp @@ -936,17 +936,17 @@ namespace hal case EndpointList::HasGlobalEndpoint: if (epl.hasInputArrow()) { - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); graphicsNet = san; int yGridPos = mGlobalInputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); const EndpointCoordinate& epc = mEndpointHash.value(QPoint(mNodeBoundingBox.left(), yGridPos * 2)); - san->setInputPosition(QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.left(),-1), epc.lanePosition(0, true))); + san->setInputPosition(QPointF(mCoordArrayX->lanePosition(mNodeBoundingBox.left(),0), epc.lanePosition(0, true))); } if (epl.hasOutputArrow()) { if (graphicsNet) mScene->addGraphItem(graphicsNet); - StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines); + StandardArrowNet* san = new StandardArrowNet(n, dnt->mLines, dnt->mKnots); graphicsNet = san; int yGridPos = mGlobalOutputHash.value(dnt->id(), -1); Q_ASSERT(yGridPos >= 0); @@ -954,7 +954,7 @@ namespace hal const EndpointCoordinate& epc = mEndpointHash.value(pnt); const NetLayoutJunction* nlj = mJunctionHash.value(pnt); Q_ASSERT(nlj); - san->setOutputPosition(QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj->rect().right() + 1), epc.lanePosition(0, true))); + san->setOutputPosition(QPointF(mCoordArrayX->lanePosition(pnt.x(),nlj->rect().right()), epc.lanePosition(0, true))); } break; case EndpointList::SourceAndDestination: From a1257edd949951eefe8198bb729a788d4086e270 Mon Sep 17 00:00:00 2001 From: SJulianS Date: Mon, 13 Nov 2023 21:14:30 +0100 Subject: [PATCH 22/22] improve memory usage --- include/hal_core/utilities/finite_set.h | 220 ++++++++++++++++++++++-- src/utilities/finite_set.cpp | 129 -------------- tests/core/utils.cpp | 92 +++++++++- 3 files changed, 287 insertions(+), 154 deletions(-) delete mode 100644 src/utilities/finite_set.cpp diff --git a/include/hal_core/utilities/finite_set.h b/include/hal_core/utilities/finite_set.h index 88d405dd18d..9f5f231e9f4 100644 --- a/include/hal_core/utilities/finite_set.h +++ b/include/hal_core/utilities/finite_set.h @@ -27,34 +27,222 @@ #include "hal_core/defines.h" +#include #include #include namespace hal { + template struct FiniteSet { - FiniteSet(const u32 size); + FiniteSet(const std::vector* const data, const std::unordered_map* const data_to_index) : m_data(data), m_data_to_index(data_to_index) + { + m_size = m_data->size(); + m_content = std::vector(((m_size - 1) >> 6) + 1, 0); + } - bool operator==(const FiniteSet& rhs) const; - bool operator<(const FiniteSet& rhs) const; - FiniteSet operator&(const FiniteSet& rhs) const; // intersect - FiniteSet operator|(const FiniteSet& rhs) const; // union - FiniteSet operator-(const FiniteSet& rhs) const; // difference - FiniteSet operator^(const FiniteSet& rhs) const; // symmetric difference + bool operator==(const FiniteSet& rhs) const + { + return m_content == rhs.m_content; + } - bool is_disjoint(const FiniteSet& rhs) const; - bool is_subset(const FiniteSet& rhs) const; - bool is_superset(const FiniteSet& rhs) const; + bool operator<(const FiniteSet& rhs) const + { + return m_content < rhs.m_content; + } - bool insert(const u32 index); - bool erase(const u32 index); - bool contains(const u32 index); + FiniteSet operator&(const FiniteSet& rhs) const + { + FiniteSet res(m_data, m_data_to_index); + for (u32 i = 0; i < m_content.size(); i++) + { + res.m_content.at(i) = m_content.at(i) & rhs.m_content.at(i); + } + return res; + } + + FiniteSet operator|(const FiniteSet& rhs) const + { + FiniteSet res(m_data, m_data_to_index); + for (u32 i = 0; i < m_content.size(); i++) + { + res.m_content.at(i) = m_content.at(i) | rhs.m_content.at(i); + } + return res; + } + + FiniteSet operator-(const FiniteSet& rhs) const + { + FiniteSet res(m_data, m_data_to_index); + for (u32 i = 0; i < m_content.size(); i++) + { + res.m_content.at(i) = m_content.at(i) & ~rhs.m_content.at(i); + } + return res; + } + + FiniteSet operator^(const FiniteSet& rhs) const + { + FiniteSet res(m_data, m_data_to_index); + for (u32 i = 0; i < m_content.size(); i++) + { + res.m_content.at(i) = m_content.at(i) ^ rhs.m_content.at(i); + } + return res; + } + + bool is_disjoint(const FiniteSet& rhs) const + { + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != 0) + { + return false; + } + } + return true; + } + + bool is_subset(const FiniteSet& rhs) const + { + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != m_content.at(i)) + { + return false; + } + } + return true; + } + + bool is_superset(const FiniteSet& rhs) const + { + for (u32 i = 0; i < m_content.size(); i++) + { + if ((m_content.at(i) & rhs.m_content.at(i)) != rhs.m_content.at(i)) + { + return false; + } + } + return true; + } + + bool insert(const u32 index) + { + if (index >= m_size) + { + return false; + } + + m_content.at(index >> 6) ^= (u64)1 << (index & 0x3F); + + return true; + } + + bool insert(const T& elem) + { + const auto it = m_data_to_index->find(elem); + if (it == m_data_to_index->end()) + { + return false; + } + + const u32 index = it->second; + m_content.at(index >> 6) ^= (u64)1 << (index & 0x3F); + return true; + } + + bool erase(const u32 index) + { + if (index >= m_size) + { + return false; + } + + m_content.at(index >> 6) &= ~((u64)1 << (index & 0x3F)); + + return true; + } + + bool erase(const T& elem) + { + const auto it = m_data_to_index->find(elem); + if (it == m_data_to_index->end()) + { + return false; + } + + const u32 index = it->second; + m_content.at(index >> 6) &= ~((u64)1 << (index & 0x3F)); + + return true; + } + + bool contains(const u32 index) + { + if (index >= m_size) + { + return false; + } + + return (m_content.at(index >> 6) & (u64)1 << (index & 0x3F)) != 0; + } + + bool contains(const T& elem) + { + const auto it = m_data_to_index->find(elem); + if (it == m_data_to_index->end()) + { + return false; + } + + const u32 index = it->second; + return (m_content.at(index >> 6) & (u64)1 << (index & 0x3F)) != 0; + } + + Result get_at(u32 index) const + { + if (index >= m_size) + { + return ERR("index " + std::to_string(index) + " is out of range, FiniteSet has size " + std::to_string(m_size)); + } + + return OK(m_data->at(index)); + } + + Result get_index(const T& elem) const + { + const auto it = m_data_to_index->find(elem); + if (it == m_data_to_index->end()) + { + return ERR("element cannot be part of FiniteSet because it is not contained in base data"); + } + + return OK(it->second); + } + + std::vector get_contained() const + { + std::vector res; + + for (u32 i = 0; i < m_content.size(); i++) + { + for (u32 j = 0; j < 64; j++) + { + if (m_content.at(i) & ((u64)1 << j)) + { + res.push_back(m_data->at((i << 6) + j)); + } + } + } + + return res; + } u32 m_size; + const std::vector* const m_data; + const std::unordered_map* const m_data_to_index; std::vector m_content; - - private: - void initialize(); }; } // namespace hal diff --git a/src/utilities/finite_set.cpp b/src/utilities/finite_set.cpp deleted file mode 100644 index da535df4b9f..00000000000 --- a/src/utilities/finite_set.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "hal_core/utilities/finite_set.h" -#include -namespace hal -{ - FiniteSet::FiniteSet(const u32 size) : m_size(size) - { - m_content = std::vector(((m_size - 1) >> 6) + 1, 0); - } - - bool FiniteSet::operator==(const FiniteSet& rhs) const - { - return m_content == rhs.m_content; - } - - bool FiniteSet::operator<(const FiniteSet& rhs) const - { - return m_content < rhs.m_content; - } - - FiniteSet FiniteSet::operator&(const FiniteSet& rhs) const - { - FiniteSet res(m_size); - for (u32 i = 0; i < m_content.size(); i++) - { - res.m_content.at(i) = m_content.at(i) & rhs.m_content.at(i); - } - return res; - } - - FiniteSet FiniteSet::operator|(const FiniteSet& rhs) const - { - FiniteSet res(m_size); - for (u32 i = 0; i < m_content.size(); i++) - { - res.m_content.at(i) = m_content.at(i) | rhs.m_content.at(i); - } - return res; - } - - FiniteSet FiniteSet::operator-(const FiniteSet& rhs) const - { - FiniteSet res(m_size); - for (u32 i = 0; i < m_content.size(); i++) - { - res.m_content.at(i) = m_content.at(i) & ~rhs.m_content.at(i); - } - return res; - } - - FiniteSet FiniteSet::operator^(const FiniteSet& rhs) const - { - FiniteSet res(m_size); - for (u32 i = 0; i < m_content.size(); i++) - { - res.m_content.at(i) = m_content.at(i) ^ rhs.m_content.at(i); - } - return res; - } - - bool FiniteSet::is_disjoint(const FiniteSet& rhs) const - { - for (u32 i = 0; i < m_content.size(); i++) - { - if ((m_content.at(i) & rhs.m_content.at(i)) != 0) - { - return false; - } - } - return true; - } - - bool FiniteSet::is_subset(const FiniteSet& rhs) const - { - for (u32 i = 0; i < m_content.size(); i++) - { - if ((m_content.at(i) & rhs.m_content.at(i)) != m_content.at(i)) - { - return false; - } - } - return true; - } - - bool FiniteSet::is_superset(const FiniteSet& rhs) const - { - for (u32 i = 0; i < m_content.size(); i++) - { - if ((m_content.at(i) & rhs.m_content.at(i)) != rhs.m_content.at(i)) - { - return false; - } - } - return true; - } - - bool FiniteSet::insert(const u32 index) - { - if (index >= m_size) - { - return false; - } - - m_content.at(index >> 6) ^= (u64)1 << (index & 0x3F); - - return true; - } - - bool FiniteSet::erase(const u32 index) - { - if (index >= m_size) - { - return false; - } - - m_content.at(index >> 6) &= ~((u64)1 << (index & 0x3F)); - - return true; - } - - bool FiniteSet::contains(const u32 index) - { - if (index >= m_size) - { - return false; - } - - return (m_content.at(index >> 6) & (u64)1 << (index & 0x3F)) != 0; - } -} // namespace hal \ No newline at end of file diff --git a/tests/core/utils.cpp b/tests/core/utils.cpp index fa73ab9d468..015280aed97 100644 --- a/tests/core/utils.cpp +++ b/tests/core/utils.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace hal { using namespace utils; @@ -653,9 +654,32 @@ namespace hal { { TEST_START { - FiniteSet set_16(16); - FiniteSet set_64(64); - FiniteSet set_128(128); + std::vector dummy_data_16; + std::unordered_map dummy_map_16; + for (u32 i = 0; i < 16; i++) + { + dummy_data_16.push_back(std::to_string(i)); + dummy_map_16[std::to_string(i)] = i; + } + FiniteSet set_16(&dummy_data_16, &dummy_map_16); + + std::vector dummy_data_64; + std::unordered_map dummy_map_64; + for (u32 i = 0; i < 64; i++) + { + dummy_data_64.push_back(std::to_string(i)); + dummy_map_64[std::to_string(i)] = i; + } + FiniteSet set_64(&dummy_data_64, &dummy_map_64); + + std::vector dummy_data_128; + std::unordered_map dummy_map_128; + for (u32 i = 0; i < 128; i++) + { + dummy_data_128.push_back(std::to_string(i)); + dummy_map_128[std::to_string(i)] = i; + } + FiniteSet set_128(&dummy_data_128, &dummy_map_128); ASSERT_EQ(set_16.m_size, 16); ASSERT_EQ(set_16.m_content.size(), 1); @@ -674,6 +698,12 @@ namespace hal { EXPECT_TRUE(set_16.erase(10)); EXPECT_FALSE(set_16.contains(10)); EXPECT_EQ(set_16.m_content.at(0), (u64)0); + EXPECT_TRUE(set_16.insert("10")); + EXPECT_TRUE(set_16.contains("10")); + EXPECT_EQ(set_16.m_content.at(0), ((u64)1) << 10); + EXPECT_TRUE(set_16.erase("10")); + EXPECT_FALSE(set_16.contains("10")); + EXPECT_EQ(set_16.m_content.at(0), (u64)0); EXPECT_FALSE(set_64.contains(63)); EXPECT_EQ(set_64.m_content.at(0), (u64)0); @@ -683,6 +713,12 @@ namespace hal { EXPECT_TRUE(set_64.erase(63)); EXPECT_FALSE(set_64.contains(63)); EXPECT_EQ(set_64.m_content.at(0), (u64)0); + EXPECT_TRUE(set_64.insert("63")); + EXPECT_TRUE(set_64.contains("63")); + EXPECT_EQ(set_64.m_content.at(0), ((u64)1) << 63); + EXPECT_TRUE(set_64.erase("63")); + EXPECT_FALSE(set_64.contains("63")); + EXPECT_EQ(set_64.m_content.at(0), (u64)0); EXPECT_FALSE(set_128.contains(63)); EXPECT_EQ(set_128.m_content.at(0), (u64)0); @@ -695,6 +731,14 @@ namespace hal { EXPECT_FALSE(set_128.contains(63)); EXPECT_EQ(set_128.m_content.at(0), (u64)0); EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.insert("63")); + EXPECT_TRUE(set_128.contains("63")); + EXPECT_EQ(set_128.m_content.at(0), ((u64)1) << 63); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.erase("63")); + EXPECT_FALSE(set_128.contains("63")); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); EXPECT_FALSE(set_128.contains(100)); EXPECT_EQ(set_128.m_content.at(0), (u64)0); @@ -707,10 +751,33 @@ namespace hal { EXPECT_FALSE(set_128.contains(100)); EXPECT_EQ(set_128.m_content.at(0), (u64)0); EXPECT_EQ(set_128.m_content.at(1), (u64)0); + EXPECT_TRUE(set_128.insert("100")); + EXPECT_TRUE(set_128.contains("100")); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), ((u64)1) << 36); + EXPECT_TRUE(set_128.erase("100")); + EXPECT_FALSE(set_128.contains("100")); + EXPECT_EQ(set_128.m_content.at(0), (u64)0); + EXPECT_EQ(set_128.m_content.at(1), (u64)0); + + EXPECT_TRUE(set_128.insert("10")); + EXPECT_TRUE(set_128.insert("30")); + EXPECT_TRUE(set_128.insert("50")); + EXPECT_TRUE(set_128.insert("70")); + EXPECT_TRUE(set_128.insert("90")); + + EXPECT_EQ(set_128.get_contained(), std::vector({"10", "30", "50", "70", "90"})); } { - FiniteSet set_a(128); - FiniteSet set_b(128); + std::vector dummy_data; + std::unordered_map dummy_map; + for (u32 i = 0; i < 128; i++) + { + dummy_data.push_back(std::to_string(i)); + dummy_map[std::to_string(i)] = i; + } + FiniteSet set_a(&dummy_data, &dummy_map); + FiniteSet set_b(&dummy_data, &dummy_map); EXPECT_TRUE(set_a == set_b); @@ -761,10 +828,17 @@ namespace hal { EXPECT_TRUE(set_b.is_disjoint(set_a)); } { - FiniteSet set_a(128); - FiniteSet set_b(128); - FiniteSet set_c(128); - FiniteSet set_d(128); + std::vector dummy_data; + std::unordered_map dummy_map; + for (u32 i = 0; i < 128; i++) + { + dummy_data.push_back(std::to_string(i)); + dummy_map[std::to_string(i)] = i; + } + FiniteSet set_a(&dummy_data, &dummy_map); + FiniteSet set_b(&dummy_data, &dummy_map); + FiniteSet set_c(&dummy_data, &dummy_map); + FiniteSet set_d(&dummy_data, &dummy_map); set_a.insert(10); set_b.insert(10);