aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-13 19:10:20 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-13 19:10:27 +0100
commitb8ca1a55820d6429f5ad5207be1e125b8786e093 (patch)
tree6733f6ff9de556ccee6bf87b33dbe6b963cbc6db
parent89809a8b810dd57f50f365d70a0ce547705f8dbb (diff)
parent07ff5ad8b8e4d0f87770b81b8478aa257567c504 (diff)
downloadnextpnr-b8ca1a55820d6429f5ad5207be1e125b8786e093.tar.gz
nextpnr-b8ca1a55820d6429f5ad5207be1e125b8786e093.tar.bz2
nextpnr-b8ca1a55820d6429f5ad5207be1e125b8786e093.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into q3k/lock-the-things
-rw-r--r--3rdparty/python-console/modified/pyconsole.cc322
-rw-r--r--3rdparty/python-console/modified/pyconsole.h80
-rw-r--r--ecp5/arch.h1
-rw-r--r--ecp5/archdefs.h2
-rw-r--r--ecp5/main.cc3
-rw-r--r--ecp5/pack.cc4
-rw-r--r--generic/arch.cc12
-rw-r--r--generic/arch.h1
-rw-r--r--gui/CMakeLists.txt1
-rw-r--r--gui/basewindow.cc3
-rw-r--r--gui/ice40/mainwindow.cc1
-rw-r--r--gui/ice40/worker.cc3
-rw-r--r--gui/line_editor.cc56
-rw-r--r--gui/line_editor.h11
-rw-r--r--gui/pyconsole.cc82
-rw-r--r--gui/pyconsole.h (renamed from ecp5/pack.h)37
-rw-r--r--gui/pythontab.cc41
-rw-r--r--gui/pythontab.h8
-rw-r--r--ice40/arch.cc89
-rw-r--r--ice40/arch.h29
-rw-r--r--ice40/arch_pybindings.cc5
-rw-r--r--ice40/archdefs.h3
-rw-r--r--ice40/chipdb.py2
-rw-r--r--ice40/gfx.cc103
-rw-r--r--ice40/main.cc3
-rw-r--r--ice40/pack.cc4
-rw-r--r--ice40/pack.h32
27 files changed, 411 insertions, 527 deletions
diff --git a/3rdparty/python-console/modified/pyconsole.cc b/3rdparty/python-console/modified/pyconsole.cc
deleted file mode 100644
index d724553b..00000000
--- a/3rdparty/python-console/modified/pyconsole.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-#include "pyconsole.h"
-#include "pyinterpreter.h"
-#include "ColumnFormatter.h"
-
-#include <iostream>
-#include <QKeyEvent>
-#include <QFont>
-
-#include "Utils.h"
-
-const QString PythonConsole::PROMPT = ">>> ";
-const QString PythonConsole::MULTILINE_PROMPT = "... ";
-const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF( 0, 0, 0 );
-const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF( 1.0, 0, 0 );
-const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF( 0, 0, 1.0 );
-
-PythonConsole::PythonConsole( QWidget* parent ):
- QTextEdit( parent )
-{
- QFont font("unexistent");
- font.setStyleHint(QFont::Monospace);
- setFont(font);
- m_parseHelper.subscribe( this );
-}
-
-void PythonConsole::keyPressEvent( QKeyEvent* e )
-{
- switch ( e->key() )
- {
- case Qt::Key_Return:
- handleReturnKeyPress( );
- return;
-
- case Qt::Key_Tab:
- autocomplete( );
- return;
-
- case Qt::Key_Backspace:
- if ( ! canBackspace( ) )
- return;
- break;
-
- case Qt::Key_Up:
- previousHistory( );
- return;
-
- case Qt::Key_Down:
- nextHistory( );
- return;
-
- case Qt::Key_Left:
- if ( ! canGoLeft( ) )
- return;
- }
- if (!cursorIsOnInputLine()) return;
- if (textCursor().columnNumber() < PythonConsole::PROMPT.size()) return;
- QTextEdit::keyPressEvent( e );
-}
-
-void PythonConsole::handleReturnKeyPress( )
-{
- if ( ! cursorIsOnInputLine( ) )
- {
- return;
- }
-
- QString line = getLine( );
-
- m_parseHelper.process( line.toStdString( ) );
- if ( m_parseHelper.buffered( ) )
- {
- append("");
- displayPrompt( );
- }
- if ( line.size( ) )
- {
- m_historyBuffer.push_back( line.toStdString( ) );
- m_historyIt = m_historyBuffer.end();
- }
- moveCursorToEnd( );
-}
-
-void PythonConsole::parseEvent( const ParseMessage& message )
-{
- // handle invalid user input
- if ( message.errorCode )
- {
- setTextColor( ERROR_COLOR );
- append(message.message.c_str());
-
- setTextColor( NORMAL_COLOR );
- append("");
- displayPrompt( );
- return;
- }
-
- // interpret valid user input
- int errorCode = 0;
- std::string res;
- if ( message.message.size() )
- res = pyinterpreter_execute( message.message, &errorCode );
- if ( errorCode )
- {
- setTextColor( ERROR_COLOR );
- }
- else
- {
- setTextColor( OUTPUT_COLOR );
- }
-
- if ( res.size( ) )
- {
- append(res.c_str());
- }
-
- setTextColor( NORMAL_COLOR );
-
- // set up the next line on the console
- append("");
- displayPrompt( );
-}
-
-QString PythonConsole::getLine( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- QString line = cursor.selectedText( );
- cursor.clearSelection( );
- return line;
-}
-
-bool PythonConsole::cursorIsOnInputLine( )
-{
- int cursorBlock = textCursor( ).blockNumber( );
- QTextCursor bottomCursor = textCursor( );
- bottomCursor.movePosition( QTextCursor::End );
- int bottomBlock = bottomCursor.blockNumber( );
- return ( cursorBlock == bottomBlock );
-}
-
-bool PythonConsole::inputLineIsEmpty( )
-{
- QTextCursor bottomCursor = textCursor( );
- bottomCursor.movePosition( QTextCursor::End );
- int col = bottomCursor.columnNumber( );
- return ( col == PythonConsole::PROMPT.size( ) );
-}
-
-bool PythonConsole::canBackspace( )
-{
- if ( ! cursorIsOnInputLine( ) )
- {
- return false;
- }
-
- if ( inputLineIsEmpty( ) )
- {
- return false;
- }
-
- return true;
-}
-
-bool PythonConsole::canGoLeft( )
-{
- if ( cursorIsOnInputLine( ) )
- {
- QTextCursor bottomCursor = textCursor( );
- int col = bottomCursor.columnNumber( );
- return (col > PythonConsole::PROMPT.size( ));
- }
- return true;
-}
-
-void PythonConsole::displayPrompt( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- if ( m_parseHelper.buffered( ) )
- {
- cursor.insertText( PythonConsole::MULTILINE_PROMPT );
- }
- else
- {
- cursor.insertText( PythonConsole::PROMPT );
- }
- cursor.movePosition( QTextCursor::EndOfLine );
-}
-
-void PythonConsole::displayString(QString text)
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- cursor.insertText( text );
- cursor.movePosition( QTextCursor::EndOfLine );
-}
-
-void PythonConsole::autocomplete( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- QString line = getLine( );
- const std::list<std::string>& suggestions =
- pyinterpreter_suggest( line.toStdString( ) );
- if (suggestions.size() == 1)
- {
- line = suggestions.back().c_str();
- }
- else
- {
- // try to complete to longest common prefix
- std::string prefix =
- LongestCommonPrefix(suggestions.begin(), suggestions.end());
- if (prefix.size() > (size_t)line.size())
- {
- line = prefix.c_str();
- }
- else
- {
- ColumnFormatter fmt;
- fmt.setItems(suggestions.begin(), suggestions.end());
- fmt.format(width() / 10);
- setTextColor( OUTPUT_COLOR );
- const std::list<std::string>& formatted = fmt.formattedOutput();
- for (std::list<std::string>::const_iterator it = formatted.begin();
- it != formatted.end(); ++it)
- {
- append(it->c_str());
- }
- setTextColor( NORMAL_COLOR );
- }
- }
-
- // set up the next line on the console
- append("");
- displayPrompt( );
- moveCursorToEnd( );
- QTextCursor cursor = textCursor();
- cursor.insertText( line );
- moveCursorToEnd( );
-}
-
-void PythonConsole::previousHistory( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- if ( ! m_historyBuffer.size( ) )
- return;
-
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- cursor.removeSelectedText( );
- if ( m_historyIt != m_historyBuffer.begin( ) )
- {
- --m_historyIt;
- }
- cursor.insertText( m_historyIt->c_str() );
-}
-
-void PythonConsole::nextHistory( )
-{
- if ( ! cursorIsOnInputLine( ) )
- return;
-
- if ( ! m_historyBuffer.size( ) )
- return;
- if ( m_historyIt == m_historyBuffer.end( ) )
- {
- return;
- }
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::StartOfLine );
- cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, PythonConsole::PROMPT.size( ) );
- cursor.movePosition( QTextCursor::EndOfLine, QTextCursor::KeepAnchor );
- cursor.removeSelectedText( );
- ++m_historyIt;
- if ( m_historyIt == m_historyBuffer.end( ) )
- {
- return;
- }
- cursor.insertText( m_historyIt->c_str() );
-}
-
-void PythonConsole::moveCursorToEnd( )
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition( QTextCursor::End );
- setTextCursor( cursor );
-}
-
-void PythonConsole::insertFromMimeData(const QMimeData *src)
-{
- if (src->hasText()) {
- QStringList list = src->text().split("\n",QString::KeepEmptyParts);
- bool lastends = src->text().endsWith("\n");
- for (int i=0;i<list.size();i++)
- {
- QString line = list.at(i);
- displayString(line);
- if (!lastends && (i==list.size()-1)) break;
-
- m_parseHelper.process( line.toStdString( ) );
- if ( m_parseHelper.buffered( ) )
- {
- append("");
- displayPrompt( );
- }
- if ( line.size( ) )
- {
- m_historyBuffer.push_back( line.toStdString( ) );
- m_historyIt = m_historyBuffer.end();
- }
- moveCursorToEnd( );
- }
- }
-} \ No newline at end of file
diff --git a/3rdparty/python-console/modified/pyconsole.h b/3rdparty/python-console/modified/pyconsole.h
deleted file mode 100644
index adf4ce20..00000000
--- a/3rdparty/python-console/modified/pyconsole.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
-python-console
-Copyright (C) 2018 Alex Tsui
-
-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.
-*/
-
-#ifndef PYCONSOLE_H
-#define PYCONSOLE_H
-#include <QColor>
-#include <QTextEdit>
-#include <QMimeData>
-#include "ParseHelper.h"
-#include "ParseListener.h"
-
-class QWidget;
-class QKeyEvent;
-
-class PythonConsole : public QTextEdit, ParseListener
-{
- Q_OBJECT
-
- public:
- PythonConsole(QWidget *parent = 0);
-
- void displayPrompt();
- void displayString(QString text);
-
- protected:
- // override QTextEdit
- virtual void keyPressEvent(QKeyEvent *e);
-
- virtual void handleReturnKeyPress();
-
- virtual void insertFromMimeData(const QMimeData *src);
-
- /**
- Handle a compilable chunk of Python user input.
- */
- virtual void parseEvent(const ParseMessage &message);
-
- QString getLine();
- bool cursorIsOnInputLine();
- bool inputLineIsEmpty();
- bool canBackspace();
- bool canGoLeft();
- void autocomplete();
- void previousHistory();
- void nextHistory();
- void moveCursorToEnd();
-
- static const QString PROMPT;
- static const QString MULTILINE_PROMPT;
-
- static const QColor NORMAL_COLOR;
- static const QColor ERROR_COLOR;
- static const QColor OUTPUT_COLOR;
-
- ParseHelper m_parseHelper;
- std::list<std::string> m_historyBuffer;
- std::list<std::string>::const_iterator m_historyIt;
-};
-
-#endif // PYCONSOLE_H
diff --git a/ecp5/arch.h b/ecp5/arch.h
index bbc7c561..930c488e 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -730,6 +730,7 @@ struct Arch : BaseCtx
// -------------------------------------------------
+ bool pack();
bool place();
bool route();
diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h
index c4d25a50..84a431fd 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -22,7 +22,7 @@
#error Include "archdefs.h" via "nextpnr.h" only.
#endif
-#include <boost/functional/hash_fwd.hpp>
+#include <boost/functional/hash.hpp>
NEXTPNR_NAMESPACE_BEGIN
diff --git a/ecp5/main.cc b/ecp5/main.cc
index 734ae560..4cb2f10d 100644
--- a/ecp5/main.cc
+++ b/ecp5/main.cc
@@ -43,7 +43,6 @@
#include "bitstream.h"
#include "design_utils.h"
#include "jsonparse.h"
-#include "pack.h"
#include "timing.h"
USING_NEXTPNR_NAMESPACE
@@ -147,7 +146,7 @@ int main(int argc, char *argv[])
if (!parse_json_file(f, filename, ctx.get()))
log_error("Loading design failed.\n");
- if (!pack_design(ctx.get()) && !ctx->force)
+ if (!ctx->pack() && !ctx->force)
log_error("Packing design failed.\n");
if (vm.count("freq"))
ctx->target_freq = vm["freq"].as<double>() * 1e6;
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 7f54c231..e3ddc07d 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -17,7 +17,6 @@
*
*/
-#include "pack.h"
#include <algorithm>
#include <iterator>
#include <unordered_set>
@@ -84,8 +83,9 @@ void pack_io(Context *ctx)
}
// Main pack function
-bool pack_design(Context *ctx)
+bool Arch::pack()
{
+ Context *ctx = getCtx();
try {
log_break();
pack_io(ctx);
diff --git a/generic/arch.cc b/generic/arch.cc
index ec2443f2..390830aa 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -181,6 +181,7 @@ void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength)
bels.at(bel).bound_cell = cell;
cells.at(cell)->bel = bel;
cells.at(cell)->belStrength = strength;
+ refreshUiBel(bel);
}
void Arch::unbindBel(BelId bel)
@@ -188,6 +189,7 @@ void Arch::unbindBel(BelId bel)
cells.at(bels.at(bel).bound_cell)->bel = BelId();
cells.at(bels.at(bel).bound_cell)->belStrength = STRENGTH_NONE;
bels.at(bel).bound_cell = IdString();
+ refreshUiBel(bel);
}
bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == IdString(); }
@@ -236,6 +238,7 @@ void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength)
wires.at(wire).bound_net = net;
nets.at(net)->wires[wire].pip = PipId();
nets.at(net)->wires[wire].strength = strength;
+ refreshUiWire(wire);
}
void Arch::unbindWire(WireId wire)
@@ -243,11 +246,14 @@ void Arch::unbindWire(WireId wire)
auto &net_wires = nets[wires.at(wire).bound_net]->wires;
auto pip = net_wires.at(wire).pip;
- if (pip != PipId())
+ if (pip != PipId()) {
pips.at(pip).bound_net = IdString();
+ refreshUiPip(pip);
+ }
net_wires.erase(wire);
wires.at(wire).bound_net = IdString();
+ refreshUiWire(wire);
}
bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == IdString(); }
@@ -282,6 +288,8 @@ void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength)
wires.at(wire).bound_net = net;
nets.at(net)->wires[wire].pip = pip;
nets.at(net)->wires[wire].strength = strength;
+ refreshUiPip(pip);
+ refreshUiWire(wire);
}
void Arch::unbindPip(PipId pip)
@@ -290,6 +298,8 @@ void Arch::unbindPip(PipId pip)
nets.at(wires.at(wire).bound_net)->wires.erase(wire);
pips.at(pip).bound_net = IdString();
wires.at(wire).bound_net = IdString();
+ refreshUiPip(pip);
+ refreshUiWire(wire);
}
bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == IdString(); }
diff --git a/generic/arch.h b/generic/arch.h
index f6243404..5d7ac540 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -183,6 +183,7 @@ struct Arch : BaseCtx
float getDelayNS(delay_t v) const { return v; }
uint32_t getDelayChecksum(delay_t v) const { return 0; }
+ bool pack() { return true; }
bool place();
bool route();
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 5ac4d955..2e8e367e 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -12,7 +12,6 @@ if (BUILD_PYTHON)
../3rdparty/python-console/modified/pyredirector.cc
../3rdparty/python-console/modified/pyinterpreter.cc
- ../3rdparty/python-console/modified/pyconsole.cc
)
endif()
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 6bc56c7b..b76527e1 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -66,7 +66,6 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
DesignWidget *designview = new DesignWidget();
designview->setMinimumWidth(300);
- designview->setMaximumWidth(300);
splitter_h->addWidget(designview);
connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *)));
@@ -77,7 +76,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
tabWidget = new QTabWidget();
#ifndef NO_PYTHON
PythonTab *pythontab = new PythonTab();
- tabWidget->addTab(pythontab, "Python");
+ tabWidget->addTab(pythontab, "Console");
connect(this, SIGNAL(contextChanged(Context *)), pythontab, SLOT(newContext(Context *)));
#endif
info = new InfoTab();
diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc
index b7f08104..bea5fce7 100644
--- a/gui/ice40/mainwindow.cc
+++ b/gui/ice40/mainwindow.cc
@@ -27,7 +27,6 @@
#include "design_utils.h"
#include "jsonparse.h"
#include "log.h"
-#include "pack.h"
#include "pcf.h"
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc
index 16f5fb89..09093ec8 100644
--- a/gui/ice40/worker.cc
+++ b/gui/ice40/worker.cc
@@ -23,7 +23,6 @@
#include "design_utils.h"
#include "jsonparse.h"
#include "log.h"
-#include "pack.h"
#include "pcf.h"
#include "timing.h"
@@ -97,7 +96,7 @@ void Worker::pack()
{
Q_EMIT taskStarted();
try {
- bool res = pack_design(ctx);
+ bool res = ctx->pack();
print_utilisation(ctx);
Q_EMIT pack_finished(res);
} catch (WorkerInterruptionRequested) {
diff --git a/gui/line_editor.cc b/gui/line_editor.cc
index 9d9dac25..3c7ebe94 100644
--- a/gui/line_editor.cc
+++ b/gui/line_editor.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,12 +18,18 @@
*
*/
+#ifndef NO_PYTHON
+
#include "line_editor.h"
#include <QKeyEvent>
+#include <QToolTip>
+#include "ColumnFormatter.h"
+#include "Utils.h"
+#include "pyinterpreter.h"
NEXTPNR_NAMESPACE_BEGIN
-LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0)
+LineEditor::LineEditor(ParseHelper *helper, QWidget *parent) : QLineEdit(parent), index(0), parseHelper(helper)
{
setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &history", this);
@@ -38,10 +45,12 @@ LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0)
void LineEditor::keyPressEvent(QKeyEvent *ev)
{
+
if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) {
+ QToolTip::hideText();
if (lines.empty())
return;
-
+ printf("Key_Up\n");
if (ev->key() == Qt::Key_Up)
index--;
if (ev->key() == Qt::Key_Down)
@@ -56,12 +65,21 @@ void LineEditor::keyPressEvent(QKeyEvent *ev)
}
setText(lines[index]);
} else if (ev->key() == Qt::Key_Escape) {
+ QToolTip::hideText();
clear();
return;
+ } else if (ev->key() == Qt::Key_Tab) {
+ autocomplete();
+ return;
}
+ QToolTip::hideText();
+
QLineEdit::keyPressEvent(ev);
}
+// This makes TAB work
+bool LineEditor::focusNextPrevChild(bool next) { return false; }
+
void LineEditor::textInserted()
{
if (lines.empty() || lines.back() != text())
@@ -82,4 +100,36 @@ void LineEditor::clearHistory()
clear();
}
-NEXTPNR_NAMESPACE_END \ No newline at end of file
+void LineEditor::autocomplete()
+{
+ QString line = text();
+ const std::list<std::string> &suggestions = pyinterpreter_suggest(line.toStdString());
+ if (suggestions.size() == 1) {
+ line = suggestions.back().c_str();
+ } else {
+ // try to complete to longest common prefix
+ std::string prefix = LongestCommonPrefix(suggestions.begin(), suggestions.end());
+ if (prefix.size() > (size_t)line.size()) {
+ line = prefix.c_str();
+ } else {
+ ColumnFormatter fmt;
+ fmt.setItems(suggestions.begin(), suggestions.end());
+ fmt.format(width() / 5);
+ QString out = "";
+ for (auto &it : fmt.formattedOutput()) {
+ if (!out.isEmpty())
+ out += "\n";
+ out += it.c_str();
+ }
+ QToolTip::setFont(font());
+ if (!out.trimmed().isEmpty())
+ QToolTip::showText(mapToGlobal(QPoint(0, 0)), out);
+ }
+ }
+ // set up the next line on the console
+ setText(line);
+}
+
+NEXTPNR_NAMESPACE_END
+
+#endif // NO_PYTHON
diff --git a/gui/line_editor.h b/gui/line_editor.h
index 91837182..5a57129b 100644
--- a/gui/line_editor.h
+++ b/gui/line_editor.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,8 +21,11 @@
#ifndef LINE_EDITOR_H
#define LINE_EDITOR_H
+#ifndef NO_PYTHON
+
#include <QLineEdit>
#include <QMenu>
+#include "ParseHelper.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -31,7 +35,7 @@ class LineEditor : public QLineEdit
Q_OBJECT
public:
- explicit LineEditor(QWidget *parent = 0);
+ explicit LineEditor(ParseHelper *helper, QWidget *parent = 0);
private Q_SLOTS:
void textInserted();
@@ -43,13 +47,18 @@ class LineEditor : public QLineEdit
protected:
void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE;
+ bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE;
+ void autocomplete();
private:
int index;
QStringList lines;
QMenu *contextMenu;
+ ParseHelper *parseHelper;
};
NEXTPNR_NAMESPACE_END
+#endif // NO_PYTHON
+
#endif // LINE_EDITOR_H
diff --git a/gui/pyconsole.cc b/gui/pyconsole.cc
new file mode 100644
index 00000000..6da06b7e
--- /dev/null
+++ b/gui/pyconsole.cc
@@ -0,0 +1,82 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef NO_PYTHON
+
+#include "pyconsole.h"
+#include "pyinterpreter.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+const QColor PythonConsole::NORMAL_COLOR = QColor::fromRgbF(0, 0, 0);
+const QColor PythonConsole::ERROR_COLOR = QColor::fromRgbF(1.0, 0, 0);
+const QColor PythonConsole::OUTPUT_COLOR = QColor::fromRgbF(0, 0, 1.0);
+
+PythonConsole::PythonConsole(QWidget *parent) : QTextEdit(parent) {}
+
+void PythonConsole::parseEvent(const ParseMessage &message)
+{
+ // handle invalid user input
+ if (message.errorCode) {
+ setTextColor(ERROR_COLOR);
+ append(message.message.c_str());
+
+ setTextColor(NORMAL_COLOR);
+ append("");
+ return;
+ }
+ // interpret valid user input
+ int errorCode = 0;
+ std::string res;
+ if (message.message.size())
+ res = pyinterpreter_execute(message.message, &errorCode);
+ if (errorCode) {
+ setTextColor(ERROR_COLOR);
+ } else {
+ setTextColor(OUTPUT_COLOR);
+ }
+
+ if (res.size()) {
+ append(res.c_str());
+ }
+ setTextColor(NORMAL_COLOR);
+ append("");
+ moveCursorToEnd();
+}
+
+void PythonConsole::displayString(QString text)
+{
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ setTextColor(NORMAL_COLOR);
+ cursor.insertText(text);
+ cursor.movePosition(QTextCursor::EndOfLine);
+}
+
+void PythonConsole::moveCursorToEnd()
+{
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ setTextCursor(cursor);
+}
+
+NEXTPNR_NAMESPACE_END
+
+#endif // NO_PYTHON
diff --git a/ecp5/pack.h b/gui/pyconsole.h
index cc051a41..60f10672 100644
--- a/ecp5/pack.h
+++ b/gui/pyconsole.h
@@ -1,7 +1,8 @@
/*
* nextpnr -- Next Generation Place and Route
*
- * Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+ * Copyright (C) 2018 Alex Tsui
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,15 +18,41 @@
*
*/
-#ifndef PACK_H
-#define PACK_H
+#ifndef PYCONSOLE_H
+#define PYCONSOLE_H
+#ifndef NO_PYTHON
+
+#include <QColor>
+#include <QMimeData>
+#include <QTextEdit>
+#include "ParseHelper.h"
+#include "ParseListener.h"
#include "nextpnr.h"
+class QWidget;
+class QKeyEvent;
+
NEXTPNR_NAMESPACE_BEGIN
-bool pack_design(Context *ctx);
+class PythonConsole : public QTextEdit, public ParseListener
+{
+ Q_OBJECT
+
+ public:
+ PythonConsole(QWidget *parent = 0);
+
+ void displayString(QString text);
+ void moveCursorToEnd();
+ virtual void parseEvent(const ParseMessage &message);
+
+ protected:
+ static const QColor NORMAL_COLOR;
+ static const QColor ERROR_COLOR;
+ static const QColor OUTPUT_COLOR;
+};
NEXTPNR_NAMESPACE_END
+#endif // NO_PYTHON
-#endif // ROUTE_H
+#endif // PYCONSOLE_H
diff --git a/gui/pythontab.cc b/gui/pythontab.cc
index 897f87b3..5c349d7c 100644
--- a/gui/pythontab.cc
+++ b/gui/pythontab.cc
@@ -25,12 +25,20 @@
NEXTPNR_NAMESPACE_BEGIN
+const QString PythonTab::PROMPT = ">>> ";
+const QString PythonTab::MULTILINE_PROMPT = "... ";
+
PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
{
+ QFont f("unexistent");
+ f.setStyleHint(QFont::Monospace);
+
// Add text area for Python output and input line
console = new PythonConsole();
console->setMinimumHeight(100);
- console->setEnabled(false);
+ console->setReadOnly(true);
+ console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ console->setFont(f);
console->setContextMenuPolicy(Qt::CustomContextMenu);
QAction *clearAction = new QAction("Clear &buffer", this);
@@ -41,9 +49,21 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
contextMenu->addAction(clearAction);
connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
+ lineEdit = new LineEditor(&parseHelper);
+ lineEdit->setMinimumHeight(30);
+ lineEdit->setMaximumHeight(30);
+ lineEdit->setFont(f);
+ lineEdit->setPlaceholderText(PythonTab::PROMPT);
+ connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString)));
+
QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(console, 0, 0);
+ mainLayout->addWidget(lineEdit, 1, 0);
setLayout(mainLayout);
+
+ parseHelper.subscribe(console);
+
+ prompt = PythonTab::PROMPT;
}
PythonTab::~PythonTab()
@@ -54,13 +74,27 @@ PythonTab::~PythonTab()
}
}
+void PythonTab::editLineReturnPressed(QString text)
+{
+ console->displayString(prompt + text + "\n");
+ console->moveCursorToEnd();
+
+ parseHelper.process(text.toStdString());
+
+ if (parseHelper.buffered())
+ prompt = PythonTab::MULTILINE_PROMPT;
+ else
+ prompt = PythonTab::PROMPT;
+
+ lineEdit->setPlaceholderText(prompt);
+}
+
void PythonTab::newContext(Context *ctx)
{
if (initialized) {
pyinterpreter_finalize();
deinit_python();
}
- console->setEnabled(true);
console->clear();
pyinterpreter_preinit();
@@ -74,7 +108,6 @@ void PythonTab::newContext(Context *ctx)
QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform());
console->displayString(version);
- console->displayPrompt();
}
void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
@@ -83,4 +116,4 @@ void PythonTab::clearBuffer() { console->clear(); }
NEXTPNR_NAMESPACE_END
-#endif \ No newline at end of file
+#endif // NO_PYTHON
diff --git a/gui/pythontab.h b/gui/pythontab.h
index 4b22e6a9..3fd12981 100644
--- a/gui/pythontab.h
+++ b/gui/pythontab.h
@@ -25,6 +25,7 @@
#include <QLineEdit>
#include <QMenu>
#include <QPlainTextEdit>
+#include "ParseHelper.h"
#include "line_editor.h"
#include "nextpnr.h"
#include "pyconsole.h"
@@ -42,13 +43,20 @@ class PythonTab : public QWidget
private Q_SLOTS:
void showContextMenu(const QPoint &pt);
void clearBuffer();
+ void editLineReturnPressed(QString text);
public Q_SLOTS:
void newContext(Context *ctx);
private:
PythonConsole *console;
+ LineEditor *lineEdit;
QMenu *contextMenu;
bool initialized;
+ ParseHelper parseHelper;
+ QString prompt;
+
+ static const QString PROMPT;
+ static const QString MULTILINE_PROMPT;
};
NEXTPNR_NAMESPACE_END
diff --git a/ice40/arch.cc b/ice40/arch.cc
index 7c6af263..af31e147 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -494,6 +494,7 @@ DecalXY Arch::getFrameDecal() const
{
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_FRAME;
+ decalxy.decal.active = true;
return decalxy;
}
@@ -502,6 +503,7 @@ DecalXY Arch::getBelDecal(BelId bel) const
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_BEL;
decalxy.decal.index = bel.index;
+ decalxy.decal.active = bel_to_cell.at(bel.index) != IdString();
return decalxy;
}
@@ -510,18 +512,25 @@ DecalXY Arch::getWireDecal(WireId wire) const
DecalXY decalxy;
decalxy.decal.type = DecalId::TYPE_WIRE;
decalxy.decal.index = wire.index;
+ decalxy.decal.active = wire_to_net.at(wire.index) != IdString();
return decalxy;
}
DecalXY Arch::getPipDecal(PipId pip) const
{
DecalXY decalxy;
+ decalxy.decal.type = DecalId::TYPE_PIP;
+ decalxy.decal.index = pip.index;
+ decalxy.decal.active = pip_to_net.at(pip.index) != IdString();
return decalxy;
};
DecalXY Arch::getGroupDecal(GroupId group) const
{
DecalXY decalxy;
+ decalxy.decal.type = DecalId::TYPE_GROUP;
+ decalxy.decal.index = (group.type << 16) | (group.x << 8) | (group.y);
+ decalxy.decal.active = true;
return decalxy;
};
@@ -549,8 +558,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
int n = chip_info->wire_data[wire.index].num_segments;
const WireSegmentPOD *p = chip_info->wire_data[wire.index].segments.get();
- GraphicElement::style_t style =
- wire_to_net.at(wire.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
+ GraphicElement::style_t style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
for (int i = 0; i < n; i++)
gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style);
@@ -565,7 +573,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
if (bel_type == TYPE_ICESTORM_LC) {
GraphicElement el;
el.type = GraphicElement::G_BOX;
- el.style = bel_to_cell.at(bel.index) != IdString() ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
+ el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2;
el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 +
@@ -635,14 +643,42 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
}
if (bel_type == TYPE_ICESTORM_RAM) {
- GraphicElement el;
- el.type = GraphicElement::G_BOX;
- el.x1 = chip_info->bel_data[bel.index].x + 0.1;
- el.x2 = chip_info->bel_data[bel.index].x + 0.9;
- el.y1 = chip_info->bel_data[bel.index].y + 0.1;
- el.y2 = chip_info->bel_data[bel.index].y + 1.9;
- el.z = 0;
- ret.push_back(el);
+ for (int i = 0; i < 2; i++)
+ {
+ int tx = chip_info->bel_data[bel.index].x;
+ int ty = chip_info->bel_data[bel.index].y + i;
+
+ GraphicElement el;
+ el.type = GraphicElement::G_BOX;
+ el.style = decal.active ? GraphicElement::G_ACTIVE : GraphicElement::G_INACTIVE;
+ el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1;
+ el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2;
+ el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1;
+ el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch;
+ el.z = 0;
+ ret.push_back(el);
+
+ // Main switchbox
+ GraphicElement main_sw;
+ main_sw.type = GraphicElement::G_BOX;
+ main_sw.style = GraphicElement::G_FRAME;
+ main_sw.x1 = tx + main_swbox_x1;
+ main_sw.x2 = tx + main_swbox_x2;
+ main_sw.y1 = ty + main_swbox_y1;
+ main_sw.y2 = ty + main_swbox_y2;
+ ret.push_back(main_sw);
+
+ // Local tracks to LUT input switchbox
+ GraphicElement local_sw;
+ local_sw.type = GraphicElement::G_BOX;
+ local_sw.style = GraphicElement::G_FRAME;
+ local_sw.x1 = tx + local_swbox_x1;
+ local_sw.x2 = tx + local_swbox_x2;
+ local_sw.y1 = ty + local_swbox_y1;
+ local_sw.y2 = ty + local_swbox_y2;
+ local_sw.z = 0;
+ ret.push_back(local_sw);
+ }
}
}
@@ -822,16 +858,6 @@ BelId ArchRProxyMethods::getBelByName(IdString name) const
// -----------------------------------------------------------------------
-void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength)
-{
- NPNR_ASSERT(wire != WireId());
- NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString());
-
- parent_->wire_to_net[wire.index] = net;
- parent_->nets[net]->wires[wire].pip = PipId();
- parent_->nets[net]->wires[wire].strength = strength;
-}
-
void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength)
{
NPNR_ASSERT(bel != BelId());
@@ -839,6 +865,7 @@ void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strengt
parent_->bel_to_cell[bel.index] = cell;
parent_->cells[cell]->bel = bel;
parent_->cells[cell]->belStrength = strength;
+ parent_->refreshUiBel(bel);
}
void ArchRWProxyMethods::unbindBel(BelId bel)
@@ -848,6 +875,18 @@ void ArchRWProxyMethods::unbindBel(BelId bel)
parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId();
parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
parent_->bel_to_cell[bel.index] = IdString();
+ parent_->refreshUiBel(bel);
+}
+
+void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength)
+{
+ NPNR_ASSERT(wire != WireId());
+ NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString());
+
+ parent_->wire_to_net[wire.index] = net;
+ parent_->nets[net]->wires[wire].pip = PipId();
+ parent_->nets[net]->wires[wire].strength = strength;
+ parent_->refreshUiWire(wire);
}
void ArchRWProxyMethods::unbindWire(WireId wire)
@@ -863,10 +902,12 @@ void ArchRWProxyMethods::unbindWire(WireId wire)
if (pip != PipId()) {
parent_->pip_to_net[pip.index] = IdString();
parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
+ parent_->refreshUiPip(pip);
}
net_wires.erase(it);
parent_->wire_to_net[wire.index] = IdString();
+ parent_->refreshUiWire(wire);
}
void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength)
@@ -884,6 +925,9 @@ void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength
parent_->wire_to_net[dst.index] = net;
parent_->nets[net]->wires[dst].pip = pip;
parent_->nets[net]->wires[dst].strength = strength;
+
+ parent_->refreshUiPip(pip);
+ parent_->refreshUiWire(dst);
}
void ArchRWProxyMethods::unbindPip(PipId pip)
@@ -900,6 +944,9 @@ void ArchRWProxyMethods::unbindPip(PipId pip)
parent_->pip_to_net[pip.index] = IdString();
parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
+
+ parent_->refreshUiPip(pip);
+ parent_->refreshUiWire(dst);
}
CellInfo *ArchRWProxyMethods::getCell(IdString cell)
diff --git a/ice40/arch.h b/ice40/arch.h
index 4462ce9e..36e34d7b 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -477,21 +477,6 @@ public:
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
-
- WireRange getWires() const
- {
- WireRange range;
- range.b.cursor = 0;
- range.e.cursor = chip_info->num_wires;
- return range;
- }
-
- // -------------------------------------------------
-
- IdString getPipName(PipId pip) const;
-
- uint32_t getPipChecksum(PipId pip) const { return pip.index; }
-
AllPipRange getPips() const
{
AllPipRange range;
@@ -499,6 +484,10 @@ public:
range.e.cursor = chip_info->num_pips;
return range;
}
+
+ IdString getPipName(PipId pip) const;
+
+ uint32_t getPipChecksum(PipId pip) const { return pip.index; }
WireId getPipSrcWire(PipId pip) const
{
@@ -551,6 +540,15 @@ public:
return range;
}
+ WireRange getWires() const
+ {
+ WireRange range;
+ range.b.cursor = 0;
+ range.e.cursor = chip_info->num_wires;
+ return range;
+ }
+
+
BelId getPackagePinBel(const std::string &pin) const;
std::string getBelPackagePin(BelId bel) const;
@@ -575,6 +573,7 @@ public:
// -------------------------------------------------
+ bool pack();
bool place();
bool route();
diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc
index ac8c189a..fd5109b4 100644
--- a/ice40/arch_pybindings.cc
+++ b/ice40/arch_pybindings.cc
@@ -58,7 +58,10 @@ void arch_wrap_python()
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
- .def("checksum", &Context::checksum);
+ .def("checksum", &Context::checksum)
+ .def("pack", &Context::pack)
+ .def("place", &Context::place)
+ .def("route", &Context::route);
fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>,
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType");
diff --git a/ice40/archdefs.h b/ice40/archdefs.h
index 3252dabf..75df678a 100644
--- a/ice40/archdefs.h
+++ b/ice40/archdefs.h
@@ -21,7 +21,7 @@
#error Include "archdefs.h" via "nextpnr.h" only.
#endif
-#include <boost/functional/hash_fwd.hpp>
+#include <boost/functional/hash.hpp>
NEXTPNR_NAMESPACE_BEGIN
@@ -144,6 +144,7 @@ struct DecalId
TYPE_GROUP
} type = TYPE_NONE;
int32_t index = -1;
+ bool active = false;
bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); }
bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); }
diff --git a/ice40/chipdb.py b/ice40/chipdb.py
index f52a2283..51fe169c 100644
--- a/ice40/chipdb.py
+++ b/ice40/chipdb.py
@@ -77,7 +77,7 @@ with open(args.gfxh) as f:
state = 1
elif state == 1 and line.startswith("};"):
state = 0
- elif state == 1 and line.startswith("{"):
+ elif state == 1 and (line.startswith("{") or line.strip() == ""):
pass
elif state == 1:
idx = len(gfx_wire_ids)
diff --git a/ice40/gfx.cc b/ice40/gfx.cc
index f4941750..19aaed13 100644
--- a/ice40/gfx.cc
+++ b/ice40/gfx.cc
@@ -31,17 +31,31 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) {
int idx = (id - TILE_WIRE_SP4_H_L_36) + 48;
- float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx));
- el.x1 = x + 0.0;
- el.x2 = x + 0.9;
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1)));
+ float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - idx));
+
+ el.x1 = x;
+ el.x2 = x + 0.01;
el.y1 = y1;
el.y2 = y1;
g.push_back(el);
+ el.x1 = x + 0.01;
+ el.x2 = x + 0.02;
+ el.y1 = y1;
+ el.y2 = y2;
+ g.push_back(el);
+
+ el.x1 = x + 0.02;
+ el.x2 = x + 0.9;
+ el.y1 = y2;
+ el.y2 = y2;
+ g.push_back(el);
+
el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 35);
el.x2 = el.x1;
- el.y1 = y1;
+ el.y1 = y2;
el.y2 = y + main_swbox_y2;
g.push_back(el);
}
@@ -91,17 +105,30 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) {
int idx = (id - TILE_WIRE_SP4_V_T_36) + 48;
- float x1 = x + 0.03 + 0.0025 * (60 - idx);
+ float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1));
+ float x2 = x + 0.03 + 0.0025 * (60 - idx);
- el.y1 = y + 1.0;
- el.y2 = y + 0.1;
+ el.y1 = y + 1.00;
+ el.y2 = y + 0.99;
el.x1 = x1;
el.x2 = x1;
g.push_back(el);
+ el.y1 = y + 0.99;
+ el.y2 = y + 0.98;
+ el.x1 = x1;
+ el.x2 = x2;
+ g.push_back(el);
+
+ el.y1 = y + 0.98;
+ el.y2 = y + 0.10;
+ el.x1 = x2;
+ el.x2 = x2;
+ g.push_back(el);
+
el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx));
el.y2 = el.y1;
- el.x1 = x1;
+ el.x1 = x2;
el.x2 = x + main_swbox_x1;
g.push_back(el);
}
@@ -109,9 +136,9 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) {
int idx = id - TILE_WIRE_SP4_V_B_0;
- float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1));
- float x2 = x + 0.03 + 0.0025 * (60 - idx);
- float x3 = x + 0.03 + 0.0025 * (60 - idx - 12);
+ float x1 = x + 0.03 + 0.0025 * (60 - idx);
+ float x2 = x + 0.03 + 0.0025 * (60 - (idx ^ 1));
+ float x3 = x + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12);
if (idx >= 12) {
el.y1 = y + 1.00;
@@ -139,13 +166,13 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
el.x2 = x3;
g.push_back(el);
- el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx));
+ el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1)));
el.y2 = el.y1;
el.x1 = x;
el.x2 = x2;
g.push_back(el);
- el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx));
+ el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
el.y2 = el.y1;
el.x1 = x2;
el.x2 = x + main_swbox_x1;
@@ -157,17 +184,30 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) {
int idx = (id - TILE_WIRE_SP12_H_L_22) + 24;
- float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx));
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1)));
+ float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx));
- el.x1 = x + 0.0;
- el.x2 = x + 0.98333;
+ el.x1 = x;
+ el.x2 = x + 0.01;
el.y1 = y1;
el.y2 = y1;
g.push_back(el);
+ el.x1 = x + 0.01;
+ el.x2 = x + 0.02;
+ el.y1 = y1;
+ el.y2 = y2;
+ g.push_back(el);
+
+ el.x1 = x + 0.02;
+ el.x2 = x + 0.98333;
+ el.y1 = y2;
+ el.y2 = y2;
+ g.push_back(el);
+
el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5);
el.x2 = el.x1;
- el.y1 = y1;
+ el.y1 = y2;
el.y2 = y + main_swbox_y2;
g.push_back(el);
}
@@ -175,9 +215,9 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) {
int idx = id - TILE_WIRE_SP12_H_R_0;
- float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1)));
- float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx));
- float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - idx - 2));
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx));
+ float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1)));
+ float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1) - 2));
if (idx >= 2) {
el.x1 = x;
@@ -205,7 +245,7 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
el.y2 = y3;
g.push_back(el);
- el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5);
+ el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
el.x2 = el.x1;
el.y1 = y2;
el.y2 = y + main_swbox_y2;
@@ -217,7 +257,7 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) {
int idx = id - TILE_WIRE_SP4_R_V_B_0;
- float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - idx));
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1)));
el.y1 = y1;
el.y2 = y1;
@@ -231,17 +271,30 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) {
int idx = (id - TILE_WIRE_SP12_V_T_22) + 24;
- float x1 = x + 0.03 + 0.0025 * (90 - idx);
+ float x1 = x + 0.03 + 0.0025 * (90 - (idx ^ 1));
+ float x2 = x + 0.03 + 0.0025 * (90 - idx);
el.y1 = y + 1.00;
- el.y2 = y + 0.01667;
+ el.y2 = y + 0.99;
el.x1 = x1;
el.x2 = x1;
g.push_back(el);
+ el.y1 = y + 0.99;
+ el.y2 = y + 0.98;
+ el.x1 = x1;
+ el.x2 = x2;
+ g.push_back(el);
+
+ el.y1 = y + 0.98;
+ el.y2 = y + 0.01667;
+ el.x1 = x2;
+ el.x2 = x2;
+ g.push_back(el);
+
el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - idx));
el.y2 = el.y1;
- el.x1 = x1;
+ el.x1 = x2;
el.x2 = x + main_swbox_x1;
g.push_back(el);
}
diff --git a/ice40/main.cc b/ice40/main.cc
index 53cd7164..e77bdd34 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -39,7 +39,6 @@
#include "jsonparse.h"
#include "log.h"
#include "nextpnr.h"
-#include "pack.h"
#include "pcf.h"
#include "place_legaliser.h"
#include "timing.h"
@@ -382,7 +381,7 @@ int main(int argc, char *argv[])
log_error("Loading PCF failed.\n");
}
- if (!pack_design(ctx.get()) && !ctx->force)
+ if (!ctx->pack() && !ctx->force)
log_error("Packing design failed.\n");
assign_budget(ctx.get());
ctx->check();
diff --git a/ice40/pack.cc b/ice40/pack.cc
index d1be4a29..76a52be0 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -18,7 +18,6 @@
*
*/
-#include "pack.h"
#include <algorithm>
#include <iterator>
#include <unordered_set>
@@ -577,8 +576,9 @@ static void pack_special(Context *ctx)
}
// Main pack function
-bool pack_design(Context *ctx)
+bool Arch::pack()
{
+ Context *ctx = getCtx();
try {
log_break();
pack_constants(ctx);
diff --git a/ice40/pack.h b/ice40/pack.h
deleted file mode 100644
index cdebdd79..00000000
--- a/ice40/pack.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * nextpnr -- Next Generation Place and Route
- *
- * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
- * Copyright (C) 2018 David Shah <david@symbioticeda.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#ifndef PACK_H
-#define PACK_H
-
-#include "nextpnr.h"
-
-NEXTPNR_NAMESPACE_BEGIN
-
-bool pack_design(Context *ctx);
-
-NEXTPNR_NAMESPACE_END
-
-#endif // ROUTE_H