Merge github.com:YosysHQ/nextpnr into xc7

This commit is contained in:
Eddie Hung 2018-09-03 13:18:06 -07:00
commit 001806f317
50 changed files with 1810 additions and 176 deletions

2
.gitignore vendored
View File

@ -28,3 +28,5 @@ CTestTestfile.cmake
install_manifest.txt install_manifest.txt
/bbasm /bbasm
/ImportExecutables.cmake /ImportExecutables.cmake
*-coverage/
*-coverage.info

View File

@ -82,6 +82,7 @@ public:
void slotCollapsed(const QModelIndex &index); void slotCollapsed(const QModelIndex &index);
void slotExpanded(const QModelIndex &index); void slotExpanded(const QModelIndex &index);
void onHoverPropertyChanged(QtBrowserItem *item);
QColor calculatedBackgroundColor(QtBrowserItem *item) const; QColor calculatedBackgroundColor(QtBrowserItem *item) const;
@ -129,12 +130,17 @@ public:
{ return itemFromIndex(index); } { return itemFromIndex(index); }
protected: protected:
void mouseMoveEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *event) override;
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
Q_SIGNALS:
void hoverPropertyChanged(QtBrowserItem *item);
private: private:
QtTreePropertyBrowserPrivate *m_editorPrivate; QtTreePropertyBrowserPrivate *m_editorPrivate;
QModelIndex current;
}; };
QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) : QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
@ -172,6 +178,21 @@ void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem
painter->restore(); painter->restore();
} }
void QtPropertyEditorView::mouseMoveEvent(QMouseEvent *event)
{
QModelIndex index = indexAt(event->pos());
if (index!=current) {
current = index;
Q_EMIT hoverPropertyChanged(m_editorPrivate->indexToBrowserItem(index));
}
QTreeWidget::mouseMoveEvent(event);
}
void QtPropertyEditorView::leaveEvent(QEvent *event)
{
Q_EMIT hoverPropertyChanged(nullptr);
}
void QtPropertyEditorView::keyPressEvent(QKeyEvent *event) void QtPropertyEditorView::keyPressEvent(QKeyEvent *event)
{ {
switch (event->key()) { switch (event->key()) {
@ -489,6 +510,7 @@ void QtTreePropertyBrowserPrivate::init(QWidget *parent)
QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &)));
QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &)));
QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
QObject::connect(m_treeWidget, SIGNAL(hoverPropertyChanged(QtBrowserItem *)), q_ptr, SLOT(onHoverPropertyChanged(QtBrowserItem *)));
} }
QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
@ -688,6 +710,12 @@ void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
emit q_ptr->expanded(idx); emit q_ptr->expanded(idx);
} }
void QtTreePropertyBrowserPrivate::onHoverPropertyChanged(QtBrowserItem *item)
{
emit q_ptr->hoverPropertyChanged(item);
}
void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item) void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
{ {
if (!m_browserChangedBlocked && item != currentItem()) if (!m_browserChangedBlocked && item != currentItem())

View File

@ -115,7 +115,7 @@ Q_SIGNALS:
void collapsed(QtBrowserItem *item); void collapsed(QtBrowserItem *item);
void expanded(QtBrowserItem *item); void expanded(QtBrowserItem *item);
void hoverPropertyChanged(QtBrowserItem *item);
protected: protected:
virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem);
virtual void itemRemoved(QtBrowserItem *item); virtual void itemRemoved(QtBrowserItem *item);
@ -131,6 +131,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &))
Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *)) Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *))
Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)) Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *))
Q_PRIVATE_SLOT(d_func(), void onHoverPropertyChanged(QtBrowserItem *))
}; };

View File

@ -5,6 +5,16 @@ project(nextpnr)
option(BUILD_GUI "Build GUI" ON) option(BUILD_GUI "Build GUI" ON)
option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_PYTHON "Build Python Integration" ON)
option(BUILD_TESTS "Build GUI" OFF) option(BUILD_TESTS "Build GUI" OFF)
option(COVERAGE "Add code coverage info" OFF)
option(STATIC_BUILD "Create static build" OFF)
set(link_param "")
if (STATIC_BUILD)
set(Boost_USE_STATIC_LIBS ON)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(link_param "-static")
endif()
endif()
# List of families to build # List of families to build
set(FAMILIES generic ice40 ecp5 xc7) set(FAMILIES generic ice40 ecp5 xc7)
@ -43,7 +53,11 @@ set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g")
endif() endif()
set(CMAKE_DEFIN) set(CMAKE_DEFIN)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/sanitizers-cmake/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/sanitizers-cmake/cmake;." ${CMAKE_MODULE_PATH})
if (COVERAGE)
include(CodeCoverage)
endif()
if(NOT DEFINED CMAKE_SUPPRESS_DEVELOPER_WARNINGS) if(NOT DEFINED CMAKE_SUPPRESS_DEVELOPER_WARNINGS)
set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings") set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings")
@ -185,6 +199,16 @@ foreach (family ${ARCH})
# Add any new per-architecture targets here # Add any new per-architecture targets here
if (BUILD_TESTS) if (BUILD_TESTS)
if (COVERAGE)
APPEND_COVERAGE_COMPILER_FLAGS()
set(COVERAGE_LCOV_EXCLUDES '/usr/include/*' '3rdparty/*' 'generated/*' 'bba/*' 'tests/*')
SETUP_TARGET_FOR_COVERAGE_LCOV(
NAME ${family}-coverage
EXECUTABLE nextpnr-${family}-test
DEPENDENCIES nextpnr-${family}-test
)
endif()
aux_source_directory(tests/${family}/ ${ufamily}_TEST_FILES) aux_source_directory(tests/${family}/ ${ufamily}_TEST_FILES)
if (BUILD_GUI) if (BUILD_GUI)
aux_source_directory(tests/gui/ GUI_TEST_FILES) aux_source_directory(tests/gui/ GUI_TEST_FILES)
@ -211,7 +235,7 @@ foreach (family ${ARCH})
# Include family-specific source files to all family targets and set defines appropriately # Include family-specific source files to all family targets and set defines appropriately
target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/) target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/)
target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family}) target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family})
target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES}) target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} ${link_param})
if (NOT MSVC) if (NOT MSVC)
target_link_libraries(${target} LINK_PUBLIC pthread) target_link_libraries(${target} LINK_PUBLIC pthread)
endif() endif()

303
CodeCoverage.cmake Normal file
View File

@ -0,0 +1,303 @@
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt:
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# APPEND_COVERAGE_COMPILER_FLAGS()
#
# 4. If you need to exclude additional directories from the report, specify them
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
# Example:
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( SIMPLE_PYTHON_EXECUTABLE python )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_LCOV(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup lcov
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
# Create baseline to make sure untouched files show up in the report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
# Run tests
COMMAND ${Coverage_EXECUTABLE}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
# add baseline counters
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Running gcovr
COMMAND ${GCOVR_PATH} --xml
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Create folder
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
# Running gcovr
COMMAND ${GCOVR_PATH} --html --html-details
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
function(APPEND_COVERAGE_COMPILER_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS

View File

@ -127,6 +127,13 @@ cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -
make -j$(nproc) make -j$(nproc)
``` ```
To make static build relase for iCE40 architecture use the following:
```
cmake -DARCH=ice40 -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -DSTATIC_BUILD=ON .
make -j$(nproc)
```
Notes for developers Notes for developers
-------------------- --------------------
@ -145,6 +152,9 @@ Testing
- `-DSANITIZE_THREAD=ON` - `-DSANITIZE_THREAD=ON`
- `-DSANITIZE_UNDEFINED=ON` - `-DSANITIZE_UNDEFINED=ON`
- Running valgrind example `valgrind --leak-check=yes --tool=memcheck ./nextpnr-ice40 --json ice40/blinky.json` - Running valgrind example `valgrind --leak-check=yes --tool=memcheck ./nextpnr-ice40 --json ice40/blinky.json`
- Running tests with code coverage use `-DBUILD_TESTS=ON -DCOVERAGE` and after `make` run `make ice40-coverage`
- After that open `ice40-coverage/index.html` in your browser to view the coverage report
- Note that `lcov` is needed in order to generate reports
Links and references Links and references
-------------------- --------------------
@ -167,6 +177,6 @@ Links and references
- [Arachne PNR](https://github.com/cseed/arachne-pnr) - [Arachne PNR](https://github.com/cseed/arachne-pnr)
- [VPR/VTR](https://verilogtorouting.org/) - [VPR/VTR](https://verilogtorouting.org/)
- [SymbiFlow](https://github.com/SymbiFlow/symbiflow-arch-defs) - [SymbiFlow](https://github.com/SymbiFlow/symbiflow-arch-defs)
- [Gaffe](https://github.com/kc8apf/gaffe) - [Gaffe](https://github.com/gaffe-logic/gaffe)
- [KinglerPAR](https://github.com/rqou/KinglerPAR) - [KinglerPAR](https://github.com/rqou/KinglerPAR)

View File

@ -144,7 +144,7 @@ void CommandHandler::setupContext(Context *ctx)
} }
if (vm.count("cstrweight")) { if (vm.count("cstrweight")) {
// ctx->placer_constraintWeight = vm["cstrweight"].as<float>(); settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
} }
if (vm.count("freq")) { if (vm.count("freq")) {
@ -261,6 +261,7 @@ int CommandHandler::exec()
} else { } else {
ctx = createContext(); ctx = createContext();
} }
settings = std::unique_ptr<Settings>(new Settings(ctx.get()));
setupContext(ctx.get()); setupContext(ctx.get());
setupArchContext(ctx.get()); setupArchContext(ctx.get());
return executeMain(std::move(ctx)); return executeMain(std::move(ctx));

View File

@ -24,6 +24,7 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include "nextpnr.h" #include "nextpnr.h"
#include "project.h" #include "project.h"
#include "settings.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
@ -56,6 +57,7 @@ class CommandHandler
protected: protected:
po::variables_map vm; po::variables_map vm;
ArchArgs chipArgs; ArchArgs chipArgs;
std::unique_ptr<Settings> settings;
private: private:
po::options_description options; po::options_description options;

View File

@ -46,6 +46,18 @@ void (*log_error_atexit)() = NULL;
// static bool next_print_log = false; // static bool next_print_log = false;
static int log_newline_count = 0; static int log_newline_count = 0;
std::string stringf(const char *fmt, ...)
{
std::string string;
va_list ap;
va_start(ap, fmt);
string = vstringf(fmt, ap);
va_end(ap);
return string;
}
std::string vstringf(const char *fmt, va_list ap) std::string vstringf(const char *fmt, va_list ap)
{ {
std::string string; std::string string;

View File

@ -51,6 +51,9 @@ extern bool log_quiet_warnings;
extern std::string log_last_error; extern std::string log_last_error;
extern void (*log_error_atexit)(); extern void (*log_error_atexit)();
std::string stringf(const char *fmt, ...);
std::string vstringf(const char *fmt, va_list ap);
extern std::ostream clog; extern std::ostream clog;
void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2)); void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));

View File

@ -23,6 +23,7 @@
#include "placer1.h" #include "placer1.h"
#include <algorithm> #include <algorithm>
#include <boost/lexical_cast.hpp>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
@ -108,14 +109,12 @@ class SAPlacer
if (bel_type != cell->type) { if (bel_type != cell->type) {
log_error("Bel \'%s\' of type \'%s\' does not match cell " log_error("Bel \'%s\' of type \'%s\' does not match cell "
"\'%s\' of type \'%s\'\n", "\'%s\' of type \'%s\'\n",
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
cell->type.c_str(ctx));
} }
if (!ctx->isValidBelForCell(cell, bel)) { if (!ctx->isValidBelForCell(cell, bel)) {
log_error("Bel \'%s\' of type \'%s\' is not valid for cell " log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
"\'%s\' of type \'%s\'\n", "\'%s\' of type \'%s\'\n",
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
cell->type.c_str(ctx));
} }
ctx->bindBel(bel, cell, STRENGTH_USER); ctx->bindBel(bel, cell, STRENGTH_USER);
@ -492,6 +491,8 @@ class SAPlacer
std::vector<decltype(NetInfo::udata)> old_udata; std::vector<decltype(NetInfo::udata)> old_udata;
}; };
Placer1Cfg::Placer1Cfg(Context *ctx) : Settings(ctx) { constraintWeight = get<float>("placer1/constraintWeight", 10); }
bool placer1(Context *ctx, Placer1Cfg cfg) bool placer1(Context *ctx, Placer1Cfg cfg)
{ {
try { try {

View File

@ -20,12 +20,14 @@
#define PLACE_H #define PLACE_H
#include "nextpnr.h" #include "nextpnr.h"
#include "settings.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
struct Placer1Cfg struct Placer1Cfg : public Settings
{ {
float constraintWeight = 10; Placer1Cfg(Context *ctx);
float constraintWeight;
}; };
extern bool placer1(Context *ctx, Placer1Cfg cfg); extern bool placer1(Context *ctx, Placer1Cfg cfg);

View File

@ -18,6 +18,7 @@
*/ */
#include "project.h" #include "project.h"
#include <algorithm>
#include <boost/filesystem/convenience.hpp> #include <boost/filesystem/convenience.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <fstream> #include <fstream>
@ -64,17 +65,36 @@ void ProjectHandler::save(Context *ctx, std::string filename)
root.put("project.name", boost::filesystem::basename(filename)); root.put("project.name", boost::filesystem::basename(filename));
root.put("project.arch.name", ctx->archId().c_str(ctx)); root.put("project.arch.name", ctx->archId().c_str(ctx));
root.put("project.arch.type", ctx->archArgsToId(ctx->archArgs()).c_str(ctx)); root.put("project.arch.type", ctx->archArgsToId(ctx->archArgs()).c_str(ctx));
std::string fn = ctx->settings[ctx->id("project/input/json")]; std::string fn = ctx->settings[ctx->id("input/json")];
root.put("project.input.json", make_relative(fn, proj.parent_path()).string()); root.put("project.input.json", make_relative(fn, proj.parent_path()).string());
root.put("project.params.freq", int(ctx->target_freq / 1e6)); root.put("project.params.freq", int(ctx->target_freq / 1e6));
root.put("project.params.seed", ctx->rngstate); root.put("project.params.seed", ctx->rngstate);
saveArch(ctx, root, proj.parent_path().string()); saveArch(ctx, root, proj.parent_path().string());
for (auto const &item : ctx->settings) {
std::string path = "project.settings.";
path += item.first.c_str(ctx);
std::replace(path.begin(), path.end(), '/', '.');
root.put(path, item.second);
}
pt::write_json(f, root); pt::write_json(f, root);
} catch (...) { } catch (...) {
log_error("Error saving project file.\n"); log_error("Error saving project file.\n");
} }
} }
void addSettings(Context *ctx, std::string path, pt::ptree sub)
{
for (pt::ptree::value_type &v : sub) {
const std::string &key = v.first;
const boost::property_tree::ptree &subtree = v.second;
if (subtree.empty()) {
ctx->settings.emplace(ctx->id(path + key), subtree.get_value<std::string>().c_str());
} else {
addSettings(ctx, path + key + "/", subtree);
}
}
}
std::unique_ptr<Context> ProjectHandler::load(std::string filename) std::unique_ptr<Context> ProjectHandler::load(std::string filename)
{ {
std::unique_ptr<Context> ctx; std::unique_ptr<Context> ctx;
@ -110,6 +130,10 @@ std::unique_ptr<Context> ProjectHandler::load(std::string filename)
if (params.count("seed")) if (params.count("seed"))
ctx->rngseed(params.get<uint64_t>("seed")); ctx->rngseed(params.get<uint64_t>("seed"));
} }
if (project.count("settings")) {
addSettings(ctx.get(), "", project.get_child("settings"));
}
loadArch(ctx.get(), root, proj.parent_path().string()); loadArch(ctx.get(), root, proj.parent_path().string());
} catch (...) { } catch (...) {
log_error("Error loading project file.\n"); log_error("Error loading project file.\n");

View File

@ -682,6 +682,14 @@ void cleanupReroute(Context *ctx, const Router1Cfg &cfg, RipupScoreboard &scores
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
Router1Cfg::Router1Cfg(Context *ctx) : Settings(ctx)
{
maxIterCnt = get<int>("router1/maxIterCnt", 200);
cleanupReroute = get<bool>("router1/cleanupReroute", true);
fullCleanupReroute = get<bool>("router1/fullCleanupReroute", true);
useEstimate = get<bool>("router1/useEstimate", true);
}
bool router1(Context *ctx, const Router1Cfg &cfg) bool router1(Context *ctx, const Router1Cfg &cfg)
{ {
try { try {
@ -953,7 +961,7 @@ bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *del
std::unordered_map<WireId, PipId> *route, bool useEstimate) std::unordered_map<WireId, PipId> *route, bool useEstimate)
{ {
RipupScoreboard scores; RipupScoreboard scores;
Router1Cfg cfg; Router1Cfg cfg(this);
cfg.useEstimate = useEstimate; cfg.useEstimate = useEstimate;
Router router(this, cfg, scores, src_wire, dst_wire); Router router(this, cfg, scores, src_wire, dst_wire);

View File

@ -21,15 +21,18 @@
#define ROUTER1_H #define ROUTER1_H
#include "nextpnr.h" #include "nextpnr.h"
#include "settings.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
struct Router1Cfg struct Router1Cfg : Settings
{ {
int maxIterCnt = 200; Router1Cfg(Context *ctx);
bool cleanupReroute = true;
bool fullCleanupReroute = true; int maxIterCnt;
bool useEstimate = true; bool cleanupReroute;
bool fullCleanupReroute;
bool useEstimate;
}; };
extern bool router1(Context *ctx, const Router1Cfg &cfg); extern bool router1(Context *ctx, const Router1Cfg &cfg);

63
common/settings.h Normal file
View File

@ -0,0 +1,63 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@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 SETTINGS_H
#define SETTINGS_H
#include <boost/lexical_cast.hpp>
#include "log.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
class Settings
{
public:
explicit Settings(Context *ctx) : ctx(ctx) {}
template <typename T> T get(const char *name, T defaultValue)
{
try {
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(defaultValue));
if (!pair.second) {
return boost::lexical_cast<T>(pair.first->second);
}
} catch (boost::bad_lexical_cast &) {
log_error("Problem reading setting %s, using default value\n", name);
}
return defaultValue;
}
template <typename T> void set(const char *name, T value)
{
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(value));
if (!pair.second) {
ctx->settings[pair.first->first] = value;
}
}
private:
Context *ctx;
};
NEXTPNR_NAMESPACE_END
#endif // SETTINGS_H

View File

@ -410,12 +410,13 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
log_info("estimated Fmax = %.2f MHz\n", 1e3 / ctx->getDelayNS(default_slack - min_slack)); log_info("estimated Fmax = %.2f MHz\n", 1e3 / ctx->getDelayNS(default_slack - min_slack));
if (print_histogram && slack_histogram.size() > 0) { if (print_histogram && slack_histogram.size() > 0) {
constexpr unsigned num_bins = 20; unsigned num_bins = 20;
unsigned bar_width = 60; unsigned bar_width = 60;
auto min_slack = slack_histogram.begin()->first; auto min_slack = slack_histogram.begin()->first;
auto max_slack = slack_histogram.rbegin()->first; auto max_slack = slack_histogram.rbegin()->first;
auto bin_size = (max_slack - min_slack) / num_bins; auto bin_size = std::max(1u, (max_slack - min_slack) / num_bins);
std::vector<unsigned> bins(num_bins + 1); num_bins = std::min((max_slack - min_slack) / bin_size, num_bins) + 1;
std::vector<unsigned> bins(num_bins);
unsigned max_freq = 0; unsigned max_freq = 0;
for (const auto &i : slack_histogram) { for (const auto &i : slack_histogram) {
auto &bin = bins[(i.first - min_slack) / bin_size]; auto &bin = bins[(i.first - min_slack) / bin_size];
@ -428,7 +429,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
log_info("Slack histogram:\n"); log_info("Slack histogram:\n");
log_info(" legend: * represents %d endpoint(s)\n", max_freq / bar_width); log_info(" legend: * represents %d endpoint(s)\n", max_freq / bar_width);
log_info(" + represents [1,%d) endpoint(s)\n", max_freq / bar_width); log_info(" + represents [1,%d) endpoint(s)\n", max_freq / bar_width);
for (unsigned i = 0; i < bins.size(); ++i) for (unsigned i = 0; i < num_bins; ++i)
log_info("[%6d, %6d) |%s%c\n", min_slack + bin_size * i, min_slack + bin_size * (i + 1), log_info("[%6d, %6d) |%s%c\n", min_slack + bin_size * i, min_slack + bin_size * (i + 1),
std::string(bins[i] * bar_width / max_freq, '*').c_str(), std::string(bins[i] * bar_width / max_freq, '*').c_str(),
(bins[i] * bar_width) % max_freq > 0 ? '+' : ' '); (bins[i] * bar_width) % max_freq > 0 ? '+' : ' ');

View File

@ -151,6 +151,11 @@ Return a list of all bels on the device.
Return the type of a given bel. Return the type of a given bel.
### const\_range\<std\:\:pair\<IdString, std::string\>\> getBelAttrs(BelId bel) const
Return the attributes for that bel. Bel attributes are only informal. They are displayed by the GUI but are otherwise
unused. An implementation may simply return an empty range.
### WireId getBelPinWire(BelId bel, IdString pin) const ### WireId getBelPinWire(BelId bel, IdString pin) const
Return the wire connected to the given bel pin. Return the wire connected to the given bel pin.
@ -180,6 +185,11 @@ Get the type of a wire. The wire type is purely informal and
isn't used by any of the core algorithms. Implementations may isn't used by any of the core algorithms. Implementations may
simply return `IdString()`. simply return `IdString()`.
### const\_range\<std\:\:pair\<IdString, std::string\>\> getWireAttrs(WireId wire) const
Return the attributes for that wire. Wire attributes are only informal. They are displayed by the GUI but are otherwise
unused. An implementation may simply return an empty range.
### uint32\_t getWireChecksum(WireId wire) const ### uint32\_t getWireChecksum(WireId wire) const
Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations. Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations.
@ -242,6 +252,11 @@ Get the name for a pip. (Pip names must be unique.)
Get the type of a pip. Pip types are purely informal and Get the type of a pip. Pip types are purely informal and
implementations may simply return `IdString()`. implementations may simply return `IdString()`.
### const\_range\<std\:\:pair\<IdString, std::string\>\> getPipAttrs(PipId pip) const
Return the attributes for that pip. Pip attributes are only informal. They are displayed by the GUI but are otherwise
unused. An implementation may simply return an empty range.
### Loc getPipLocation(PipId pip) const ### Loc getPipLocation(PipId pip) const
Get the X/Y/Z location of a given pip. Pip locations do not need to be unique, and in most cases they aren't. So Get the X/Y/Z location of a given pip. Pip locations do not need to be unique, and in most cases they aren't. So

View File

@ -46,7 +46,9 @@ static std::tuple<int, int, std::string> split_identifier_name(const std::string
void IdString::initialize_arch(const BaseCtx *ctx) void IdString::initialize_arch(const BaseCtx *ctx)
{ {
#define X(t) initialize_add(ctx, #t, ID_##t); #define X(t) initialize_add(ctx, #t, ID_##t);
#include "constids.inc" #include "constids.inc"
#undef X #undef X
} }
@ -92,6 +94,8 @@ Arch::Arch(ArchArgs args) : args(args)
if (!package_info) if (!package_info)
log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str());
bel_to_cell.resize(chip_info->height * chip_info->width * max_loc_bels, nullptr);
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -367,7 +371,7 @@ BelId Arch::getBelByLocation(Loc loc) const
delay_t Arch::estimateDelay(WireId src, WireId dst) const delay_t Arch::estimateDelay(WireId src, WireId dst) const
{ {
return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); return 100 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
} }
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
@ -376,20 +380,16 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
auto driver_loc = getBelLocation(driver.cell->bel); auto driver_loc = getBelLocation(driver.cell->bel);
auto sink_loc = getBelLocation(sink.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel);
return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
} }
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::place() { return placer1(getCtx(), Placer1Cfg()); } bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
bool Arch::route() bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
{
Router1Cfg cfg;
return router1(getCtx(), cfg);
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -436,7 +436,7 @@ DecalXY Arch::getBelDecal(BelId bel) const
decalxy.decal.type = DecalId::TYPE_BEL; decalxy.decal.type = DecalId::TYPE_BEL;
decalxy.decal.location = bel.location; decalxy.decal.location = bel.location;
decalxy.decal.z = bel.index; decalxy.decal.z = bel.index;
decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != nullptr); decalxy.decal.active = (bel_to_cell.at(getBelFlatIndex(bel)) != nullptr);
return decalxy; return decalxy;
} }
@ -450,12 +450,122 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
{ {
// Data for -8 grade
if (cell->type == id_TRELLIS_SLICE) {
bool has_carry = str_or_default(cell->params, id("MODE"), "LOGIC") == "CCU2";
if (fromPort == id_A0 || fromPort == id_B0 || fromPort == id_C0 || fromPort == id_D0) {
if (toPort == id_F0) {
delay.delay = 180;
return true;
} else if (has_carry && toPort == id_F1) {
delay.delay = 500;
return true;
} else if (has_carry && toPort == id_FCO) {
delay.delay = 355;
return true;
} else if (toPort == id_OFX0) {
delay.delay = 306;
return true;
}
}
if (fromPort == id_A1 || fromPort == id_B1 || fromPort == id_C1 || fromPort == id_D1) {
if (toPort == id_F1) {
delay.delay = 180;
return true;
} else if (has_carry && toPort == id_FCO) {
delay.delay = 355;
return true;
} else if (toPort == id_OFX0) {
delay.delay = 306;
return true;
}
}
if (has_carry && fromPort == id_FCI) {
if (toPort == id_F0) {
delay.delay = 328;
return true;
} else if (toPort == id_F1) {
delay.delay = 349;
return true;
} else if (toPort == id_FCO) {
delay.delay = 56;
return true;
}
}
if (fromPort == id_CLK && (toPort == id_Q0 || toPort == id_Q1)) {
delay.delay = 395;
return true;
}
if (fromPort == id_M0 && toPort == id_OFX0) {
delay.delay = 193;
return true;
}
if (fromPort == id_WCK && (toPort == id_F0 || toPort == id_F1)) {
delay.delay = 717;
return true;
}
if ((fromPort == id_A0 && toPort == id_WADO3) || (fromPort == id_A1 && toPort == id_WDO1) ||
(fromPort == id_B0 && toPort == id_WADO1) || (fromPort == id_B1 && toPort == id_WDO3) ||
(fromPort == id_C0 && toPort == id_WADO2) || (fromPort == id_C1 && toPort == id_WDO0) ||
(fromPort == id_D0 && toPort == id_WADO0) || (fromPort == id_D1 && toPort == id_WDO2)) {
delay.delay = 0;
return true;
}
return false; return false;
} else {
return false;
}
} }
TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const
{ {
if (cell->type == id_TRELLIS_SLICE) {
int sd0 = int_or_default(cell->params, id("REG0_SD"), 0), sd1 = int_or_default(cell->params, id("REG1_SD"), 0);
if (port == id_CLK || port == id_WCK)
return TMG_CLOCK_INPUT;
if (port == id_A0 || port == id_A1 || port == id_B0 || port == id_B1 || port == id_C0 || port == id_C1 ||
port == id_D0 || port == id_D1 || port == id_FCI || port == id_FXA || port == id_FXB)
return TMG_COMB_INPUT;
if (port == id_F0 || port == id_F1 || port == id_FCO || port == id_OFX0 || port == id_OFX1)
return TMG_COMB_OUTPUT;
if (port == id_DI0 || port == id_DI1 || port == id_CE || port == id_LSR || (sd0 == 1 && port == id_M0) ||
(sd1 == 1 && port == id_M1)) {
clockPort = id_CLK;
return TMG_REGISTER_INPUT;
}
if (port == id_M0 || port == id_M1)
return TMG_COMB_INPUT;
if (port == id_Q0 || port == id_Q1) {
clockPort = id_CLK;
return TMG_REGISTER_OUTPUT;
}
if (port == id_WDO0 || port == id_WDO1 || port == id_WDO2 || port == id_WDO3 || port == id_WADO0 ||
port == id_WADO1 || port == id_WADO2 || port == id_WADO3)
return TMG_COMB_OUTPUT;
if (port == id_WD0 || port == id_WD1 || port == id_WAD0 || port == id_WAD1 || port == id_WAD2 ||
port == id_WAD3 || port == id_WRE) {
clockPort = id_WCK;
return TMG_REGISTER_INPUT;
}
NPNR_ASSERT_FALSE_STR("no timing type for slice port '" + port.str(this) + "'");
} else if (cell->type == id_TRELLIS_IO) {
if (port == id_T || port == id_I)
return TMG_ENDPOINT;
if (port == id_O)
return TMG_STARTPOINT;
return TMG_IGNORE; return TMG_IGNORE;
} else {
NPNR_ASSERT_FALSE_STR("no timing data for cell type '" + cell->type.str(this) + "'");
}
} }
std::vector<std::pair<std::string, std::string>> Arch::getTilesAtLocation(int row, int col) std::vector<std::pair<std::string, std::string>> Arch::getTilesAtLocation(int row, int col)

View File

@ -404,7 +404,7 @@ struct Arch : BaseCtx
mutable std::unordered_map<IdString, WireId> wire_by_name; mutable std::unordered_map<IdString, WireId> wire_by_name;
mutable std::unordered_map<IdString, PipId> pip_by_name; mutable std::unordered_map<IdString, PipId> pip_by_name;
std::unordered_map<BelId, CellInfo *> bel_to_cell; std::vector<CellInfo *> bel_to_cell;
std::unordered_map<WireId, NetInfo *> wire_to_net; std::unordered_map<WireId, NetInfo *> wire_to_net;
std::unordered_map<PipId, NetInfo *> pip_to_net; std::unordered_map<PipId, NetInfo *> pip_to_net;
@ -443,11 +443,18 @@ struct Arch : BaseCtx
uint32_t getBelChecksum(BelId bel) const { return bel.index; } uint32_t getBelChecksum(BelId bel) const { return bel.index; }
const int max_loc_bels = 20;
int getBelFlatIndex(BelId bel) const
{
return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index;
}
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel] == nullptr); int idx = getBelFlatIndex(bel);
bel_to_cell[bel] = cell; NPNR_ASSERT(bel_to_cell.at(idx) == nullptr);
bel_to_cell[idx] = cell;
cell->bel = bel; cell->bel = bel;
cell->belStrength = strength; cell->belStrength = strength;
refreshUiBel(bel); refreshUiBel(bel);
@ -456,10 +463,11 @@ struct Arch : BaseCtx
void unbindBel(BelId bel) void unbindBel(BelId bel)
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel] != nullptr); int idx = getBelFlatIndex(bel);
bel_to_cell[bel]->bel = BelId(); NPNR_ASSERT(bel_to_cell.at(idx) != nullptr);
bel_to_cell[bel]->belStrength = STRENGTH_NONE; bel_to_cell[idx]->bel = BelId();
bel_to_cell[bel] = nullptr; bel_to_cell[idx]->belStrength = STRENGTH_NONE;
bel_to_cell[idx] = nullptr;
refreshUiBel(bel); refreshUiBel(bel);
} }
@ -480,25 +488,19 @@ struct Arch : BaseCtx
bool checkBelAvail(BelId bel) const bool checkBelAvail(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == nullptr; return bel_to_cell[getBelFlatIndex(bel)] == nullptr;
} }
CellInfo *getBoundBelCell(BelId bel) const CellInfo *getBoundBelCell(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
if (bel_to_cell.find(bel) == bel_to_cell.end()) return bel_to_cell[getBelFlatIndex(bel)];
return nullptr;
else
return bel_to_cell.at(bel);
} }
CellInfo *getConflictingBelCell(BelId bel) const CellInfo *getConflictingBelCell(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
if (bel_to_cell.find(bel) == bel_to_cell.end()) return bel_to_cell[getBelFlatIndex(bel)];
return nullptr;
else
return bel_to_cell.at(bel);
} }
BelRange getBels() const BelRange getBels() const
@ -522,6 +524,12 @@ struct Arch : BaseCtx
return id; return id;
} }
std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId) const
{
std::vector<std::pair<IdString, std::string>> ret;
return ret;
}
WireId getBelPinWire(BelId bel, IdString pin) const; WireId getBelPinWire(BelId bel, IdString pin) const;
BelPinRange getWireBelPins(WireId wire) const BelPinRange getWireBelPins(WireId wire) const
@ -553,6 +561,12 @@ struct Arch : BaseCtx
IdString getWireType(WireId wire) const { return IdString(); } IdString getWireType(WireId wire) const { return IdString(); }
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId) const
{
std::vector<std::pair<IdString, std::string>> ret;
return ret;
}
uint32_t getWireChecksum(WireId wire) const { return wire.index; } uint32_t getWireChecksum(WireId wire) const { return wire.index; }
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
@ -633,6 +647,12 @@ struct Arch : BaseCtx
IdString getPipType(PipId pip) const { return IdString(); } IdString getPipType(PipId pip) const { return IdString(); }
std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId) const
{
std::vector<std::pair<IdString, std::string>> ret;
return ret;
}
uint32_t getPipChecksum(PipId pip) const { return pip.index; } uint32_t getPipChecksum(PipId pip) const { return pip.index; }
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
@ -725,7 +745,7 @@ struct Arch : BaseCtx
{ {
DelayInfo delay; DelayInfo delay;
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
delay.delay = locInfo(pip)->pip_data[pip.index].delay * 100; delay.delay = locInfo(pip)->pip_data[pip.index].delay;
return delay; return delay;
} }
@ -848,6 +868,8 @@ struct Arch : BaseCtx
// Helper function for above // Helper function for above
bool slicesCompatible(const std::vector<const CellInfo *> &cells) const; bool slicesCompatible(const std::vector<const CellInfo *> &cells) const;
void assignArchInfo();
std::vector<std::pair<std::string, std::string>> getTilesAtLocation(int row, int col); std::vector<std::pair<std::string, std::string>> getTilesAtLocation(int row, int col);
std::string getTileByTypeAndLocation(int row, int col, std::string type) const std::string getTileByTypeAndLocation(int row, int col, std::string type) const
{ {

View File

@ -35,26 +35,26 @@ bool Arch::slicesCompatible(const std::vector<const CellInfo *> &cells) const
{ {
// TODO: allow different LSR/CLK and MUX/SRMODE settings once // TODO: allow different LSR/CLK and MUX/SRMODE settings once
// routing details are worked out // routing details are worked out
NetInfo *clk_sig = nullptr, *lsr_sig = nullptr; IdString clk_sig, lsr_sig;
std::string CLKMUX, LSRMUX, SRMODE; IdString CLKMUX, LSRMUX, SRMODE;
bool first = true; bool first = true;
for (auto cell : cells) { for (auto cell : cells) {
if (first) { if (first) {
clk_sig = port_or_nullptr(cell, id_CLK); clk_sig = cell->sliceInfo.clk_sig;
lsr_sig = port_or_nullptr(cell, id_LSR); lsr_sig = cell->sliceInfo.lsr_sig;
CLKMUX = str_or_default(cell->params, id_CLKMUX, "CLK"); CLKMUX = cell->sliceInfo.clkmux;
LSRMUX = str_or_default(cell->params, id_LSRMUX, "LSR"); LSRMUX = cell->sliceInfo.lsrmux;
SRMODE = str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR"); SRMODE = cell->sliceInfo.srmode;
} else { } else {
if (port_or_nullptr(cell, id_CLK) != clk_sig) if (cell->sliceInfo.clk_sig != clk_sig)
return false; return false;
if (port_or_nullptr(cell, id_LSR) != lsr_sig) if (cell->sliceInfo.lsr_sig != lsr_sig)
return false; return false;
if (str_or_default(cell->params, id_CLKMUX, "CLK") != CLKMUX) if (cell->sliceInfo.clkmux != CLKMUX)
return false; return false;
if (str_or_default(cell->params, id_LSRMUX, "LSR") != LSRMUX) if (cell->sliceInfo.lsrmux != LSRMUX)
return false; return false;
if (str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR") != SRMODE) if (cell->sliceInfo.srmode != SRMODE)
return false; return false;
} }
first = false; first = false;

View File

@ -139,6 +139,10 @@ struct ArchNetInfo
}; };
struct ArchCellInfo struct ArchCellInfo
{ {
struct
{
IdString clk_sig, lsr_sig, clkmux, lsrmux, srmode;
} sliceInfo;
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -536,10 +536,34 @@ bool Arch::pack()
log_break(); log_break();
Ecp5Packer(ctx).pack(); Ecp5Packer(ctx).pack();
log_info("Checksum: 0x%08x\n", ctx->checksum()); log_info("Checksum: 0x%08x\n", ctx->checksum());
assignArchInfo();
return true; return true;
} catch (log_execution_error_exception) { } catch (log_execution_error_exception) {
assignArchInfo();
return false; return false;
} }
} }
void Arch::assignArchInfo()
{
for (auto cell : sorted(cells)) {
CellInfo *ci = cell.second;
if (ci->type == id_TRELLIS_SLICE) {
if (ci->ports.count(id_CLK) && ci->ports[id_CLK].net != nullptr)
ci->sliceInfo.clk_sig = ci->ports[id_CLK].net->name;
else
ci->sliceInfo.clk_sig = IdString();
if (ci->ports.count(id_LSR) && ci->ports[id_LSR].net != nullptr)
ci->sliceInfo.lsr_sig = ci->ports[id_LSR].net->name;
else
ci->sliceInfo.lsr_sig = IdString();
ci->sliceInfo.clkmux = id(str_or_default(ci->params, id_CLKMUX, "CLK"));
ci->sliceInfo.lsrmux = id(str_or_default(ci->params, id_LSRMUX, "LSR"));
ci->sliceInfo.srmode = id(str_or_default(ci->params, id_SRMODE, "LSR_OVER_CE"));
}
}
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -130,11 +130,54 @@ def process_loc_globals(chip):
tapdrv = chip.global_data.get_tap_driver(y, x) tapdrv = chip.global_data.get_tap_driver(y, x)
global_data[x, y] = (quadrants.index(quad), int(tapdrv.dir), tapdrv.col) global_data[x, y] = (quadrants.index(quad), int(tapdrv.dir), tapdrv.col)
def get_wire_type(name):
if "H00" in name or "V00" in name:
return "X0"
if "H01" in name or "V01" in name:
return "X1"
if "H02" in name or "V02" in name:
return "X2"
if "H06" in name or "V06" in name:
return "X6"
if "_SLICE" in name or "_EBR" in name:
return "SLICE"
return "LOCAL"
def get_pip_delay(wire_from, wire_to):
# ECP5 timings WIP!!!
type_from = get_wire_type(wire_from)
type_to = get_wire_type(wire_to)
if type_from == "X2" and type_to == "X2":
return 170
if type_from == "SLICE" or type_to == "SLICE":
return 205
if type_from in ("LOCAL", "X0") and type_to in ("X1", "X2", "X6"):
return 90
if type_from == "X6" or type_to == "X6":
return 200
if type_from in ("X1", "X2", "X6") and type_to in ("LOCAL", "X0"):
return 90
return 100
def write_database(dev_name, chip, ddrg, endianness): def write_database(dev_name, chip, ddrg, endianness):
def write_loc(loc, sym_name): def write_loc(loc, sym_name):
bba.u16(loc.x, "%s.x" % sym_name) bba.u16(loc.x, "%s.x" % sym_name)
bba.u16(loc.y, "%s.y" % sym_name) bba.u16(loc.y, "%s.y" % sym_name)
loctypes = list([_.key() for _ in ddrg.locationTypes])
loc_with_type = {}
for y in range(0, max_row+1):
for x in range(0, max_col+1):
loc_with_type[loctypes.index(ddrg.typeAtLocation[pytrellis.Location(x, y)])] = (x, y)
def get_wire_name(arc_loctype, rel, idx):
loc = loc_with_type[arc_loctype]
lt = ddrg.typeAtLocation[pytrellis.Location(loc[0] + rel.x, loc[1] + rel.y)]
wire = ddrg.locationTypes[lt].wires[idx]
return ddrg.to_str(wire.name)
bba = BinaryBlobAssembler() bba = BinaryBlobAssembler()
bba.pre('#include "nextpnr.h"') bba.pre('#include "nextpnr.h"')
bba.pre('NEXTPNR_NAMESPACE_BEGIN') bba.pre('NEXTPNR_NAMESPACE_BEGIN')
@ -142,7 +185,6 @@ def write_database(dev_name, chip, ddrg, endianness):
bba.push("chipdb_blob_%s" % dev_name) bba.push("chipdb_blob_%s" % dev_name)
bba.r("chip_info", "chip_info") bba.r("chip_info", "chip_info")
loctypes = list([_.key() for _ in ddrg.locationTypes])
for idx in range(len(loctypes)): for idx in range(len(loctypes)):
loctype = ddrg.locationTypes[loctypes[idx]] loctype = ddrg.locationTypes[loctypes[idx]]
@ -153,7 +195,7 @@ def write_database(dev_name, chip, ddrg, endianness):
write_loc(arc.sinkWire.rel, "dst") write_loc(arc.sinkWire.rel, "dst")
bba.u32(arc.srcWire.id, "src_idx") bba.u32(arc.srcWire.id, "src_idx")
bba.u32(arc.sinkWire.id, "dst_idx") bba.u32(arc.sinkWire.id, "dst_idx")
bba.u32(arc.delay, "delay") # TODO:delay bba.u32(get_pip_delay(get_wire_name(idx, arc.srcWire.rel, arc.srcWire.id), get_wire_name(idx, arc.sinkWire.rel, arc.sinkWire.id)), "delay") # TODO:delay
bba.u16(get_tiletype_index(ddrg.to_str(arc.tiletype)), "tile_type") bba.u16(get_tiletype_index(ddrg.to_str(arc.tiletype)), "tile_type")
bba.u8(int(arc.cls), "pip_type") bba.u8(int(arc.cls), "pip_type")
bba.u8(0, "padding") bba.u8(0, "padding")

View File

@ -184,6 +184,21 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
refreshUiGroup(group); refreshUiGroup(group);
} }
void Arch::setWireAttr(IdString wire, IdString key, const std::string &value)
{
wires.at(wire).attrs[key] = value;
}
void Arch::setPipAttr(IdString pip, IdString key, const std::string &value)
{
pips.at(pip).attrs[key] = value;
}
void Arch::setBelAttr(IdString bel, IdString key, const std::string &value)
{
bels.at(bel).attrs[key] = value;
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
Arch::Arch(ArchArgs args) : chipName("generic"), args(args) {} Arch::Arch(ArchArgs args) : chipName("generic"), args(args) {}
@ -251,6 +266,8 @@ const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; } IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; }
const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; }
WireId Arch::getBelPinWire(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).wire; } WireId Arch::getBelPinWire(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).wire; }
PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; } PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; }
@ -276,6 +293,8 @@ IdString Arch::getWireName(WireId wire) const { return wire; }
IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; } IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; }
const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; }
uint32_t Arch::getWireChecksum(WireId wire) const uint32_t Arch::getWireChecksum(WireId wire) const
{ {
// FIXME // FIXME
@ -328,6 +347,8 @@ IdString Arch::getPipName(PipId pip) const { return pip; }
IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; } IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; }
const std::map<IdString, std::string> &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; }
uint32_t Arch::getPipChecksum(PipId wire) const uint32_t Arch::getPipChecksum(PipId wire) const
{ {
// FIXME // FIXME
@ -425,9 +446,9 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
// --------------------------------------------------------------- // ---------------------------------------------------------------
bool Arch::place() { return placer1(getCtx(), Placer1Cfg()); } bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
bool Arch::route() { return router1(getCtx(), Router1Cfg()); } bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
// --------------------------------------------------------------- // ---------------------------------------------------------------

View File

@ -32,6 +32,7 @@ struct WireInfo;
struct PipInfo struct PipInfo
{ {
IdString name, type; IdString name, type;
std::map<IdString, std::string> attrs;
NetInfo *bound_net; NetInfo *bound_net;
WireId srcWire, dstWire; WireId srcWire, dstWire;
DelayInfo delay; DelayInfo delay;
@ -42,6 +43,7 @@ struct PipInfo
struct WireInfo struct WireInfo
{ {
IdString name, type; IdString name, type;
std::map<IdString, std::string> attrs;
NetInfo *bound_net; NetInfo *bound_net;
std::vector<PipId> downhill, uphill, aliases; std::vector<PipId> downhill, uphill, aliases;
BelPin uphill_bel_pin; BelPin uphill_bel_pin;
@ -61,6 +63,7 @@ struct PinInfo
struct BelInfo struct BelInfo
{ {
IdString name, type; IdString name, type;
std::map<IdString, std::string> attrs;
CellInfo *bound_cell; CellInfo *bound_cell;
std::unordered_map<IdString, PinInfo> pins; std::unordered_map<IdString, PinInfo> pins;
DecalXY decalxy; DecalXY decalxy;
@ -120,6 +123,10 @@ struct Arch : BaseCtx
void setBelDecal(BelId bel, DecalXY decalxy); void setBelDecal(BelId bel, DecalXY decalxy);
void setGroupDecal(GroupId group, DecalXY decalxy); void setGroupDecal(GroupId group, DecalXY decalxy);
void setWireAttr(IdString wire, IdString key, const std::string &value);
void setPipAttr(IdString pip, IdString key, const std::string &value);
void setBelAttr(IdString bel, IdString key, const std::string &value);
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Common Arch API. Every arch must provide the following methods. // Common Arch API. Every arch must provide the following methods.
@ -151,6 +158,7 @@ struct Arch : BaseCtx
CellInfo *getConflictingBelCell(BelId bel) const; CellInfo *getConflictingBelCell(BelId bel) const;
const std::vector<BelId> &getBels() const; const std::vector<BelId> &getBels() const;
IdString getBelType(BelId bel) const; IdString getBelType(BelId bel) const;
const std::map<IdString, std::string> &getBelAttrs(BelId bel) const;
WireId getBelPinWire(BelId bel, IdString pin) const; WireId getBelPinWire(BelId bel, IdString pin) const;
PortType getBelPinType(BelId bel, IdString pin) const; PortType getBelPinType(BelId bel, IdString pin) const;
std::vector<IdString> getBelPins(BelId bel) const; std::vector<IdString> getBelPins(BelId bel) const;
@ -158,6 +166,7 @@ struct Arch : BaseCtx
WireId getWireByName(IdString name) const; WireId getWireByName(IdString name) const;
IdString getWireName(WireId wire) const; IdString getWireName(WireId wire) const;
IdString getWireType(WireId wire) const; IdString getWireType(WireId wire) const;
const std::map<IdString, std::string> &getWireAttrs(WireId wire) const;
uint32_t getWireChecksum(WireId wire) const; uint32_t getWireChecksum(WireId wire) const;
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength); void bindWire(WireId wire, NetInfo *net, PlaceStrength strength);
void unbindWire(WireId wire); void unbindWire(WireId wire);
@ -171,6 +180,7 @@ struct Arch : BaseCtx
PipId getPipByName(IdString name) const; PipId getPipByName(IdString name) const;
IdString getPipName(PipId pip) const; IdString getPipName(PipId pip) const;
IdString getPipType(PipId pip) const; IdString getPipType(PipId pip) const;
const std::map<IdString, std::string> &getPipAttrs(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const; uint32_t getPipChecksum(PipId pip) const;
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); void bindPip(PipId pip, NetInfo *net, PlaceStrength strength);
void unbindPip(PipId pip); void unbindPip(PipId pip);

View File

@ -109,6 +109,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, ArchArgs args,
connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem); connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem);
connect(designview, &DesignWidget::zoomSelected, fpgaView, &FPGAViewWidget::zoomSelected); connect(designview, &DesignWidget::zoomSelected, fpgaView, &FPGAViewWidget::zoomSelected);
connect(designview, &DesignWidget::highlight, fpgaView, &FPGAViewWidget::onHighlightGroupChanged); connect(designview, &DesignWidget::highlight, fpgaView, &FPGAViewWidget::onHighlightGroupChanged);
connect(designview, &DesignWidget::hover, fpgaView, &FPGAViewWidget::onHoverItemChanged);
// Click event on device view // Click event on device view
connect(fpgaView, &FPGAViewWidget::clickedBel, designview, &DesignWidget::onClickedBel); connect(fpgaView, &FPGAViewWidget::clickedBel, designview, &DesignWidget::onClickedBel);
@ -420,7 +421,7 @@ void BaseMainWindow::disableActions()
actionNew->setEnabled(true); actionNew->setEnabled(true);
actionOpen->setEnabled(true); actionOpen->setEnabled(true);
if (ctx->settings.find(ctx->id("project/input/json")) != ctx->settings.end()) if (ctx->settings.find(ctx->id("input/json")) != ctx->settings.end())
actionSave->setEnabled(true); actionSave->setEnabled(true);
else else
actionSave->setEnabled(false); actionSave->setEnabled(false);

View File

@ -30,15 +30,34 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
TreeView::TreeView(QWidget *parent) : QTreeView(parent) {}
TreeView::~TreeView() {}
void TreeView::mouseMoveEvent(QMouseEvent *event)
{
QModelIndex index = indexAt(event->pos());
if (index!=current) {
current = index;
Q_EMIT hoverIndexChanged(index);
}
QTreeView::mouseMoveEvent(event);
}
void TreeView::leaveEvent(QEvent *event)
{
Q_EMIT hoverIndexChanged(QModelIndex());
}
DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), selectionModel(nullptr) DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), selectionModel(nullptr)
{ {
// Add tree view // Add tree view
treeView = new QTreeView(); treeView = new TreeView();
treeModel = new TreeModel::Model(); treeModel = new TreeModel::Model();
treeView->setModel(treeModel); treeView->setModel(treeModel);
treeView->setContextMenuPolicy(Qt::CustomContextMenu); treeView->setContextMenuPolicy(Qt::CustomContextMenu);
treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
treeView->viewport()->setMouseTracking(true);
// Add property view // Add property view
variantManager = new QtVariantPropertyManager(this); variantManager = new QtVariantPropertyManager(this);
readOnlyManager = new QtVariantPropertyManager(this); readOnlyManager = new QtVariantPropertyManager(this);
@ -50,6 +69,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
propertyEditor->show(); propertyEditor->show();
propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu); propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection); propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection);
propertyEditor->treeWidget()->viewport()->setMouseTracking(true);
searchEdit = new QLineEdit(); searchEdit = new QLineEdit();
searchEdit->setClearButtonEnabled(true); searchEdit->setClearButtonEnabled(true);
@ -158,9 +178,11 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this, connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this,
&DesignWidget::prepareMenuProperty); &DesignWidget::prepareMenuProperty);
connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked); connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked);
connect(propertyEditor, &QtTreePropertyBrowser::hoverPropertyChanged, this, &DesignWidget::onHoverPropertyChanged);
connect(treeView, &QTreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); connect(treeView, &TreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
connect(treeView, &QTreeView::doubleClicked, this, &DesignWidget::onDoubleClicked); connect(treeView, &TreeView::doubleClicked, this, &DesignWidget::onDoubleClicked);
connect(treeView, &TreeView::hoverIndexChanged, this, &DesignWidget::onHoverIndexChanged);
selectionModel = treeView->selectionModel(); selectionModel = treeView->selectionModel();
connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &DesignWidget::onSelectionChanged); connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &DesignWidget::onSelectionChanged);
@ -388,7 +410,6 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
ElementType type = clickItem->type(); ElementType type = clickItem->type();
if (type == ElementType::NONE) if (type == ElementType::NONE)
return; return;
std::vector<DecalXY> decals;
addToHistory(index); addToHistory(index);
@ -411,6 +432,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)), addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
ElementType::CELL); ElementType::CELL);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getBelAttrs(bel)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
QtProperty *belpinsItem = addSubGroup(topItem, "Ports"); QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
for (const auto &item : ctx->getBelPins(bel)) { for (const auto &item : ctx->getBelPins(bel)) {
QtProperty *portInfoItem = addSubGroup(belpinsItem, item.c_str(ctx)); QtProperty *portInfoItem = addSubGroup(belpinsItem, item.c_str(ctx));
@ -433,6 +459,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)), addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
ElementType::NET); ElementType::NET);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getWireAttrs(wire)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
DelayInfo delay = ctx->getWireDelay(wire); DelayInfo delay = ctx->getWireDelay(wire);
QtProperty *delayItem = addSubGroup(topItem, "Delay"); QtProperty *delayItem = addSubGroup(topItem, "Delay");
@ -492,6 +523,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx), addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx),
ElementType::WIRE); ElementType::WIRE);
QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
for (auto &item : ctx->getPipAttrs(pip)) {
addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
}
DelayInfo delay = ctx->getPipDelay(pip); DelayInfo delay = ctx->getPipDelay(pip);
QtProperty *delayItem = addSubGroup(topItem, "Delay"); QtProperty *delayItem = addSubGroup(topItem, "Delay");
@ -785,4 +821,35 @@ void DesignWidget::onSearchInserted()
if (currentSearchIndexes.size() > 0 && currentIndex < currentSearchIndexes.size()) if (currentSearchIndexes.size() > 0 && currentIndex < currentSearchIndexes.size())
selectionModel->setCurrentIndex(currentSearchIndexes.at(currentIndex), QItemSelectionModel::ClearAndSelect); selectionModel->setCurrentIndex(currentSearchIndexes.at(currentIndex), QItemSelectionModel::ClearAndSelect);
} }
void DesignWidget::onHoverIndexChanged(QModelIndex index)
{
if (index.isValid()) {
TreeModel::Item *item = treeModel->nodeFromIndex(index);
if (item->type() != ElementType::NONE) {
Q_EMIT hover(getDecals(item->type(), item->id()).at(0));
return;
}
}
Q_EMIT hover(DecalXY());
}
void DesignWidget::onHoverPropertyChanged(QtBrowserItem *item)
{
if (item!=nullptr) {
QtProperty *selectedProperty = item->property();
ElementType type = getElementTypeByName(selectedProperty->propertyId());
if (type != ElementType::NONE) {
IdString value = ctx->id(selectedProperty->valueText().toStdString());
if (value!=IdString()) {
auto node = treeModel->nodeForIdType(type, value);
if (node) {
Q_EMIT hover(getDecals((*node)->type(), (*node)->id()).at(0));
return;
}
}
}
}
Q_EMIT hover(DecalXY());
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -22,6 +22,7 @@
#include <QTreeView> #include <QTreeView>
#include <QVariant> #include <QVariant>
#include <QMouseEvent>
#include "nextpnr.h" #include "nextpnr.h"
#include "qtgroupboxpropertybrowser.h" #include "qtgroupboxpropertybrowser.h"
#include "qtpropertymanager.h" #include "qtpropertymanager.h"
@ -31,6 +32,22 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
class TreeView : public QTreeView
{
Q_OBJECT
public:
explicit TreeView(QWidget *parent = 0);
~TreeView();
void mouseMoveEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *event) override;
Q_SIGNALS:
void hoverIndexChanged(QModelIndex index);
private:
QModelIndex current;
};
class DesignWidget : public QWidget class DesignWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -55,6 +72,7 @@ class DesignWidget : public QWidget
Q_SIGNALS: Q_SIGNALS:
void selected(std::vector<DecalXY> decal, bool keep); void selected(std::vector<DecalXY> decal, bool keep);
void highlight(std::vector<DecalXY> decal, int group); void highlight(std::vector<DecalXY> decal, int group);
void hover(DecalXY decal);
void zoomSelected(); void zoomSelected();
private Q_SLOTS: private Q_SLOTS:
@ -64,6 +82,8 @@ class DesignWidget : public QWidget
void onItemDoubleClicked(QTreeWidgetItem *item, int column); void onItemDoubleClicked(QTreeWidgetItem *item, int column);
void onDoubleClicked(const QModelIndex &index); void onDoubleClicked(const QModelIndex &index);
void onSearchInserted(); void onSearchInserted();
void onHoverIndexChanged(QModelIndex index);
void onHoverPropertyChanged(QtBrowserItem *item);
public Q_SLOTS: public Q_SLOTS:
void newContext(Context *ctx); void newContext(Context *ctx);
void updateTree(); void updateTree();
@ -74,7 +94,7 @@ class DesignWidget : public QWidget
private: private:
Context *ctx; Context *ctx;
QTreeView *treeView; TreeView *treeView;
QItemSelectionModel *selectionModel; QItemSelectionModel *selectionModel;
TreeModel::Model *treeModel; TreeModel::Model *treeModel;
QLineEdit *searchEdit; QLineEdit *searchEdit;

View File

@ -240,9 +240,10 @@ void FPGAViewWidget::populateQuadTree(RendererData *data, const DecalXY &decal,
continue; continue;
} }
bool res = true;
if (el.type == GraphicElement::TYPE_BOX) { if (el.type == GraphicElement::TYPE_BOX) {
// Boxes are bounded by themselves. // Boxes are bounded by themselves.
data->qt->insert(PickQuadTree::BoundingBox(x + el.x1, y + el.y1, x + el.x2, y + el.y2), element); res = data->qt->insert(PickQuadTree::BoundingBox(x + el.x1, y + el.y1, x + el.x2, y + el.y2), element);
} }
if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) { if (el.type == GraphicElement::TYPE_LINE || el.type == GraphicElement::TYPE_ARROW) {
@ -261,7 +262,11 @@ void FPGAViewWidget::populateQuadTree(RendererData *data, const DecalXY &decal,
x1 += 0.01; x1 += 0.01;
y1 += 0.01; y1 += 0.01;
data->qt->insert(PickQuadTree::BoundingBox(x0, y0, x1, y1), element); res = data->qt->insert(PickQuadTree::BoundingBox(x0, y0, x1, y1), element);
}
if (!res) {
NPNR_ASSERT_FALSE("populateQuadTree: could not insert element");
} }
} }
} }
@ -450,8 +455,17 @@ void FPGAViewWidget::renderLines(void)
NPNR_ASSERT(data->bbGlobal.w() != 0); NPNR_ASSERT(data->bbGlobal.w() != 0);
NPNR_ASSERT(data->bbGlobal.h() != 0); NPNR_ASSERT(data->bbGlobal.h() != 0);
// Enlarge the bounding box slightly for the picking - when we insert
// elements into it, we enlarge their bounding boxes slightly, so
// we need to give ourselves some sagery margin here.
auto bb = data->bbGlobal;
bb.setX0(bb.x0() - 1);
bb.setY0(bb.y0() - 1);
bb.setX1(bb.x1() + 1);
bb.setY1(bb.y1() + 1);
// Populate picking quadtree. // Populate picking quadtree.
data->qt = std::unique_ptr<PickQuadTree>(new PickQuadTree(data->bbGlobal)); data->qt = std::unique_ptr<PickQuadTree>(new PickQuadTree(bb));
for (auto const &decal : belDecals) { for (auto const &decal : belDecals) {
populateQuadTree(data.get(), decal.first, populateQuadTree(data.get(), decal.first,
PickedElement::fromBel(decal.second, decal.first.x, decal.first.y)); PickedElement::fromBel(decal.second, decal.first.x, decal.first.y));
@ -545,6 +559,14 @@ void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int gr
pokeRenderer(); pokeRenderer();
} }
void FPGAViewWidget::onHoverItemChanged(DecalXY decal)
{
QMutexLocker locked(&rendererArgsLock_);
rendererArgs_->hoveredDecal = decal;
rendererArgs_->changed = true;
pokeRenderer();
}
void FPGAViewWidget::resizeGL(int width, int height) {} void FPGAViewWidget::resizeGL(int width, int height) {}
boost::optional<FPGAViewWidget::PickedElement> FPGAViewWidget::pickElement(float worldx, float worldy) boost::optional<FPGAViewWidget::PickedElement> FPGAViewWidget::pickElement(float worldx, float worldy)
@ -736,7 +758,7 @@ void FPGAViewWidget::zoomOut() { zoom(-10); }
void FPGAViewWidget::zoomToBB(const PickQuadTree::BoundingBox &bb, float margin) void FPGAViewWidget::zoomToBB(const PickQuadTree::BoundingBox &bb, float margin)
{ {
if (bb.w() < 0.00005 && bb.h() < 0.00005) if (fabs(bb.w()) < 0.00005 && fabs(bb.h()) < 0.00005)
return; return;
viewMove_.setToIdentity(); viewMove_.setToIdentity();
@ -767,4 +789,12 @@ void FPGAViewWidget::zoomOutbound()
} }
} }
void FPGAViewWidget::leaveEvent(QEvent *event)
{
QMutexLocker locked(&rendererArgsLock_);
rendererArgs_->hoveredDecal = DecalXY();
rendererArgs_->changed = true;
pokeRenderer();
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -107,11 +107,13 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
QSize minimumSizeHint() const override; QSize minimumSizeHint() const override;
QSize sizeHint() const override; QSize sizeHint() const override;
void leaveEvent(QEvent *event) override;
public Q_SLOTS: public Q_SLOTS:
void newContext(Context *ctx); void newContext(Context *ctx);
void onSelectedArchItem(std::vector<DecalXY> decals, bool keep); void onSelectedArchItem(std::vector<DecalXY> decals, bool keep);
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group); void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
void onHoverItemChanged(DecalXY decal);
void pokeRenderer(void); void pokeRenderer(void);
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();

View File

@ -191,7 +191,7 @@ void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); }
void MainWindow::onProjectLoaded() void MainWindow::onProjectLoaded()
{ {
if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end()) if (ctx->settings.find(ctx->id("input/pcf")) != ctx->settings.end())
actionLoadPCF->setEnabled(false); actionLoadPCF->setEnabled(false);
} }

View File

@ -226,6 +226,15 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const
return PORT_INOUT; return PORT_INOUT;
} }
std::vector<std::pair<IdString, std::string>> Arch::getBelAttrs(BelId bel) const
{
std::vector<std::pair<IdString, std::string>> ret;
ret.push_back(std::make_pair(id("INDEX"), stringf("%d", bel.index)));
return ret;
}
WireId Arch::getBelPinWire(BelId bel, IdString pin) const WireId Arch::getBelPinWire(BelId bel, IdString pin) const
{ {
WireId ret; WireId ret;
@ -331,6 +340,28 @@ IdString Arch::getWireType(WireId wire) const
return IdString(); return IdString();
} }
std::vector<std::pair<IdString, std::string>> Arch::getWireAttrs(WireId wire) const
{
std::vector<std::pair<IdString, std::string>> ret;
auto &wi = chip_info->wire_data[wire.index];
ret.push_back(std::make_pair(id("INDEX"), stringf("%d", wire.index)));
ret.push_back(std::make_pair(id("GRID_X"), stringf("%d", wi.x)));
ret.push_back(std::make_pair(id("GRID_Y"), stringf("%d", wi.y)));
ret.push_back(std::make_pair(id("GRID_Z"), stringf("%d", wi.z)));
#if 0
for (int i = 0; i < wi.num_segments; i++) {
auto &si = wi.segments[i];
ret.push_back(std::make_pair(id(stringf("segment[%d]", i)),
stringf("X%d/Y%d/%s", si.x, si.y, chip_info->tile_wire_names[si.index].get())));
}
#endif
return ret;
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
PipId Arch::getPipByName(IdString name) const PipId Arch::getPipByName(IdString name) const
@ -372,6 +403,18 @@ IdString Arch::getPipName(PipId pip) const
#endif #endif
} }
IdString Arch::getPipType(PipId pip) const { return IdString(); }
std::vector<std::pair<IdString, std::string>> Arch::getPipAttrs(PipId pip) const
{
std::vector<std::pair<IdString, std::string>> ret;
ret.push_back(std::make_pair(id("INDEX"), stringf("%d", pip.index)));
return ret;
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
BelId Arch::getPackagePinBel(const std::string &pin) const BelId Arch::getPackagePinBel(const std::string &pin) const
@ -565,18 +608,9 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool Arch::place() bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
{
Placer1Cfg cfg;
cfg.constraintWeight = placer_constraintWeight;
return placer1(getCtx(), cfg);
}
bool Arch::route() bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
{
Router1Cfg cfg;
return router1(getCtx(), cfg);
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -695,13 +729,29 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); gfxTileWire(ret, p[i].x, p[i].y, chip_info->width, chip_info->height, GfxTileWireId(p[i].index), style);
#if 0
if (ret.empty()) {
WireId wire;
wire.index = decal.index;
log_warning("No gfx decal for wire %s (%d).\n", getWireName(wire).c_str(getCtx()), decal.index);
}
#endif
} }
if (decal.type == DecalId::TYPE_PIP) { if (decal.type == DecalId::TYPE_PIP) {
const PipInfoPOD &p = chip_info->pip_data[decal.index]; const PipInfoPOD &p = chip_info->pip_data[decal.index];
GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN;
gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style); gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style);
#if 0
if (ret.empty()) {
PipId pip;
pip.index = decal.index;
log_warning("No gfx decal for pip %s (%d).\n", getPipName(pip).c_str(getCtx()), decal.index);
}
#endif
} }
if (decal.type == DecalId::TYPE_BEL) { if (decal.type == DecalId::TYPE_BEL) {
@ -727,7 +777,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
GraphicElement el; GraphicElement el;
el.type = GraphicElement::TYPE_BOX; el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x1 = chip_info->bel_data[bel.index].x + lut_swbox_x1;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; 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.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 +
(4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch; (4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch;
@ -741,13 +791,43 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
GraphicElement el; GraphicElement el;
el.type = GraphicElement::TYPE_BOX; el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x1 = chip_info->bel_data[bel.index].x + lut_swbox_x1;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2;
el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i;
el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch; el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch;
ret.push_back(el); ret.push_back(el);
} }
} }
if (bel_type == id_SB_GB) {
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = chip_info->bel_data[bel.index].x + local_swbox_x1 + 0.05;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2 - 0.05;
el.y1 = chip_info->bel_data[bel.index].y + main_swbox_y2 - 0.05;
el.y2 = chip_info->bel_data[bel.index].y + main_swbox_y2 - 0.10;
ret.push_back(el);
}
if (bel_type == id_ICESTORM_PLL || bel_type == id_SB_WARMBOOT) {
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
el.x1 = chip_info->bel_data[bel.index].x + local_swbox_x1 + 0.05;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2 - 0.05;
el.y1 = chip_info->bel_data[bel.index].y + main_swbox_y2;
el.y2 = chip_info->bel_data[bel.index].y + main_swbox_y2 + 0.05;
ret.push_back(el);
}
#if 0
if (ret.empty()) {
BelId bel;
bel.index = decal.index;
log_warning("No gfx decal for bel %s (%d).\n", getBelName(bel).c_str(getCtx()), decal.index);
}
#endif
} }
return ret; return ret;

View File

@ -225,6 +225,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
RelPtr<BelConfigPOD> bel_config; RelPtr<BelConfigPOD> bel_config;
RelPtr<PackageInfoPOD> packages_data; RelPtr<PackageInfoPOD> packages_data;
RelPtr<CellTimingPOD> cell_timing; RelPtr<CellTimingPOD> cell_timing;
RelPtr<RelPtr<char>> tile_wire_names;
}); });
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -502,6 +503,8 @@ struct Arch : BaseCtx
return IdString(chip_info->bel_data[bel.index].type); return IdString(chip_info->bel_data[bel.index].type);
} }
std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId bel) const;
WireId getBelPinWire(BelId bel, IdString pin) const; WireId getBelPinWire(BelId bel, IdString pin) const;
PortType getBelPinType(BelId bel, IdString pin) const; PortType getBelPinType(BelId bel, IdString pin) const;
std::vector<IdString> getBelPins(BelId bel) const; std::vector<IdString> getBelPins(BelId bel) const;
@ -517,6 +520,7 @@ struct Arch : BaseCtx
} }
IdString getWireType(WireId wire) const; IdString getWireType(WireId wire) const;
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const;
uint32_t getWireChecksum(WireId wire) const { return wire.index; } uint32_t getWireChecksum(WireId wire) const { return wire.index; }
@ -692,7 +696,8 @@ struct Arch : BaseCtx
IdString getPipName(PipId pip) const; IdString getPipName(PipId pip) const;
IdString getPipType(PipId pip) const { return IdString(); } IdString getPipType(PipId pip) const;
std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const { return pip.index; } uint32_t getPipChecksum(PipId pip) const { return pip.index; }
@ -832,8 +837,6 @@ struct Arch : BaseCtx
} }
NPNR_ASSERT_FALSE("Expected PLL pin to share an output with an SB_IO D_IN_{0,1}"); NPNR_ASSERT_FALSE("Expected PLL pin to share an output with an SB_IO D_IN_{0,1}");
} }
float placer_constraintWeight = 10;
}; };
void ice40DelayFuzzerMain(Context *ctx); void ice40DelayFuzzerMain(Context *ctx);

View File

@ -870,12 +870,14 @@ bool read_asc(Context *ctx, std::istream &in)
} }
if (isUsed) { if (isUsed) {
NetInfo *net = ctx->wire_to_net[pi.dst]; NetInfo *net = ctx->wire_to_net[pi.dst];
if (net!=nullptr) {
WireId wire; WireId wire;
wire.index = pi.dst; wire.index = pi.dst;
ctx->unbindWire(wire); ctx->unbindWire(wire);
ctx->bindPip(pip, net, STRENGTH_WEAK); ctx->bindPip(pip, net, STRENGTH_WEAK);
} }
} }
}
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
if (ctx->getBelType(bel) == id_ICESTORM_LC) { if (ctx->getBelType(bel) == id_ICESTORM_LC) {
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];

View File

@ -28,6 +28,7 @@ NEXTPNR_NAMESPACE_BEGIN
void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir)
{ {
IdString id = ctx->id(name); IdString id = ctx->id(name);
NPNR_ASSERT(cell->ports.count(id) == 0);
cell->ports[id] = PortInfo{id, nullptr, dir}; cell->ports[id] = PortInfo{id, nullptr, dir};
} }
@ -237,7 +238,7 @@ std::unique_ptr<CellInfo> create_ice_cell(Context *ctx, IdString type, std::stri
add_port(ctx, new_cell.get(), "SCLK", PORT_IN); add_port(ctx, new_cell.get(), "SCLK", PORT_IN);
add_port(ctx, new_cell.get(), "SDI", PORT_IN); add_port(ctx, new_cell.get(), "SDI", PORT_IN);
add_port(ctx, new_cell.get(), "SDI", PORT_OUT); add_port(ctx, new_cell.get(), "SDO", PORT_OUT);
add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); add_port(ctx, new_cell.get(), "LOCK", PORT_OUT);
add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT);

View File

@ -50,6 +50,7 @@ tiletypes = dict()
wiretypes = dict() wiretypes = dict()
gfx_wire_ids = dict() gfx_wire_ids = dict()
gfx_wire_names = list()
wire_segments = dict() wire_segments = dict()
fast_timings = None fast_timings = None
@ -93,6 +94,136 @@ with open(args.gfxh) as f:
idx = len(gfx_wire_ids) idx = len(gfx_wire_ids)
name = line.strip().rstrip(",") name = line.strip().rstrip(",")
gfx_wire_ids[name] = idx gfx_wire_ids[name] = idx
gfx_wire_names.append(name)
def gfx_wire_alias(old, new):
assert old in gfx_wire_ids
assert new not in gfx_wire_ids
gfx_wire_ids[new] = gfx_wire_ids[old]
# GFX aliases for RAM tiles
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_RAM_RADDR_0")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_RAM_RADDR_1")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_2", "TILE_WIRE_RAM_RADDR_2")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_RAM_RADDR_3")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_0", "TILE_WIRE_RAM_RADDR_4")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_1", "TILE_WIRE_RAM_RADDR_5")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_2", "TILE_WIRE_RAM_RADDR_6")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_3", "TILE_WIRE_RAM_RADDR_7")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_0", "TILE_WIRE_RAM_RADDR_8")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_1", "TILE_WIRE_RAM_RADDR_9")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_2", "TILE_WIRE_RAM_RADDR_10")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_RAM_WADDR_0")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_RAM_WADDR_1")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_2", "TILE_WIRE_RAM_WADDR_2")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_RAM_WADDR_3")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_0", "TILE_WIRE_RAM_WADDR_4")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_1", "TILE_WIRE_RAM_WADDR_5")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_2", "TILE_WIRE_RAM_WADDR_6")
gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_3", "TILE_WIRE_RAM_WADDR_7")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_0", "TILE_WIRE_RAM_WADDR_8")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_1", "TILE_WIRE_RAM_WADDR_9")
gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_2", "TILE_WIRE_RAM_WADDR_10")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_0", "TILE_WIRE_RAM_MASK_0")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_1", "TILE_WIRE_RAM_MASK_1")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_2", "TILE_WIRE_RAM_MASK_2")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_3", "TILE_WIRE_RAM_MASK_3")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_RAM_MASK_4")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_RAM_MASK_5")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_2", "TILE_WIRE_RAM_MASK_6")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_RAM_MASK_7")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_0", "TILE_WIRE_RAM_MASK_8")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_1", "TILE_WIRE_RAM_MASK_9")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_2", "TILE_WIRE_RAM_MASK_10")
gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_3", "TILE_WIRE_RAM_MASK_11")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_RAM_MASK_12")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_RAM_MASK_13")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_2", "TILE_WIRE_RAM_MASK_14")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_RAM_MASK_15")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_0", "TILE_WIRE_RAM_WDATA_0")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_1", "TILE_WIRE_RAM_WDATA_1")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_2", "TILE_WIRE_RAM_WDATA_2")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_3", "TILE_WIRE_RAM_WDATA_3")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_0", "TILE_WIRE_RAM_WDATA_4")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_1", "TILE_WIRE_RAM_WDATA_5")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_2", "TILE_WIRE_RAM_WDATA_6")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_3", "TILE_WIRE_RAM_WDATA_7")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_0", "TILE_WIRE_RAM_WDATA_8")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_1", "TILE_WIRE_RAM_WDATA_9")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_2", "TILE_WIRE_RAM_WDATA_10")
gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_3", "TILE_WIRE_RAM_WDATA_11")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_0", "TILE_WIRE_RAM_WDATA_12")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_1", "TILE_WIRE_RAM_WDATA_13")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_2", "TILE_WIRE_RAM_WDATA_14")
gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_3", "TILE_WIRE_RAM_WDATA_15")
gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_RAM_RDATA_0")
gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_RAM_RDATA_1")
gfx_wire_alias("TILE_WIRE_LUTFF_2_OUT", "TILE_WIRE_RAM_RDATA_2")
gfx_wire_alias("TILE_WIRE_LUTFF_3_OUT", "TILE_WIRE_RAM_RDATA_3")
gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_RAM_RDATA_4")
gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_RAM_RDATA_5")
gfx_wire_alias("TILE_WIRE_LUTFF_6_OUT", "TILE_WIRE_RAM_RDATA_6")
gfx_wire_alias("TILE_WIRE_LUTFF_7_OUT", "TILE_WIRE_RAM_RDATA_7")
gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_RAM_RDATA_8")
gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_RAM_RDATA_9")
gfx_wire_alias("TILE_WIRE_LUTFF_2_OUT", "TILE_WIRE_RAM_RDATA_10")
gfx_wire_alias("TILE_WIRE_LUTFF_3_OUT", "TILE_WIRE_RAM_RDATA_11")
gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_RAM_RDATA_12")
gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_RAM_RDATA_13")
gfx_wire_alias("TILE_WIRE_LUTFF_6_OUT", "TILE_WIRE_RAM_RDATA_14")
gfx_wire_alias("TILE_WIRE_LUTFF_7_OUT", "TILE_WIRE_RAM_RDATA_15")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_RAM_RCLKE")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_RAM_WCLKE")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_RAM_RCLK")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_RAM_WCLK")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_RAM_RE")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_RAM_WE")
# GFX aliases for IO tiles
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_IO_0_D_OUT_0")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_IO_0_D_OUT_1")
gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_IO_0_OUT_ENB")
gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_IO_0_D_IN_0")
gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_IO_0_D_IN_1")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_IO_1_D_OUT_0")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_IO_1_D_OUT_1")
gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_IO_1_OUT_ENB")
gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_IO_1_D_IN_0")
gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_IO_1_D_IN_1")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_IO_GLOBAL_CEN")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_IO_GLOBAL_INCLK")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_IO_GLOBAL_OUTCLK")
gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_G0", "TILE_WIRE_IO_GLOBAL_LATCH")
for neigh in "BNL BNR BOT LFT RGT TNL TNR TOP".split():
for i in range(8):
gfx_wire_alias("TILE_WIRE_NEIGH_OP_%s_%d" % (neigh, i), "TILE_WIRE_LOGIC_OP_%s_%d" % (neigh, i))
# End of GFX aliases
def read_timings(filename): def read_timings(filename):
db = dict() db = dict()
@ -165,6 +296,18 @@ def maj_wire_name(name):
return name[2] in ("sp12_v_b_0", "sp12_v_b_1") return name[2] in ("sp12_v_b_0", "sp12_v_b_1")
return False return False
def norm_wire_xy(x, y, name):
if name.startswith("glb_netwk_"):
return None
if name.startswith("neigh_op_"):
return None
if name.startswith("logic_op_"):
return None
if name.startswith("io_global/latch"):
return None
return None # FIXME
return (x, y)
def cmp_wire_names(newname, oldname): def cmp_wire_names(newname, oldname):
if maj_wire_name(newname): if maj_wire_name(newname):
return True return True
@ -508,11 +651,13 @@ with open(args.filename, "r") as f:
wire_names_r[mode[1]] = wname wire_names_r[mode[1]] = wname
if mode[1] not in wire_xy: if mode[1] not in wire_xy:
wire_xy[mode[1]] = list() wire_xy[mode[1]] = list()
wire_xy[mode[1]].append((int(line[0]), int(line[1]))) wire_xy[mode[1]].append(wname)
if mode[1] not in wire_segments: if mode[1] not in wire_segments:
wire_segments[mode[1]] = dict() wire_segments[mode[1]] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids: if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
wire_segments[mode[1]][(wname[0], wname[1])] = wname[2] if (wname[0], wname[1]) not in wire_segments[mode[1]]:
wire_segments[mode[1]][(wname[0], wname[1])] = list()
wire_segments[mode[1]][(wname[0], wname[1])].append(wname[2])
continue continue
if mode[0] in ("buffer", "routing"): if mode[0] in ("buffer", "routing"):
@ -561,7 +706,9 @@ def add_wire(x, y, name):
wire_names_r[wire_idx] = wname wire_names_r[wire_idx] = wname
wire_segments[wire_idx] = dict() wire_segments[wire_idx] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids: if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
wire_segments[wire_idx][(wname[0], wname[1])] = wname[2] if (wname[0], wname[1]) not in wire_segments[wire_idx]:
wire_segments[wire_idx][(wname[0], wname[1])] = list()
wire_segments[wire_idx][(wname[0], wname[1])].append(wname[2])
return wire_idx return wire_idx
def add_switch(x, y, bel=-1): def add_switch(x, y, bel=-1):
@ -580,10 +727,6 @@ def add_pip(src, dst, flags=0):
pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1, flags) pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1, flags)
# Add virtual padin wires
for i in range(8):
add_wire(0, 0, "padin_%d" % i)
def add_bel_input(bel, wire, port): def add_bel_input(bel, wire, port):
if wire not in wire_belports: if wire not in wire_belports:
wire_belports[wire] = set() wire_belports[wire] = set()
@ -932,6 +1075,10 @@ bba.post('NEXTPNR_NAMESPACE_END')
bba.push("chipdb_blob_%s" % dev_name) bba.push("chipdb_blob_%s" % dev_name)
bba.r("chip_info_%s" % dev_name, "chip_info") bba.r("chip_info_%s" % dev_name, "chip_info")
bba.l("tile_wire_names")
for name in gfx_wire_names:
bba.s(name, name)
for bel in range(len(bel_name)): for bel in range(len(bel_name)):
bba.l("bel_wires_%d" % bel, "BelWirePOD") bba.l("bel_wires_%d" % bel, "BelWirePOD")
for data in sorted(bel_wires[bel]): for data in sorted(bel_wires[bel]):
@ -1028,20 +1175,32 @@ for wire in range(num_wires):
info["num_bel_pins"] = num_bel_pins info["num_bel_pins"] = num_bel_pins
info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None
pos_xy = None
first = None
if wire in wire_xy: if wire in wire_xy:
avg_x, avg_y = 0, 0 for x, y, n in wire_xy[wire]:
norm_xy = norm_wire_xy(x, y, n)
if norm_xy is None:
continue
if pos_xy is None:
pos_xy = norm_xy
first = (x, y, n)
elif pos_xy != norm_xy:
print("Conflicting positions for wire %s: (%d, %d, %s) -> (%d, %d), (%d, %d, %s) -> (%d, %d)" % \
((info["name"],) + first + pos_xy + (x, y, n) + norm_xy), file=sys.stderr)
assert 0
if (pos_xy is None) and (len(wire_xy[wire]) > 1):
# print("Only 'None' positions for wire %s." % info["name"], file=sys.stderr)
# assert 0
pass
for x, y in wire_xy[wire]: if pos_xy is None:
avg_x += x
avg_y += y
avg_x /= len(wire_xy[wire])
avg_y /= len(wire_xy[wire])
info["x"] = int(round(avg_x))
info["y"] = int(round(avg_y))
else:
info["x"] = wire_names_r[wire][0] info["x"] = wire_names_r[wire][0]
info["y"] = wire_names_r[wire][1] info["y"] = wire_names_r[wire][1]
else:
info["x"] = pos_xy[0]
info["y"] = pos_xy[1]
wireinfo.append(info) wireinfo.append(info)
@ -1108,8 +1267,13 @@ for wire, info in enumerate(wireinfo):
bba.r(info["list_downhill"], "pips_downhill") bba.r(info["list_downhill"], "pips_downhill")
bba.u32(info["num_bel_pins"], "num_bel_pins") bba.u32(info["num_bel_pins"], "num_bel_pins")
bba.r(info["list_bel_pins"], "bel_pins") bba.r(info["list_bel_pins"], "bel_pins")
bba.u32(len(wire_segments[wire]), "num_segments")
if len(wire_segments[wire]): num_segments = 0
for segs in wire_segments[wire].values():
num_segments += len(segs)
bba.u32(num_segments, "num_segments")
if num_segments:
bba.r("wire_segments_%d" % wire, "segments") bba.r("wire_segments_%d" % wire, "segments")
else: else:
bba.u32(0, "segments") bba.u32(0, "segments")
@ -1125,7 +1289,8 @@ for wire, info in enumerate(wireinfo):
for wire in range(num_wires): for wire in range(num_wires):
if len(wire_segments[wire]): if len(wire_segments[wire]):
bba.l("wire_segments_%d" % wire, "WireSegmentPOD") bba.l("wire_segments_%d" % wire, "WireSegmentPOD")
for xy, seg in sorted(wire_segments[wire].items()): for xy, segs in sorted(wire_segments[wire].items()):
for seg in segs:
bba.u8(xy[0], "x") bba.u8(xy[0], "x")
bba.u8(xy[1], "y") bba.u8(xy[1], "y")
bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index") bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
@ -1135,14 +1300,14 @@ for info in pipinfo:
src_seg = -1 src_seg = -1
src_segname = wire_names_r[info["src"]] src_segname = wire_names_r[info["src"]]
if (info["x"], info["y"]) in wire_segments[info["src"]]: if (info["x"], info["y"]) in wire_segments[info["src"]]:
src_segname = wire_segments[info["src"]][(info["x"], info["y"])] src_segname = wire_segments[info["src"]][(info["x"], info["y"])][0]
src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")] src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")]
src_segname = src_segname.replace("/", ".") src_segname = src_segname.replace("/", ".")
dst_seg = -1 dst_seg = -1
dst_segname = wire_names_r[info["dst"]] dst_segname = wire_names_r[info["dst"]]
if (info["x"], info["y"]) in wire_segments[info["dst"]]: if (info["x"], info["y"]) in wire_segments[info["dst"]]:
dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])] dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])][0]
dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")] dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")]
dst_segname = dst_segname.replace("/", ".") dst_segname = dst_segname.replace("/", ".")
@ -1276,5 +1441,6 @@ bba.r("bits_info_%s" % dev_name, "bits_info")
bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config") bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config")
bba.r("package_info_%s" % dev_name, "packages_data") bba.r("package_info_%s" % dev_name, "packages_data")
bba.r("cell_timings_%s" % dev_name, "cell_timing") bba.r("cell_timings_%s" % dev_name, "cell_timing")
bba.r("tile_wire_names", "tile_wire_names")
bba.pop() bba.pop()

View File

@ -36,7 +36,7 @@ if (MSVC)
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB} add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}
DEPENDS ${DEV_TXT_DB} ${DB_PY} DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
) )
add_custom_command(OUTPUT ${DEV_CC_DB} add_custom_command(OUTPUT ${DEV_CC_DB}
COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB} COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB}
@ -69,7 +69,7 @@ else()
add_custom_command(OUTPUT ${DEV_CC_BBA_DB} add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new
COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
DEPENDS ${DEV_TXT_DB} ${DB_PY} DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
) )
add_custom_command(OUTPUT ${DEV_CC_DB} add_custom_command(OUTPUT ${DEV_CC_DB}
COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new

View File

@ -21,7 +21,7 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style) void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, int w, int h, GfxTileWireId id, GraphicElement::style_t style)
{ {
GraphicElement el; GraphicElement el;
el.type = GraphicElement::TYPE_LINE; el.type = GraphicElement::TYPE_LINE;
@ -339,6 +339,168 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
g.push_back(el); g.push_back(el);
} }
// IO Span-4 Wires connecting to fabric
if (id >= TILE_WIRE_SPAN4_HORZ_0 && id <= TILE_WIRE_SPAN4_HORZ_47) {
int idx = id - TILE_WIRE_SPAN4_HORZ_0;
float y1 = y + 1.0 - (0.03 + 0.0025 * (48 - (idx ^ 1)));
el.x1 = x;
el.x2 = x + 1.0;
el.y1 = y1;
el.y2 = y1;
g.push_back(el);
el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
el.x2 = el.x1;
el.y1 = y1;
el.y2 = y + main_swbox_y2;
g.push_back(el);
}
if (id >= TILE_WIRE_SPAN4_VERT_0 && id <= TILE_WIRE_SPAN4_VERT_47) {
int idx = id - TILE_WIRE_SPAN4_VERT_0;
float x1 = x + 0.03 + 0.0025 * (48 - (idx ^ 1));
el.x1 = x1;
el.x2 = x1;
el.y1 = y;
el.y2 = y + 1.0;
g.push_back(el);
el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
el.y2 = el.y1;
el.x1 = x1;
el.x2 = x + main_swbox_x1;
g.push_back(el);
}
// IO Span-12 Wires connecting to fabric
if (id >= TILE_WIRE_SPAN12_HORZ_0 && id <= TILE_WIRE_SPAN12_HORZ_23) {
int idx = id - TILE_WIRE_SPAN12_HORZ_0;
float y1 = y + 1.0 - (0.03 + 0.0025 * (88 - (idx ^ 1)));
el.x1 = x;
el.x2 = x + 1.0;
el.y1 = y1;
el.y2 = y1;
g.push_back(el);
el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
el.x2 = el.x1;
el.y1 = y1;
el.y2 = y + main_swbox_y2;
g.push_back(el);
}
if (id >= TILE_WIRE_SPAN12_VERT_0 && id <= TILE_WIRE_SPAN12_VERT_23) {
int idx = id - TILE_WIRE_SPAN12_VERT_0;
float x1 = x + 0.03 + 0.0025 * (88 - (idx ^ 1));
el.x1 = x1;
el.x2 = x1;
el.y1 = y;
el.y2 = y + 1.0;
g.push_back(el);
el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
el.y2 = el.y1;
el.x1 = x1;
el.x2 = x + main_swbox_x1;
g.push_back(el);
}
// Horizontal IO Span-4 Wires
if (id >= TILE_WIRE_SPAN4_HORZ_R_0 && id <= TILE_WIRE_SPAN4_HORZ_L_15) {
int idx = id - TILE_WIRE_SPAN4_HORZ_R_0;
float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx));
float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - idx - 4));
el.x1 = x;
el.x2 = x + 0.9;
el.y1 = y1;
el.y2 = y1;
g.push_back(el);
if (idx <= 15) {
el.x1 = x + 0.9;
el.x2 = x + 1.0;
el.y1 = y1;
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.y2 = y + main_swbox_y2;
g.push_back(el);
}
// Vertical IO Span-4 Wires
if (id >= TILE_WIRE_SPAN4_VERT_B_0 && id <= TILE_WIRE_SPAN4_VERT_T_15) {
int idx = id - TILE_WIRE_SPAN4_VERT_B_0;
float x1 = x + 0.03 + 0.0025 * (60 - idx);
float x2 = x + 0.03 + 0.0025 * (60 - idx - 4);
el.y1 = y + 1.00;
el.y2 = y + 0.10;
el.x1 = x1;
el.x2 = x1;
g.push_back(el);
if (idx <= 15) {
el.y1 = y + 0.10;
el.y2 = y;
el.x1 = x1;
el.x2 = x2;
g.push_back(el);
}
if (idx <= 15 && (x == 0 || x == w-1) && y == 1) {
float y1 = y - (0.03 + 0.0025 * (60 - idx - 4));
el.x1 = x2;
el.y1 = y;
el.x2 = x2;
el.y2 = y1;
g.push_back(el);
el.x1 = x2;
el.y1 = y1;
el.x2 = x + (x == 0);
el.y2 = y1;
g.push_back(el);
}
if (idx >= 4 && (x == 0 || x == w-1) && y == h-2) {
float y1 = y + 2.0 - (0.03 + 0.0025 * (60 - idx));
el.x1 = x1;
el.y1 = y + 1.0;
el.x2 = x1;
el.y2 = y1;
g.push_back(el);
el.x1 = x1;
el.y1 = y1;
el.x2 = x + (x == 0);
el.y2 = y1;
g.push_back(el);
}
el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx));
el.y2 = el.y1;
el.x1 = x1;
el.x2 = x + main_swbox_x1;
g.push_back(el);
}
// Global2Local // Global2Local
if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
@ -392,7 +554,7 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
int input = idx % 4; int input = idx % 4;
el.x1 = x + local_swbox_x2; el.x1 = x + local_swbox_x2;
el.x2 = x + lut_swbox_x1; el.x2 = x + lut_swbox_x1;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * input) + z * logic_cell_pitch;
el.y2 = el.y1; el.y2 = el.y1;
g.push_back(el); g.push_back(el);
} }
@ -403,7 +565,7 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
int input = idx % 4; int input = idx % 4;
el.x1 = x + lut_swbox_x2; el.x1 = x + lut_swbox_x2;
el.x2 = x + logic_cell_x1; el.x2 = x + logic_cell_x1;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * input) + z * logic_cell_pitch;
el.y2 = el.y1; el.y2 = el.y1;
g.push_back(el); g.push_back(el);
} }
@ -457,6 +619,42 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
} }
} }
// LC Control for IO and BRAM
if (id >= TILE_WIRE_FUNC_GLOBAL_CEN && id <= TILE_WIRE_FUNC_GLOBAL_S_R) {
int idx = id - TILE_WIRE_FUNC_GLOBAL_CEN;
el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5);
el.x2 = el.x1;
el.y1 = y + main_swbox_y1;
el.y2 = el.y1 - 0.005 * (idx + 2);
g.push_back(el);
el.y1 = el.y2;
el.x2 = x + logic_cell_x2 - 0.005 * (2 - idx + 5);
g.push_back(el);
el.y2 = y + logic_cell_y1;
el.x1 = el.x2;
g.push_back(el);
}
if (id == TILE_WIRE_FABOUT) {
el.y1 = y + main_swbox_y1;
el.y2 = el.y1 - 0.005 * 4;
el.x1 = x + main_swbox_x2 - 0.005 * 9;
el.x2 = el.x1;
g.push_back(el);
}
if (id == TILE_WIRE_FUNC_GLOBAL_G0) {
el.y1 = y + logic_cell_y1;
el.y2 = el.y1 - 0.005 * 4;
el.x1 = x + logic_cell_x2 - 0.005 * 3;
el.x2 = el.x1;
g.push_back(el);
}
// LC Cascade // LC Cascade
if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) { if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) {
@ -571,6 +769,54 @@ static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
return true; return true;
} }
// IO Span-4 Wires connecting to fabric
if (id >= TILE_WIRE_SPAN4_HORZ_0 && id <= TILE_WIRE_SPAN4_HORZ_47) {
int idx = id - TILE_WIRE_SPAN4_HORZ_0;
x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
y = main_swbox_y2;
return true;
}
if (id >= TILE_WIRE_SPAN4_VERT_0 && id <= TILE_WIRE_SPAN4_VERT_47) {
int idx = id - TILE_WIRE_SPAN4_VERT_0;
y = 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
x = main_swbox_x1;
return true;
}
// IO Span-12 Wires connecting to fabric
if (id >= TILE_WIRE_SPAN12_HORZ_0 && id <= TILE_WIRE_SPAN12_HORZ_23) {
int idx = id - TILE_WIRE_SPAN12_HORZ_0;
x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
y = main_swbox_y2;
return true;
}
if (id >= TILE_WIRE_SPAN12_VERT_0 && id <= TILE_WIRE_SPAN12_VERT_23) {
int idx = id - TILE_WIRE_SPAN12_VERT_0;
y = 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
x = main_swbox_x1;
return true;
}
// IO Span-4 Wires
if (id >= TILE_WIRE_SPAN4_HORZ_R_0 && id <= TILE_WIRE_SPAN4_HORZ_L_15) {
int idx = id - TILE_WIRE_SPAN4_HORZ_R_0;
y = main_swbox_y2;
x = main_swbox_x1 + 0.0025 * (idx + 35);
return true;
}
if (id >= TILE_WIRE_SPAN4_VERT_B_0 && id <= TILE_WIRE_SPAN4_VERT_T_15) {
int idx = id - TILE_WIRE_SPAN4_VERT_B_0;
y = 1.0 - (0.03 + 0.0025 * (270 - idx));
x = main_swbox_x1;
return true;
}
// Global2Local // Global2Local
if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
@ -626,6 +872,19 @@ static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
return true; return true;
} }
if (id >= TILE_WIRE_FUNC_GLOBAL_CEN && id <= TILE_WIRE_FUNC_GLOBAL_S_R) {
int idx = id - TILE_WIRE_FUNC_GLOBAL_CEN;
x = main_swbox_x2 - 0.005 * (idx + 5);
y = main_swbox_y1;
return true;
}
if (id == TILE_WIRE_FABOUT) {
x = main_swbox_x2 - 0.005 * 9;
y = main_swbox_y1;
return true;
}
return false; return false;
} }
@ -662,22 +921,22 @@ void pipGfx(std::vector<GraphicElement> &g, int x, int y, float x1, float y1, fl
el.style = style; el.style = style;
if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) { if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) {
tx = x1 + 0.25 * fabsf(y1 - y2); tx = swx1 + 0.25 * fabsf(y1 - y2);
goto edge_pip; goto edge_pip;
} }
if (fabsf(x1 - swx2) < 0.001 && fabsf(x2 - swx2) < 0.001) { if (fabsf(x1 - swx2) < 0.001 && fabsf(x2 - swx2) < 0.001) {
tx = x1 - 0.25 * fabsf(y1 - y2); tx = swx2 - 0.25 * fabsf(y1 - y2);
goto edge_pip; goto edge_pip;
} }
if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) { if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
ty = y1 + 0.25 * fabsf(x1 - x2); ty = swy1 + 0.25 * fabsf(x1 - x2);
goto edge_pip; goto edge_pip;
} }
if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) { if (fabsf(y1 - swy2) < 0.001 && fabsf(y2 - swy2) < 0.001) {
ty = y1 + 0.25 * fabsf(x1 - x2); ty = swy2 - 0.25 * fabsf(x1 - x2);
goto edge_pip; goto edge_pip;
} }
@ -727,7 +986,7 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
el.style = style; el.style = style;
el.x1 = x + logic_cell_x1; el.x1 = x + logic_cell_x1;
el.x2 = x + logic_cell_x2; el.x2 = x + logic_cell_x2;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch; el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * in_idx) + lut_idx * logic_cell_pitch;
el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + lut_idx * logic_cell_pitch; el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + lut_idx * logic_cell_pitch;
g.push_back(el); g.push_back(el);
return; return;
@ -744,8 +1003,46 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
el.style = style; el.style = style;
el.x1 = x + lut_swbox_x1; el.x1 = x + lut_swbox_x1;
el.x2 = x + lut_swbox_x2; el.x2 = x + lut_swbox_x2;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch; el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * in_idx) + lut_idx * logic_cell_pitch;
el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * out_idx) + lut_idx * logic_cell_pitch; el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * out_idx) + lut_idx * logic_cell_pitch;
g.push_back(el);
return;
}
if ((src == TILE_WIRE_CARRY_IN_MUX || (src >= TILE_WIRE_LUTFF_0_COUT && src <= TILE_WIRE_LUTFF_6_COUT)) &&
(dst >= TILE_WIRE_LUTFF_0_IN_0 && dst <= TILE_WIRE_LUTFF_7_IN_3 && (dst - TILE_WIRE_LUTFF_0_IN_0) % 4 == 3)) {
int lut_idx = (dst - TILE_WIRE_LUTFF_0_IN_0) / 4;
GraphicElement el;
el.type = GraphicElement::TYPE_ARROW;
el.style = style;
el.x1 = x + (local_swbox_x2 + lut_swbox_x1) / 2;
el.x2 = el.x1;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * 3) + lut_idx * logic_cell_pitch;
el.y2 = y + (logic_cell_y1 + logic_cell_y2 - logic_cell_pitch) / 2 + lut_idx * logic_cell_pitch;
g.push_back(el);
el.x1 = x + logic_cell_x1 + 0.005 * 3;
el.y1 = el.y2;
g.push_back(el);
return;
}
if ((src >= TILE_WIRE_LUTFF_0_LOUT && src <= TILE_WIRE_LUTFF_6_LOUT) &&
(dst >= TILE_WIRE_LUTFF_0_IN_0 && dst <= TILE_WIRE_LUTFF_7_IN_3 && (dst - TILE_WIRE_LUTFF_0_IN_0) % 4 == 2)) {
int lut_idx = (dst - TILE_WIRE_LUTFF_0_IN_0) / 4;
GraphicElement el;
el.type = GraphicElement::TYPE_ARROW;
el.style = style;
el.x1 = x + (local_swbox_x2 + lut_swbox_x1) / 2 + 0.005;
el.x2 = el.x1;
el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 + 0.0075 - (0.005 * 2) + lut_idx * logic_cell_pitch;
el.y2 = y + (logic_cell_y1 + logic_cell_y2 - logic_cell_pitch) / 2 + lut_idx * logic_cell_pitch + 0.003;
g.push_back(el);
el.x1 = x + logic_cell_x1 + 0.005 * 5;
el.y1 = el.y2;
g.push_back(el); g.push_back(el);
return; return;
} }

View File

@ -205,6 +205,13 @@ enum GfxTileWireId
TILE_WIRE_LUTFF_GLOBAL_CLK, TILE_WIRE_LUTFF_GLOBAL_CLK,
TILE_WIRE_LUTFF_GLOBAL_S_R, TILE_WIRE_LUTFF_GLOBAL_S_R,
TILE_WIRE_FUNC_GLOBAL_CEN,
TILE_WIRE_FUNC_GLOBAL_CLK,
TILE_WIRE_FUNC_GLOBAL_S_R,
TILE_WIRE_FUNC_GLOBAL_G0,
TILE_WIRE_FABOUT,
TILE_WIRE_CARRY_IN, TILE_WIRE_CARRY_IN,
TILE_WIRE_CARRY_IN_MUX, TILE_WIRE_CARRY_IN_MUX,
@ -509,12 +516,205 @@ enum GfxTileWireId
TILE_WIRE_SP12_H_L_22, TILE_WIRE_SP12_H_L_22,
TILE_WIRE_SP12_H_L_23, TILE_WIRE_SP12_H_L_23,
TILE_WIRE_SPAN4_VERT_0,
TILE_WIRE_SPAN4_VERT_1,
TILE_WIRE_SPAN4_VERT_2,
TILE_WIRE_SPAN4_VERT_3,
TILE_WIRE_SPAN4_VERT_4,
TILE_WIRE_SPAN4_VERT_5,
TILE_WIRE_SPAN4_VERT_6,
TILE_WIRE_SPAN4_VERT_7,
TILE_WIRE_SPAN4_VERT_8,
TILE_WIRE_SPAN4_VERT_9,
TILE_WIRE_SPAN4_VERT_10,
TILE_WIRE_SPAN4_VERT_11,
TILE_WIRE_SPAN4_VERT_12,
TILE_WIRE_SPAN4_VERT_13,
TILE_WIRE_SPAN4_VERT_14,
TILE_WIRE_SPAN4_VERT_15,
TILE_WIRE_SPAN4_VERT_16,
TILE_WIRE_SPAN4_VERT_17,
TILE_WIRE_SPAN4_VERT_18,
TILE_WIRE_SPAN4_VERT_19,
TILE_WIRE_SPAN4_VERT_20,
TILE_WIRE_SPAN4_VERT_21,
TILE_WIRE_SPAN4_VERT_22,
TILE_WIRE_SPAN4_VERT_23,
TILE_WIRE_SPAN4_VERT_24,
TILE_WIRE_SPAN4_VERT_25,
TILE_WIRE_SPAN4_VERT_26,
TILE_WIRE_SPAN4_VERT_27,
TILE_WIRE_SPAN4_VERT_28,
TILE_WIRE_SPAN4_VERT_29,
TILE_WIRE_SPAN4_VERT_30,
TILE_WIRE_SPAN4_VERT_31,
TILE_WIRE_SPAN4_VERT_32,
TILE_WIRE_SPAN4_VERT_33,
TILE_WIRE_SPAN4_VERT_34,
TILE_WIRE_SPAN4_VERT_35,
TILE_WIRE_SPAN4_VERT_36,
TILE_WIRE_SPAN4_VERT_37,
TILE_WIRE_SPAN4_VERT_38,
TILE_WIRE_SPAN4_VERT_39,
TILE_WIRE_SPAN4_VERT_40,
TILE_WIRE_SPAN4_VERT_41,
TILE_WIRE_SPAN4_VERT_42,
TILE_WIRE_SPAN4_VERT_43,
TILE_WIRE_SPAN4_VERT_44,
TILE_WIRE_SPAN4_VERT_45,
TILE_WIRE_SPAN4_VERT_46,
TILE_WIRE_SPAN4_VERT_47,
TILE_WIRE_SPAN4_HORZ_0,
TILE_WIRE_SPAN4_HORZ_1,
TILE_WIRE_SPAN4_HORZ_2,
TILE_WIRE_SPAN4_HORZ_3,
TILE_WIRE_SPAN4_HORZ_4,
TILE_WIRE_SPAN4_HORZ_5,
TILE_WIRE_SPAN4_HORZ_6,
TILE_WIRE_SPAN4_HORZ_7,
TILE_WIRE_SPAN4_HORZ_8,
TILE_WIRE_SPAN4_HORZ_9,
TILE_WIRE_SPAN4_HORZ_10,
TILE_WIRE_SPAN4_HORZ_11,
TILE_WIRE_SPAN4_HORZ_12,
TILE_WIRE_SPAN4_HORZ_13,
TILE_WIRE_SPAN4_HORZ_14,
TILE_WIRE_SPAN4_HORZ_15,
TILE_WIRE_SPAN4_HORZ_16,
TILE_WIRE_SPAN4_HORZ_17,
TILE_WIRE_SPAN4_HORZ_18,
TILE_WIRE_SPAN4_HORZ_19,
TILE_WIRE_SPAN4_HORZ_20,
TILE_WIRE_SPAN4_HORZ_21,
TILE_WIRE_SPAN4_HORZ_22,
TILE_WIRE_SPAN4_HORZ_23,
TILE_WIRE_SPAN4_HORZ_24,
TILE_WIRE_SPAN4_HORZ_25,
TILE_WIRE_SPAN4_HORZ_26,
TILE_WIRE_SPAN4_HORZ_27,
TILE_WIRE_SPAN4_HORZ_28,
TILE_WIRE_SPAN4_HORZ_29,
TILE_WIRE_SPAN4_HORZ_30,
TILE_WIRE_SPAN4_HORZ_31,
TILE_WIRE_SPAN4_HORZ_32,
TILE_WIRE_SPAN4_HORZ_33,
TILE_WIRE_SPAN4_HORZ_34,
TILE_WIRE_SPAN4_HORZ_35,
TILE_WIRE_SPAN4_HORZ_36,
TILE_WIRE_SPAN4_HORZ_37,
TILE_WIRE_SPAN4_HORZ_38,
TILE_WIRE_SPAN4_HORZ_39,
TILE_WIRE_SPAN4_HORZ_40,
TILE_WIRE_SPAN4_HORZ_41,
TILE_WIRE_SPAN4_HORZ_42,
TILE_WIRE_SPAN4_HORZ_43,
TILE_WIRE_SPAN4_HORZ_44,
TILE_WIRE_SPAN4_HORZ_45,
TILE_WIRE_SPAN4_HORZ_46,
TILE_WIRE_SPAN4_HORZ_47,
TILE_WIRE_SPAN12_VERT_0,
TILE_WIRE_SPAN12_VERT_1,
TILE_WIRE_SPAN12_VERT_2,
TILE_WIRE_SPAN12_VERT_3,
TILE_WIRE_SPAN12_VERT_4,
TILE_WIRE_SPAN12_VERT_5,
TILE_WIRE_SPAN12_VERT_6,
TILE_WIRE_SPAN12_VERT_7,
TILE_WIRE_SPAN12_VERT_8,
TILE_WIRE_SPAN12_VERT_9,
TILE_WIRE_SPAN12_VERT_10,
TILE_WIRE_SPAN12_VERT_11,
TILE_WIRE_SPAN12_VERT_12,
TILE_WIRE_SPAN12_VERT_13,
TILE_WIRE_SPAN12_VERT_14,
TILE_WIRE_SPAN12_VERT_15,
TILE_WIRE_SPAN12_VERT_16,
TILE_WIRE_SPAN12_VERT_17,
TILE_WIRE_SPAN12_VERT_18,
TILE_WIRE_SPAN12_VERT_19,
TILE_WIRE_SPAN12_VERT_20,
TILE_WIRE_SPAN12_VERT_21,
TILE_WIRE_SPAN12_VERT_22,
TILE_WIRE_SPAN12_VERT_23,
TILE_WIRE_SPAN12_HORZ_0,
TILE_WIRE_SPAN12_HORZ_1,
TILE_WIRE_SPAN12_HORZ_2,
TILE_WIRE_SPAN12_HORZ_3,
TILE_WIRE_SPAN12_HORZ_4,
TILE_WIRE_SPAN12_HORZ_5,
TILE_WIRE_SPAN12_HORZ_6,
TILE_WIRE_SPAN12_HORZ_7,
TILE_WIRE_SPAN12_HORZ_8,
TILE_WIRE_SPAN12_HORZ_9,
TILE_WIRE_SPAN12_HORZ_10,
TILE_WIRE_SPAN12_HORZ_11,
TILE_WIRE_SPAN12_HORZ_12,
TILE_WIRE_SPAN12_HORZ_13,
TILE_WIRE_SPAN12_HORZ_14,
TILE_WIRE_SPAN12_HORZ_15,
TILE_WIRE_SPAN12_HORZ_16,
TILE_WIRE_SPAN12_HORZ_17,
TILE_WIRE_SPAN12_HORZ_18,
TILE_WIRE_SPAN12_HORZ_19,
TILE_WIRE_SPAN12_HORZ_20,
TILE_WIRE_SPAN12_HORZ_21,
TILE_WIRE_SPAN12_HORZ_22,
TILE_WIRE_SPAN12_HORZ_23,
TILE_WIRE_SPAN4_VERT_B_0,
TILE_WIRE_SPAN4_VERT_B_1,
TILE_WIRE_SPAN4_VERT_B_2,
TILE_WIRE_SPAN4_VERT_B_3,
TILE_WIRE_SPAN4_VERT_B_4,
TILE_WIRE_SPAN4_VERT_B_5,
TILE_WIRE_SPAN4_VERT_B_6,
TILE_WIRE_SPAN4_VERT_B_7,
TILE_WIRE_SPAN4_VERT_B_8,
TILE_WIRE_SPAN4_VERT_B_9,
TILE_WIRE_SPAN4_VERT_B_10,
TILE_WIRE_SPAN4_VERT_B_11,
TILE_WIRE_SPAN4_VERT_B_12,
TILE_WIRE_SPAN4_VERT_B_13,
TILE_WIRE_SPAN4_VERT_B_14,
TILE_WIRE_SPAN4_VERT_B_15,
TILE_WIRE_SPAN4_VERT_T_12,
TILE_WIRE_SPAN4_VERT_T_13,
TILE_WIRE_SPAN4_VERT_T_14,
TILE_WIRE_SPAN4_VERT_T_15,
TILE_WIRE_SPAN4_HORZ_R_0,
TILE_WIRE_SPAN4_HORZ_R_1,
TILE_WIRE_SPAN4_HORZ_R_2,
TILE_WIRE_SPAN4_HORZ_R_3,
TILE_WIRE_SPAN4_HORZ_R_4,
TILE_WIRE_SPAN4_HORZ_R_5,
TILE_WIRE_SPAN4_HORZ_R_6,
TILE_WIRE_SPAN4_HORZ_R_7,
TILE_WIRE_SPAN4_HORZ_R_8,
TILE_WIRE_SPAN4_HORZ_R_9,
TILE_WIRE_SPAN4_HORZ_R_10,
TILE_WIRE_SPAN4_HORZ_R_11,
TILE_WIRE_SPAN4_HORZ_R_12,
TILE_WIRE_SPAN4_HORZ_R_13,
TILE_WIRE_SPAN4_HORZ_R_14,
TILE_WIRE_SPAN4_HORZ_R_15,
TILE_WIRE_SPAN4_HORZ_L_12,
TILE_WIRE_SPAN4_HORZ_L_13,
TILE_WIRE_SPAN4_HORZ_L_14,
TILE_WIRE_SPAN4_HORZ_L_15,
TILE_WIRE_PLLIN, TILE_WIRE_PLLIN,
TILE_WIRE_PLLOUT_A, TILE_WIRE_PLLOUT_A,
TILE_WIRE_PLLOUT_B TILE_WIRE_PLLOUT_B
}; };
void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style); void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, int w, int h, GfxTileWireId id,
GraphicElement::style_t style);
void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src, GfxTileWireId dst,
GraphicElement::style_t style); GraphicElement::style_t style);

View File

@ -733,7 +733,7 @@ static void pack_special(Context *ctx)
if (pi.name == ctx->id("PACKAGEPIN")) { if (pi.name == ctx->id("PACKAGEPIN")) {
if (!is_pad) { if (!is_pad) {
log_error(" PLL '%s' has a PACKAGEPIN but is not a PAD PLL", ci->name.c_str(ctx)); log_error("PLL '%s' has a PACKAGEPIN but is not a PAD PLL", ci->name.c_str(ctx));
} else { } else {
// We drop this port and instead place the PLL adequately below. // We drop this port and instead place the PLL adequately below.
pad_packagepin_net = port.second.net; pad_packagepin_net = port.second.net;
@ -743,9 +743,22 @@ static void pack_special(Context *ctx)
} }
if (pi.name == ctx->id("REFERENCECLK")) { if (pi.name == ctx->id("REFERENCECLK")) {
if (!is_core) if (!is_core)
log_error(" PLL '%s' has a REFERENCECLK but is not a CORE PLL", ci->name.c_str(ctx)); log_error("PLL '%s' has a REFERENCECLK but is not a CORE PLL", ci->name.c_str(ctx));
} }
if (packed->ports.count(ctx->id(newname)) == 0) {
if (ci->ports[pi.name].net == nullptr) {
log_warning("PLL '%s' has unknown unconnected port '%s' - ignoring\n", ci->name.c_str(ctx), pi.name.c_str(ctx));
continue;
} else {
if (ctx->force) {
log_error("PLL '%s' has unknown connected port '%s'\n", ci->name.c_str(ctx), pi.name.c_str(ctx));
} else {
log_warning("PLL '%s' has unknown connected port '%s' - ignoring\n", ci->name.c_str(ctx), pi.name.c_str(ctx));
continue;
}
}
}
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname));
} }
@ -766,7 +779,7 @@ static void pack_special(Context *ctx)
auto pll_packagepin_driver = pad_packagepin_net->driver; auto pll_packagepin_driver = pad_packagepin_net->driver;
NPNR_ASSERT(pll_packagepin_driver.cell != nullptr); NPNR_ASSERT(pll_packagepin_driver.cell != nullptr);
if (pll_packagepin_driver.cell->type != ctx->id("SB_IO")) { if (pll_packagepin_driver.cell->type != ctx->id("SB_IO")) {
log_error(" PLL '%s' has a PACKAGEPIN driven by " log_error("PLL '%s' has a PACKAGEPIN driven by "
"an %s, should be directly connected to an input SB_IO\n", "an %s, should be directly connected to an input SB_IO\n",
ci->name.c_str(ctx), pll_packagepin_driver.cell->type.c_str(ctx)); ci->name.c_str(ctx), pll_packagepin_driver.cell->type.c_str(ctx));
} }
@ -774,17 +787,17 @@ static void pack_special(Context *ctx)
auto packagepin_cell = pll_packagepin_driver.cell; auto packagepin_cell = pll_packagepin_driver.cell;
auto packagepin_bel_name = packagepin_cell->attrs.find(ctx->id("BEL")); auto packagepin_bel_name = packagepin_cell->attrs.find(ctx->id("BEL"));
if (packagepin_bel_name == packagepin_cell->attrs.end()) { if (packagepin_bel_name == packagepin_cell->attrs.end()) {
log_error(" PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx), log_error("PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx),
packagepin_cell->name.c_str(ctx)); packagepin_cell->name.c_str(ctx));
} }
auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second)); auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second));
if (pll_sb_io_belpin.bel != packagepin_bel) { if (pll_sb_io_belpin.bel != packagepin_bel) {
log_error(" PLL '%s' PACKAGEPIN is connected to pin %s, can only be pin %s\n", log_error("PLL '%s' PACKAGEPIN is connected to pin %s, can only be pin %s\n",
ci->name.c_str(ctx), ctx->getBelPackagePin(packagepin_bel).c_str(), ci->name.c_str(ctx), ctx->getBelPackagePin(packagepin_bel).c_str(),
ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str()); ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str());
} }
if (pad_packagepin_net->users.size() != 1) { if (pad_packagepin_net->users.size() != 1) {
log_error(" PLL '%s' clock input '%s' can only drive PLL\n", ci->name.c_str(ctx), log_error("PLL '%s' clock input '%s' can only drive PLL\n", ci->name.c_str(ctx),
pad_packagepin_net->name.c_str(ctx)); pad_packagepin_net->name.c_str(ctx));
} }
// Set an attribute about this PLL's PAD SB_IO. // Set an attribute about this PLL's PAD SB_IO.
@ -793,13 +806,13 @@ static void pack_special(Context *ctx)
packagepin_cell->ports.erase(pll_packagepin_driver.port); packagepin_cell->ports.erase(pll_packagepin_driver.port);
} }
log_info(" constrained '%s' to %s\n", packed->name.c_str(ctx), ctx->getBelName(bel).c_str(ctx)); log_info(" constrained PLL '%s' to %s\n", packed->name.c_str(ctx), ctx->getBelName(bel).c_str(ctx));
packed->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); packed->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
pll_bel = bel; pll_bel = bel;
constrained = true; constrained = true;
} }
if (!constrained) { if (!constrained) {
log_error(" could not constrain '%s' to any PLL Bel\n", packed->name.c_str(ctx)); log_error("Could not constrain PLL '%s' to any PLL Bel (too many PLLs?)\n", packed->name.c_str(ctx));
} }
} }
@ -818,6 +831,8 @@ static void pack_special(Context *ctx)
// If we have a net connected to LOCK, make sure it only drives LUTs. // If we have a net connected to LOCK, make sure it only drives LUTs.
auto port = packed->ports[ctx->id("LOCK")]; auto port = packed->ports[ctx->id("LOCK")];
if (port.net != nullptr) { if (port.net != nullptr) {
log_info(" PLL '%s' has LOCK output, need to pass all outputs via LUT\n",
ci->name.c_str(ctx));
bool found_lut = false; bool found_lut = false;
bool all_luts = true; bool all_luts = true;
unsigned int lut_count = 0; unsigned int lut_count = 0;

View File

@ -66,7 +66,7 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in)
log_error("unsupported pcf command '%s'\n", cmd.c_str()); log_error("unsupported pcf command '%s'\n", cmd.c_str());
} }
} }
ctx->settings.emplace(ctx->id("project/input/pcf"), filename); ctx->settings.emplace(ctx->id("input/pcf"), filename);
return true; return true;
} catch (log_execution_error_exception) { } catch (log_execution_error_exception) {
return false; return false;

View File

@ -28,8 +28,8 @@ NEXTPNR_NAMESPACE_BEGIN
void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path) void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path)
{ {
root.put("project.arch.package", ctx->archArgs().package); root.put("project.arch.package", ctx->archArgs().package);
if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end()) { if (ctx->settings.find(ctx->id("input/pcf")) != ctx->settings.end()) {
std::string fn = ctx->settings[ctx->id("project/input/pcf")]; std::string fn = ctx->settings[ctx->id("input/pcf")];
root.put("project.input.pcf", make_relative(fn, path).string()); root.put("project.input.pcf", make_relative(fn, path).string());
} }
} }

View File

@ -52,7 +52,7 @@ struct JsonNode
std::map<string, JsonNode *> data_dict; std::map<string, JsonNode *> data_dict;
std::vector<string> data_dict_keys; std::vector<string> data_dict_keys;
JsonNode(std::istream &f) JsonNode(std::istream &f, int &lineno)
{ {
type = 0; type = 0;
data_number = 0; data_number = 0;
@ -63,6 +63,8 @@ struct JsonNode
if (ch == EOF) if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n"); log_error("Unexpected EOF in JSON file.\n");
if (ch == '\n')
lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
continue; continue;
@ -91,8 +93,11 @@ struct JsonNode
break; break;
} }
if ('0' <= ch && ch <= '9') { if (('0' <= ch && ch <= '9') || ('-' == ch)) {
type = 'N'; type = 'N';
if (ch == '-')
data_number = 0;
else
data_number = ch - '0'; data_number = ch - '0';
data_string += ch; data_string += ch;
@ -114,6 +119,8 @@ struct JsonNode
data_string += ch; data_string += ch;
} }
if (data_string[0] == '-')
data_number = -data_number;
data_string = ""; data_string = "";
break; break;
@ -148,6 +155,8 @@ struct JsonNode
if (ch == EOF) if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n"); log_error("Unexpected EOF in JSON file.\n");
if (ch == '\n')
lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',') if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
continue; continue;
@ -155,7 +164,7 @@ struct JsonNode
break; break;
f.unget(); f.unget();
data_array.push_back(new JsonNode(f)); data_array.push_back(new JsonNode(f, lineno));
} }
break; break;
@ -170,6 +179,8 @@ struct JsonNode
if (ch == EOF) if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n"); log_error("Unexpected EOF in JSON file.\n");
if (ch == '\n')
lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',') if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
continue; continue;
@ -177,7 +188,7 @@ struct JsonNode
break; break;
f.unget(); f.unget();
JsonNode key(f); JsonNode key(f, lineno);
while (1) { while (1) {
ch = f.get(); ch = f.get();
@ -185,6 +196,8 @@ struct JsonNode
if (ch == EOF) if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n"); log_error("Unexpected EOF in JSON file.\n");
if (ch == '\n')
lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':') if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
continue; continue;
@ -192,10 +205,10 @@ struct JsonNode
break; break;
} }
JsonNode *value = new JsonNode(f); JsonNode *value = new JsonNode(f, lineno);
if (key.type != 'S') if (key.type != 'S')
log_error("Unexpected non-string key in JSON dict.\n"); log_error("Unexpected non-string key in JSON dict, line %d.\n", lineno);
data_dict[key.data_string] = value; data_dict[key.data_string] = value;
data_dict_keys.push_back(key.data_string); data_dict_keys.push_back(key.data_string);
@ -204,7 +217,7 @@ struct JsonNode
break; break;
} }
log_error("Unexpected character in JSON file: '%c'\n", ch); log_error("Unexpected character in JSON file, line %d: '%c'\n", lineno, ch);
} }
} }
@ -736,8 +749,9 @@ bool parse_json_file(std::istream &f, std::string &filename, Context *ctx)
{ {
try { try {
using namespace JsonParser; using namespace JsonParser;
int lineno = 1;
JsonNode root(f); JsonNode root(f, lineno);
if (root.type != 'D') if (root.type != 'D')
log_error("JSON root node is not a dictionary.\n"); log_error("JSON root node is not a dictionary.\n");
@ -754,7 +768,7 @@ bool parse_json_file(std::istream &f, std::string &filename, Context *ctx)
log_info("Checksum: 0x%08x\n", ctx->checksum()); log_info("Checksum: 0x%08x\n", ctx->checksum());
log_break(); log_break();
ctx->settings.emplace(ctx->id("project/input/json"), filename); ctx->settings.emplace(ctx->id("input/json"), filename);
return true; return true;
} catch (log_execution_error_exception) { } catch (log_execution_error_exception) {
return false; return false;

View File

@ -59,7 +59,7 @@ TEST_F(HX1KTest, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 27690); ASSERT_EQ(wire_count, 32802);
} }
TEST_F(HX1KTest, pip_names) TEST_F(HX1KTest, pip_names)
@ -70,7 +70,7 @@ TEST_F(HX1KTest, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 319904); ASSERT_EQ(pip_count, 345504);
} }
TEST_F(HX1KTest, uphill_to_downhill) TEST_F(HX1KTest, uphill_to_downhill)

View File

@ -59,7 +59,7 @@ TEST_F(HX8KTest, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 135182); ASSERT_EQ(wire_count, 165894);
} }
TEST_F(HX8KTest, pip_names) TEST_F(HX8KTest, pip_names)
@ -70,7 +70,7 @@ TEST_F(HX8KTest, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 1652480); ASSERT_EQ(pip_count, 1806080);
} }
TEST_F(HX8KTest, uphill_to_downhill) TEST_F(HX8KTest, uphill_to_downhill)

View File

@ -59,7 +59,7 @@ TEST_F(LP1KTest, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 27690); ASSERT_EQ(wire_count, 32802);
} }
TEST_F(LP1KTest, pip_names) TEST_F(LP1KTest, pip_names)
@ -70,7 +70,7 @@ TEST_F(LP1KTest, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 319904); ASSERT_EQ(pip_count, 345504);
} }
TEST_F(LP1KTest, uphill_to_downhill) TEST_F(LP1KTest, uphill_to_downhill)

View File

@ -59,7 +59,7 @@ TEST_F(LP384Test, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 8302); ASSERT_EQ(wire_count, 9830);
} }
TEST_F(LP384Test, pip_names) TEST_F(LP384Test, pip_names)
@ -70,7 +70,7 @@ TEST_F(LP384Test, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 86864); ASSERT_EQ(pip_count, 94544);
} }
TEST_F(LP384Test, uphill_to_downhill) TEST_F(LP384Test, uphill_to_downhill)

View File

@ -59,7 +59,7 @@ TEST_F(LP8KTest, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 135182); ASSERT_EQ(wire_count, 165894);
} }
TEST_F(LP8KTest, pip_names) TEST_F(LP8KTest, pip_names)
@ -70,7 +70,7 @@ TEST_F(LP8KTest, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 1652480); ASSERT_EQ(pip_count, 1806080);
} }
TEST_F(LP8KTest, uphill_to_downhill) TEST_F(LP8KTest, uphill_to_downhill)

View File

@ -59,7 +59,7 @@ TEST_F(UP5KTest, wire_names)
assert(wire == ctx->getWireByName(name)); assert(wire == ctx->getWireByName(name));
wire_count++; wire_count++;
} }
ASSERT_EQ(wire_count, 103391); ASSERT_EQ(wire_count, 124503);
} }
TEST_F(UP5KTest, pip_names) TEST_F(UP5KTest, pip_names)
@ -70,7 +70,7 @@ TEST_F(UP5KTest, pip_names)
assert(pip == ctx->getPipByName(name)); assert(pip == ctx->getPipByName(name));
pip_count++; pip_count++;
} }
ASSERT_EQ(pip_count, 1219104); ASSERT_EQ(pip_count, 1324704);
} }
TEST_F(UP5KTest, uphill_to_downhill) TEST_F(UP5KTest, uphill_to_downhill)