Merge github.com:YosysHQ/nextpnr into xc7
This commit is contained in:
commit
001806f317
2
.gitignore
vendored
2
.gitignore
vendored
@ -28,3 +28,5 @@ CTestTestfile.cmake
|
||||
install_manifest.txt
|
||||
/bbasm
|
||||
/ImportExecutables.cmake
|
||||
*-coverage/
|
||||
*-coverage.info
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
|
||||
void slotCollapsed(const QModelIndex &index);
|
||||
void slotExpanded(const QModelIndex &index);
|
||||
void onHoverPropertyChanged(QtBrowserItem *item);
|
||||
|
||||
QColor calculatedBackgroundColor(QtBrowserItem *item) const;
|
||||
|
||||
@ -129,12 +130,17 @@ public:
|
||||
{ return itemFromIndex(index); }
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hoverPropertyChanged(QtBrowserItem *item);
|
||||
private:
|
||||
QtTreePropertyBrowserPrivate *m_editorPrivate;
|
||||
QModelIndex current;
|
||||
};
|
||||
|
||||
QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
|
||||
@ -172,6 +178,21 @@ void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem
|
||||
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)
|
||||
{
|
||||
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(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(hoverPropertyChanged(QtBrowserItem *)), q_ptr, SLOT(onHoverPropertyChanged(QtBrowserItem *)));
|
||||
}
|
||||
|
||||
QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
|
||||
@ -688,6 +710,12 @@ void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
|
||||
emit q_ptr->expanded(idx);
|
||||
}
|
||||
|
||||
void QtTreePropertyBrowserPrivate::onHoverPropertyChanged(QtBrowserItem *item)
|
||||
{
|
||||
emit q_ptr->hoverPropertyChanged(item);
|
||||
}
|
||||
|
||||
|
||||
void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
|
||||
{
|
||||
if (!m_browserChangedBlocked && item != currentItem())
|
||||
|
@ -115,7 +115,7 @@ Q_SIGNALS:
|
||||
|
||||
void collapsed(QtBrowserItem *item);
|
||||
void expanded(QtBrowserItem *item);
|
||||
|
||||
void hoverPropertyChanged(QtBrowserItem *item);
|
||||
protected:
|
||||
virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem);
|
||||
virtual void itemRemoved(QtBrowserItem *item);
|
||||
@ -130,7 +130,8 @@ private:
|
||||
Q_PRIVATE_SLOT(d_func(), void slotCollapsed(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 slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *))
|
||||
Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *))
|
||||
Q_PRIVATE_SLOT(d_func(), void onHoverPropertyChanged(QtBrowserItem *))
|
||||
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,16 @@ project(nextpnr)
|
||||
option(BUILD_GUI "Build GUI" ON)
|
||||
option(BUILD_PYTHON "Build Python Integration" ON)
|
||||
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
|
||||
set(FAMILIES generic ice40 ecp5 xc7)
|
||||
@ -43,7 +53,11 @@ set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g")
|
||||
endif()
|
||||
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)
|
||||
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
|
||||
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)
|
||||
if (BUILD_GUI)
|
||||
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
|
||||
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_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES})
|
||||
target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} ${link_param})
|
||||
if (NOT MSVC)
|
||||
target_link_libraries(${target} LINK_PUBLIC pthread)
|
||||
endif()
|
||||
|
303
CodeCoverage.cmake
Normal file
303
CodeCoverage.cmake
Normal 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
|
12
README.md
12
README.md
@ -127,6 +127,13 @@ cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -
|
||||
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
|
||||
--------------------
|
||||
|
||||
@ -145,6 +152,9 @@ Testing
|
||||
- `-DSANITIZE_THREAD=ON`
|
||||
- `-DSANITIZE_UNDEFINED=ON`
|
||||
- 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
|
||||
--------------------
|
||||
@ -167,6 +177,6 @@ Links and references
|
||||
- [Arachne PNR](https://github.com/cseed/arachne-pnr)
|
||||
- [VPR/VTR](https://verilogtorouting.org/)
|
||||
- [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)
|
||||
|
||||
|
@ -144,7 +144,7 @@ void CommandHandler::setupContext(Context *ctx)
|
||||
}
|
||||
|
||||
if (vm.count("cstrweight")) {
|
||||
// ctx->placer_constraintWeight = vm["cstrweight"].as<float>();
|
||||
settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
|
||||
}
|
||||
|
||||
if (vm.count("freq")) {
|
||||
@ -261,6 +261,7 @@ int CommandHandler::exec()
|
||||
} else {
|
||||
ctx = createContext();
|
||||
}
|
||||
settings = std::unique_ptr<Settings>(new Settings(ctx.get()));
|
||||
setupContext(ctx.get());
|
||||
setupArchContext(ctx.get());
|
||||
return executeMain(std::move(ctx));
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <boost/program_options.hpp>
|
||||
#include "nextpnr.h"
|
||||
#include "project.h"
|
||||
#include "settings.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
@ -56,6 +57,7 @@ class CommandHandler
|
||||
protected:
|
||||
po::variables_map vm;
|
||||
ArchArgs chipArgs;
|
||||
std::unique_ptr<Settings> settings;
|
||||
|
||||
private:
|
||||
po::options_description options;
|
||||
|
@ -46,6 +46,18 @@ void (*log_error_atexit)() = NULL;
|
||||
// static bool next_print_log = false;
|
||||
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 string;
|
||||
|
@ -51,6 +51,9 @@ extern bool log_quiet_warnings;
|
||||
extern std::string log_last_error;
|
||||
extern void (*log_error_atexit)();
|
||||
|
||||
std::string stringf(const char *fmt, ...);
|
||||
std::string vstringf(const char *fmt, va_list ap);
|
||||
|
||||
extern std::ostream clog;
|
||||
void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
|
||||
void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "placer1.h"
|
||||
#include <algorithm>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
@ -108,14 +109,12 @@ class SAPlacer
|
||||
if (bel_type != cell->type) {
|
||||
log_error("Bel \'%s\' of type \'%s\' does not match cell "
|
||||
"\'%s\' of type \'%s\'\n",
|
||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx),
|
||||
cell->type.c_str(ctx));
|
||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
}
|
||||
if (!ctx->isValidBelForCell(cell, bel)) {
|
||||
log_error("Bel \'%s\' of type \'%s\' is not valid for cell "
|
||||
"\'%s\' of type \'%s\'\n",
|
||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx),
|
||||
cell->type.c_str(ctx));
|
||||
loc_name.c_str(), bel_type.c_str(ctx), cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
}
|
||||
|
||||
ctx->bindBel(bel, cell, STRENGTH_USER);
|
||||
@ -492,6 +491,8 @@ class SAPlacer
|
||||
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)
|
||||
{
|
||||
try {
|
||||
|
@ -20,12 +20,14 @@
|
||||
#define PLACE_H
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "settings.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
struct Placer1Cfg
|
||||
struct Placer1Cfg : public Settings
|
||||
{
|
||||
float constraintWeight = 10;
|
||||
Placer1Cfg(Context *ctx);
|
||||
float constraintWeight;
|
||||
};
|
||||
|
||||
extern bool placer1(Context *ctx, Placer1Cfg cfg);
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "project.h"
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#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.arch.name", ctx->archId().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.params.freq", int(ctx->target_freq / 1e6));
|
||||
root.put("project.params.seed", ctx->rngstate);
|
||||
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);
|
||||
} catch (...) {
|
||||
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> ctx;
|
||||
@ -110,6 +130,10 @@ std::unique_ptr<Context> ProjectHandler::load(std::string filename)
|
||||
if (params.count("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());
|
||||
} catch (...) {
|
||||
log_error("Error loading project file.\n");
|
||||
|
@ -682,6 +682,14 @@ void cleanupReroute(Context *ctx, const Router1Cfg &cfg, RipupScoreboard &scores
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
RipupScoreboard scores;
|
||||
Router1Cfg cfg;
|
||||
Router1Cfg cfg(this);
|
||||
cfg.useEstimate = useEstimate;
|
||||
|
||||
Router router(this, cfg, scores, src_wire, dst_wire);
|
||||
|
@ -21,15 +21,18 @@
|
||||
#define ROUTER1_H
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "settings.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
struct Router1Cfg
|
||||
struct Router1Cfg : Settings
|
||||
{
|
||||
int maxIterCnt = 200;
|
||||
bool cleanupReroute = true;
|
||||
bool fullCleanupReroute = true;
|
||||
bool useEstimate = true;
|
||||
Router1Cfg(Context *ctx);
|
||||
|
||||
int maxIterCnt;
|
||||
bool cleanupReroute;
|
||||
bool fullCleanupReroute;
|
||||
bool useEstimate;
|
||||
};
|
||||
|
||||
extern bool router1(Context *ctx, const Router1Cfg &cfg);
|
||||
|
63
common/settings.h
Normal file
63
common/settings.h
Normal 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
|
@ -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));
|
||||
|
||||
if (print_histogram && slack_histogram.size() > 0) {
|
||||
constexpr unsigned num_bins = 20;
|
||||
unsigned num_bins = 20;
|
||||
unsigned bar_width = 60;
|
||||
auto min_slack = slack_histogram.begin()->first;
|
||||
auto max_slack = slack_histogram.rbegin()->first;
|
||||
auto bin_size = (max_slack - min_slack) / num_bins;
|
||||
std::vector<unsigned> bins(num_bins + 1);
|
||||
auto bin_size = std::max(1u, (max_slack - min_slack) / num_bins);
|
||||
num_bins = std::min((max_slack - min_slack) / bin_size, num_bins) + 1;
|
||||
std::vector<unsigned> bins(num_bins);
|
||||
unsigned max_freq = 0;
|
||||
for (const auto &i : slack_histogram) {
|
||||
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(" legend: * represents %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),
|
||||
std::string(bins[i] * bar_width / max_freq, '*').c_str(),
|
||||
(bins[i] * bar_width) % max_freq > 0 ? '+' : ' ');
|
||||
|
@ -151,6 +151,11 @@ Return a list of all bels on the device.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
|
132
ecp5/arch.cc
132
ecp5/arch.cc
@ -46,7 +46,9 @@ static std::tuple<int, int, std::string> split_identifier_name(const std::string
|
||||
void IdString::initialize_arch(const BaseCtx *ctx)
|
||||
{
|
||||
#define X(t) initialize_add(ctx, #t, ID_##t);
|
||||
|
||||
#include "constids.inc"
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
@ -92,6 +94,8 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
|
||||
if (!package_info)
|
||||
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
|
||||
{
|
||||
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
|
||||
@ -376,20 +380,16 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
auto driver_loc = getBelLocation(driver.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::place() { return placer1(getCtx(), Placer1Cfg()); }
|
||||
bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
|
||||
|
||||
bool Arch::route()
|
||||
{
|
||||
Router1Cfg cfg;
|
||||
return router1(getCtx(), cfg);
|
||||
}
|
||||
bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@ -436,7 +436,7 @@ DecalXY Arch::getBelDecal(BelId bel) const
|
||||
decalxy.decal.type = DecalId::TYPE_BEL;
|
||||
decalxy.decal.location = bel.location;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -450,12 +450,122 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
|
||||
|
||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
||||
{
|
||||
return false;
|
||||
// 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;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const
|
||||
{
|
||||
return TMG_IGNORE;
|
||||
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;
|
||||
} 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)
|
||||
|
56
ecp5/arch.h
56
ecp5/arch.h
@ -404,7 +404,7 @@ struct Arch : BaseCtx
|
||||
mutable std::unordered_map<IdString, WireId> wire_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<PipId, NetInfo *> pip_to_net;
|
||||
|
||||
@ -443,11 +443,18 @@ struct Arch : BaseCtx
|
||||
|
||||
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)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(bel_to_cell[bel] == nullptr);
|
||||
bel_to_cell[bel] = cell;
|
||||
int idx = getBelFlatIndex(bel);
|
||||
NPNR_ASSERT(bel_to_cell.at(idx) == nullptr);
|
||||
bel_to_cell[idx] = cell;
|
||||
cell->bel = bel;
|
||||
cell->belStrength = strength;
|
||||
refreshUiBel(bel);
|
||||
@ -456,10 +463,11 @@ struct Arch : BaseCtx
|
||||
void unbindBel(BelId bel)
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
NPNR_ASSERT(bel_to_cell[bel] != nullptr);
|
||||
bel_to_cell[bel]->bel = BelId();
|
||||
bel_to_cell[bel]->belStrength = STRENGTH_NONE;
|
||||
bel_to_cell[bel] = nullptr;
|
||||
int idx = getBelFlatIndex(bel);
|
||||
NPNR_ASSERT(bel_to_cell.at(idx) != nullptr);
|
||||
bel_to_cell[idx]->bel = BelId();
|
||||
bel_to_cell[idx]->belStrength = STRENGTH_NONE;
|
||||
bel_to_cell[idx] = nullptr;
|
||||
refreshUiBel(bel);
|
||||
}
|
||||
|
||||
@ -480,25 +488,19 @@ struct Arch : BaseCtx
|
||||
bool checkBelAvail(BelId bel) const
|
||||
{
|
||||
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
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||
return nullptr;
|
||||
else
|
||||
return bel_to_cell.at(bel);
|
||||
return bel_to_cell[getBelFlatIndex(bel)];
|
||||
}
|
||||
|
||||
CellInfo *getConflictingBelCell(BelId bel) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||
return nullptr;
|
||||
else
|
||||
return bel_to_cell.at(bel);
|
||||
return bel_to_cell[getBelFlatIndex(bel)];
|
||||
}
|
||||
|
||||
BelRange getBels() const
|
||||
@ -522,6 +524,12 @@ struct Arch : BaseCtx
|
||||
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;
|
||||
|
||||
BelPinRange getWireBelPins(WireId wire) const
|
||||
@ -553,6 +561,12 @@ struct Arch : BaseCtx
|
||||
|
||||
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; }
|
||||
|
||||
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
|
||||
@ -633,6 +647,12 @@ struct Arch : BaseCtx
|
||||
|
||||
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; }
|
||||
|
||||
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||
@ -725,7 +745,7 @@ struct Arch : BaseCtx
|
||||
{
|
||||
DelayInfo delay;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -848,6 +868,8 @@ struct Arch : BaseCtx
|
||||
// Helper function for above
|
||||
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::string getTileByTypeAndLocation(int row, int col, std::string type) const
|
||||
{
|
||||
|
@ -35,26 +35,26 @@ bool Arch::slicesCompatible(const std::vector<const CellInfo *> &cells) const
|
||||
{
|
||||
// TODO: allow different LSR/CLK and MUX/SRMODE settings once
|
||||
// routing details are worked out
|
||||
NetInfo *clk_sig = nullptr, *lsr_sig = nullptr;
|
||||
std::string CLKMUX, LSRMUX, SRMODE;
|
||||
IdString clk_sig, lsr_sig;
|
||||
IdString CLKMUX, LSRMUX, SRMODE;
|
||||
bool first = true;
|
||||
for (auto cell : cells) {
|
||||
if (first) {
|
||||
clk_sig = port_or_nullptr(cell, id_CLK);
|
||||
lsr_sig = port_or_nullptr(cell, id_LSR);
|
||||
CLKMUX = str_or_default(cell->params, id_CLKMUX, "CLK");
|
||||
LSRMUX = str_or_default(cell->params, id_LSRMUX, "LSR");
|
||||
SRMODE = str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR");
|
||||
clk_sig = cell->sliceInfo.clk_sig;
|
||||
lsr_sig = cell->sliceInfo.lsr_sig;
|
||||
CLKMUX = cell->sliceInfo.clkmux;
|
||||
LSRMUX = cell->sliceInfo.lsrmux;
|
||||
SRMODE = cell->sliceInfo.srmode;
|
||||
} else {
|
||||
if (port_or_nullptr(cell, id_CLK) != clk_sig)
|
||||
if (cell->sliceInfo.clk_sig != clk_sig)
|
||||
return false;
|
||||
if (port_or_nullptr(cell, id_LSR) != lsr_sig)
|
||||
if (cell->sliceInfo.lsr_sig != lsr_sig)
|
||||
return false;
|
||||
if (str_or_default(cell->params, id_CLKMUX, "CLK") != CLKMUX)
|
||||
if (cell->sliceInfo.clkmux != CLKMUX)
|
||||
return false;
|
||||
if (str_or_default(cell->params, id_LSRMUX, "LSR") != LSRMUX)
|
||||
if (cell->sliceInfo.lsrmux != LSRMUX)
|
||||
return false;
|
||||
if (str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR") != SRMODE)
|
||||
if (cell->sliceInfo.srmode != SRMODE)
|
||||
return false;
|
||||
}
|
||||
first = false;
|
||||
|
@ -139,6 +139,10 @@ struct ArchNetInfo
|
||||
};
|
||||
struct ArchCellInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
IdString clk_sig, lsr_sig, clkmux, lsrmux, srmode;
|
||||
} sliceInfo;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
24
ecp5/pack.cc
24
ecp5/pack.cc
@ -536,10 +536,34 @@ bool Arch::pack()
|
||||
log_break();
|
||||
Ecp5Packer(ctx).pack();
|
||||
log_info("Checksum: 0x%08x\n", ctx->checksum());
|
||||
assignArchInfo();
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
assignArchInfo();
|
||||
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
|
||||
|
@ -130,11 +130,54 @@ def process_loc_globals(chip):
|
||||
tapdrv = chip.global_data.get_tap_driver(y, x)
|
||||
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_loc(loc, sym_name):
|
||||
bba.u16(loc.x, "%s.x" % 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.pre('#include "nextpnr.h"')
|
||||
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.r("chip_info", "chip_info")
|
||||
|
||||
loctypes = list([_.key() for _ in ddrg.locationTypes])
|
||||
|
||||
for idx in range(len(loctypes)):
|
||||
loctype = ddrg.locationTypes[loctypes[idx]]
|
||||
@ -153,7 +195,7 @@ def write_database(dev_name, chip, ddrg, endianness):
|
||||
write_loc(arc.sinkWire.rel, "dst")
|
||||
bba.u32(arc.srcWire.id, "src_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.u8(int(arc.cls), "pip_type")
|
||||
bba.u8(0, "padding")
|
||||
|
@ -184,6 +184,21 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
|
||||
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) {}
|
||||
@ -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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; }
|
||||
|
||||
uint32_t Arch::getWireChecksum(WireId wire) const
|
||||
{
|
||||
// FIXME
|
||||
@ -328,6 +347,8 @@ IdString Arch::getPipName(PipId pip) const { return pip; }
|
||||
|
||||
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
|
||||
{
|
||||
// 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())); }
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
|
@ -32,6 +32,7 @@ struct WireInfo;
|
||||
struct PipInfo
|
||||
{
|
||||
IdString name, type;
|
||||
std::map<IdString, std::string> attrs;
|
||||
NetInfo *bound_net;
|
||||
WireId srcWire, dstWire;
|
||||
DelayInfo delay;
|
||||
@ -42,6 +43,7 @@ struct PipInfo
|
||||
struct WireInfo
|
||||
{
|
||||
IdString name, type;
|
||||
std::map<IdString, std::string> attrs;
|
||||
NetInfo *bound_net;
|
||||
std::vector<PipId> downhill, uphill, aliases;
|
||||
BelPin uphill_bel_pin;
|
||||
@ -61,6 +63,7 @@ struct PinInfo
|
||||
struct BelInfo
|
||||
{
|
||||
IdString name, type;
|
||||
std::map<IdString, std::string> attrs;
|
||||
CellInfo *bound_cell;
|
||||
std::unordered_map<IdString, PinInfo> pins;
|
||||
DecalXY decalxy;
|
||||
@ -120,6 +123,10 @@ struct Arch : BaseCtx
|
||||
void setBelDecal(BelId bel, 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.
|
||||
|
||||
@ -151,6 +158,7 @@ struct Arch : BaseCtx
|
||||
CellInfo *getConflictingBelCell(BelId bel) const;
|
||||
const std::vector<BelId> &getBels() const;
|
||||
IdString getBelType(BelId bel) const;
|
||||
const std::map<IdString, std::string> &getBelAttrs(BelId bel) const;
|
||||
WireId getBelPinWire(BelId bel, IdString pin) const;
|
||||
PortType getBelPinType(BelId bel, IdString pin) const;
|
||||
std::vector<IdString> getBelPins(BelId bel) const;
|
||||
@ -158,6 +166,7 @@ struct Arch : BaseCtx
|
||||
WireId getWireByName(IdString name) const;
|
||||
IdString getWireName(WireId wire) const;
|
||||
IdString getWireType(WireId wire) const;
|
||||
const std::map<IdString, std::string> &getWireAttrs(WireId wire) const;
|
||||
uint32_t getWireChecksum(WireId wire) const;
|
||||
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength);
|
||||
void unbindWire(WireId wire);
|
||||
@ -171,6 +180,7 @@ struct Arch : BaseCtx
|
||||
PipId getPipByName(IdString name) const;
|
||||
IdString getPipName(PipId pip) const;
|
||||
IdString getPipType(PipId pip) const;
|
||||
const std::map<IdString, std::string> &getPipAttrs(PipId pip) const;
|
||||
uint32_t getPipChecksum(PipId pip) const;
|
||||
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength);
|
||||
void unbindPip(PipId pip);
|
||||
|
@ -109,6 +109,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, ArchArgs args,
|
||||
connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem);
|
||||
connect(designview, &DesignWidget::zoomSelected, fpgaView, &FPGAViewWidget::zoomSelected);
|
||||
connect(designview, &DesignWidget::highlight, fpgaView, &FPGAViewWidget::onHighlightGroupChanged);
|
||||
connect(designview, &DesignWidget::hover, fpgaView, &FPGAViewWidget::onHoverItemChanged);
|
||||
|
||||
// Click event on device view
|
||||
connect(fpgaView, &FPGAViewWidget::clickedBel, designview, &DesignWidget::onClickedBel);
|
||||
@ -420,7 +421,7 @@ void BaseMainWindow::disableActions()
|
||||
actionNew->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);
|
||||
else
|
||||
actionSave->setEnabled(false);
|
||||
|
@ -30,15 +30,34 @@
|
||||
|
||||
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)
|
||||
{
|
||||
// Add tree view
|
||||
treeView = new QTreeView();
|
||||
treeView = new TreeView();
|
||||
treeModel = new TreeModel::Model();
|
||||
treeView->setModel(treeModel);
|
||||
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
|
||||
treeView->viewport()->setMouseTracking(true);
|
||||
// Add property view
|
||||
variantManager = new QtVariantPropertyManager(this);
|
||||
readOnlyManager = new QtVariantPropertyManager(this);
|
||||
@ -50,6 +69,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
|
||||
propertyEditor->show();
|
||||
propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
propertyEditor->treeWidget()->viewport()->setMouseTracking(true);
|
||||
|
||||
searchEdit = new QLineEdit();
|
||||
searchEdit->setClearButtonEnabled(true);
|
||||
@ -158,9 +178,11 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel
|
||||
connect(propertyEditor->treeWidget(), &QTreeWidget::customContextMenuRequested, this,
|
||||
&DesignWidget::prepareMenuProperty);
|
||||
connect(propertyEditor->treeWidget(), &QTreeWidget::itemDoubleClicked, this, &DesignWidget::onItemDoubleClicked);
|
||||
connect(propertyEditor, &QtTreePropertyBrowser::hoverPropertyChanged, this, &DesignWidget::onHoverPropertyChanged);
|
||||
|
||||
connect(treeView, &QTreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
|
||||
connect(treeView, &QTreeView::doubleClicked, this, &DesignWidget::onDoubleClicked);
|
||||
connect(treeView, &TreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree);
|
||||
connect(treeView, &TreeView::doubleClicked, this, &DesignWidget::onDoubleClicked);
|
||||
connect(treeView, &TreeView::hoverIndexChanged, this, &DesignWidget::onHoverIndexChanged);
|
||||
selectionModel = treeView->selectionModel();
|
||||
connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &DesignWidget::onSelectionChanged);
|
||||
|
||||
@ -388,7 +410,6 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
ElementType type = clickItem->type();
|
||||
if (type == ElementType::NONE)
|
||||
return;
|
||||
std::vector<DecalXY> decals;
|
||||
|
||||
addToHistory(index);
|
||||
|
||||
@ -411,6 +432,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
|
||||
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
|
||||
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");
|
||||
for (const auto &item : ctx->getBelPins(bel)) {
|
||||
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)),
|
||||
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);
|
||||
|
||||
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),
|
||||
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);
|
||||
|
||||
QtProperty *delayItem = addSubGroup(topItem, "Delay");
|
||||
@ -785,4 +821,35 @@ void DesignWidget::onSearchInserted()
|
||||
if (currentSearchIndexes.size() > 0 && currentIndex < currentSearchIndexes.size())
|
||||
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
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QVariant>
|
||||
#include <QMouseEvent>
|
||||
#include "nextpnr.h"
|
||||
#include "qtgroupboxpropertybrowser.h"
|
||||
#include "qtpropertymanager.h"
|
||||
@ -31,6 +32,22 @@
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -55,6 +72,7 @@ class DesignWidget : public QWidget
|
||||
Q_SIGNALS:
|
||||
void selected(std::vector<DecalXY> decal, bool keep);
|
||||
void highlight(std::vector<DecalXY> decal, int group);
|
||||
void hover(DecalXY decal);
|
||||
void zoomSelected();
|
||||
|
||||
private Q_SLOTS:
|
||||
@ -64,6 +82,8 @@ class DesignWidget : public QWidget
|
||||
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void onDoubleClicked(const QModelIndex &index);
|
||||
void onSearchInserted();
|
||||
void onHoverIndexChanged(QModelIndex index);
|
||||
void onHoverPropertyChanged(QtBrowserItem *item);
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void updateTree();
|
||||
@ -74,7 +94,7 @@ class DesignWidget : public QWidget
|
||||
private:
|
||||
Context *ctx;
|
||||
|
||||
QTreeView *treeView;
|
||||
TreeView *treeView;
|
||||
QItemSelectionModel *selectionModel;
|
||||
TreeModel::Model *treeModel;
|
||||
QLineEdit *searchEdit;
|
||||
|
@ -240,9 +240,10 @@ void FPGAViewWidget::populateQuadTree(RendererData *data, const DecalXY &decal,
|
||||
continue;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
if (el.type == GraphicElement::TYPE_BOX) {
|
||||
// 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) {
|
||||
@ -261,7 +262,11 @@ void FPGAViewWidget::populateQuadTree(RendererData *data, const DecalXY &decal,
|
||||
x1 += 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.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.
|
||||
data->qt = std::unique_ptr<PickQuadTree>(new PickQuadTree(data->bbGlobal));
|
||||
data->qt = std::unique_ptr<PickQuadTree>(new PickQuadTree(bb));
|
||||
for (auto const &decal : belDecals) {
|
||||
populateQuadTree(data.get(), decal.first,
|
||||
PickedElement::fromBel(decal.second, decal.first.x, decal.first.y));
|
||||
@ -545,6 +559,14 @@ void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int gr
|
||||
pokeRenderer();
|
||||
}
|
||||
|
||||
void FPGAViewWidget::onHoverItemChanged(DecalXY decal)
|
||||
{
|
||||
QMutexLocker locked(&rendererArgsLock_);
|
||||
rendererArgs_->hoveredDecal = decal;
|
||||
rendererArgs_->changed = true;
|
||||
pokeRenderer();
|
||||
}
|
||||
|
||||
void FPGAViewWidget::resizeGL(int width, int height) {}
|
||||
|
||||
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)
|
||||
{
|
||||
if (bb.w() < 0.00005 && bb.h() < 0.00005)
|
||||
if (fabs(bb.w()) < 0.00005 && fabs(bb.h()) < 0.00005)
|
||||
return;
|
||||
|
||||
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
|
||||
|
@ -107,11 +107,13 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void onSelectedArchItem(std::vector<DecalXY> decals, bool keep);
|
||||
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
|
||||
void onHoverItemChanged(DecalXY decal);
|
||||
void pokeRenderer(void);
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
|
@ -191,7 +191,7 @@ void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
108
ice40/arch.cc
108
ice40/arch.cc
@ -226,6 +226,15 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const
|
||||
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 ret;
|
||||
@ -331,6 +340,28 @@ IdString Arch::getWireType(WireId wire) const
|
||||
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
|
||||
@ -372,6 +403,18 @@ IdString Arch::getPipName(PipId pip) const
|
||||
#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
|
||||
@ -565,18 +608,9 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
bool Arch::place()
|
||||
{
|
||||
Placer1Cfg cfg;
|
||||
cfg.constraintWeight = placer_constraintWeight;
|
||||
return placer1(getCtx(), cfg);
|
||||
}
|
||||
bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
|
||||
|
||||
bool Arch::route()
|
||||
{
|
||||
Router1Cfg cfg;
|
||||
return router1(getCtx(), cfg);
|
||||
}
|
||||
bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@ -695,13 +729,29 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
||||
GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
|
||||
|
||||
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) {
|
||||
const PipInfoPOD &p = chip_info->pip_data[decal.index];
|
||||
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);
|
||||
|
||||
#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) {
|
||||
@ -727,7 +777,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
||||
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 + 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.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 +
|
||||
(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;
|
||||
el.type = GraphicElement::TYPE_BOX;
|
||||
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.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;
|
||||
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;
|
||||
|
@ -225,6 +225,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
|
||||
RelPtr<BelConfigPOD> bel_config;
|
||||
RelPtr<PackageInfoPOD> packages_data;
|
||||
RelPtr<CellTimingPOD> cell_timing;
|
||||
RelPtr<RelPtr<char>> tile_wire_names;
|
||||
});
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@ -502,6 +503,8 @@ struct Arch : BaseCtx
|
||||
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;
|
||||
PortType getBelPinType(BelId bel, IdString pin) const;
|
||||
std::vector<IdString> getBelPins(BelId bel) const;
|
||||
@ -517,6 +520,7 @@ struct Arch : BaseCtx
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
@ -692,7 +696,8 @@ struct Arch : BaseCtx
|
||||
|
||||
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; }
|
||||
|
||||
@ -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}");
|
||||
}
|
||||
|
||||
float placer_constraintWeight = 10;
|
||||
};
|
||||
|
||||
void ice40DelayFuzzerMain(Context *ctx);
|
||||
|
@ -870,10 +870,12 @@ bool read_asc(Context *ctx, std::istream &in)
|
||||
}
|
||||
if (isUsed) {
|
||||
NetInfo *net = ctx->wire_to_net[pi.dst];
|
||||
WireId wire;
|
||||
wire.index = pi.dst;
|
||||
ctx->unbindWire(wire);
|
||||
ctx->bindPip(pip, net, STRENGTH_WEAK);
|
||||
if (net!=nullptr) {
|
||||
WireId wire;
|
||||
wire.index = pi.dst;
|
||||
ctx->unbindWire(wire);
|
||||
ctx->bindPip(pip, net, STRENGTH_WEAK);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto bel : ctx->getBels()) {
|
||||
|
@ -28,6 +28,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir)
|
||||
{
|
||||
IdString id = ctx->id(name);
|
||||
NPNR_ASSERT(cell->ports.count(id) == 0);
|
||||
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(), "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(), "PLLOUT_A", PORT_OUT);
|
||||
|
216
ice40/chipdb.py
216
ice40/chipdb.py
@ -50,6 +50,7 @@ tiletypes = dict()
|
||||
wiretypes = dict()
|
||||
|
||||
gfx_wire_ids = dict()
|
||||
gfx_wire_names = list()
|
||||
wire_segments = dict()
|
||||
|
||||
fast_timings = None
|
||||
@ -93,6 +94,136 @@ with open(args.gfxh) as f:
|
||||
idx = len(gfx_wire_ids)
|
||||
name = line.strip().rstrip(",")
|
||||
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):
|
||||
db = dict()
|
||||
@ -165,6 +296,18 @@ def maj_wire_name(name):
|
||||
return name[2] in ("sp12_v_b_0", "sp12_v_b_1")
|
||||
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):
|
||||
if maj_wire_name(newname):
|
||||
return True
|
||||
@ -508,11 +651,13 @@ with open(args.filename, "r") as f:
|
||||
wire_names_r[mode[1]] = wname
|
||||
if mode[1] not in wire_xy:
|
||||
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:
|
||||
wire_segments[mode[1]] = dict()
|
||||
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
|
||||
|
||||
if mode[0] in ("buffer", "routing"):
|
||||
@ -561,7 +706,9 @@ def add_wire(x, y, name):
|
||||
wire_names_r[wire_idx] = wname
|
||||
wire_segments[wire_idx] = dict()
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
# Add virtual padin wires
|
||||
for i in range(8):
|
||||
add_wire(0, 0, "padin_%d" % i)
|
||||
|
||||
def add_bel_input(bel, wire, port):
|
||||
if wire not in wire_belports:
|
||||
wire_belports[wire] = set()
|
||||
@ -932,6 +1075,10 @@ bba.post('NEXTPNR_NAMESPACE_END')
|
||||
bba.push("chipdb_blob_%s" % dev_name)
|
||||
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)):
|
||||
bba.l("bel_wires_%d" % bel, "BelWirePOD")
|
||||
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["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None
|
||||
|
||||
pos_xy = None
|
||||
first = None
|
||||
|
||||
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]:
|
||||
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:
|
||||
if pos_xy is None:
|
||||
info["x"] = wire_names_r[wire][0]
|
||||
info["y"] = wire_names_r[wire][1]
|
||||
else:
|
||||
info["x"] = pos_xy[0]
|
||||
info["y"] = pos_xy[1]
|
||||
|
||||
wireinfo.append(info)
|
||||
|
||||
@ -1108,8 +1267,13 @@ for wire, info in enumerate(wireinfo):
|
||||
bba.r(info["list_downhill"], "pips_downhill")
|
||||
bba.u32(info["num_bel_pins"], "num_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")
|
||||
else:
|
||||
bba.u32(0, "segments")
|
||||
@ -1125,24 +1289,25 @@ for wire, info in enumerate(wireinfo):
|
||||
for wire in range(num_wires):
|
||||
if len(wire_segments[wire]):
|
||||
bba.l("wire_segments_%d" % wire, "WireSegmentPOD")
|
||||
for xy, seg in sorted(wire_segments[wire].items()):
|
||||
bba.u8(xy[0], "x")
|
||||
bba.u8(xy[1], "y")
|
||||
bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
|
||||
for xy, segs in sorted(wire_segments[wire].items()):
|
||||
for seg in segs:
|
||||
bba.u8(xy[0], "x")
|
||||
bba.u8(xy[1], "y")
|
||||
bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
|
||||
|
||||
bba.l("pip_data_%s" % dev_name, "PipInfoPOD")
|
||||
for info in pipinfo:
|
||||
src_seg = -1
|
||||
src_segname = wire_names_r[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_segname = src_segname.replace("/", ".")
|
||||
|
||||
dst_seg = -1
|
||||
dst_segname = wire_names_r[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_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("package_info_%s" % dev_name, "packages_data")
|
||||
bba.r("cell_timings_%s" % dev_name, "cell_timing")
|
||||
bba.r("tile_wire_names", "tile_wire_names")
|
||||
|
||||
bba.pop()
|
||||
|
@ -36,7 +36,7 @@ if (MSVC)
|
||||
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)
|
||||
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}
|
||||
DEPENDS ${DEV_TXT_DB} ${DB_PY}
|
||||
DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
|
||||
)
|
||||
add_custom_command(OUTPUT ${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}
|
||||
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}
|
||||
DEPENDS ${DEV_TXT_DB} ${DB_PY}
|
||||
DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
|
||||
)
|
||||
add_custom_command(OUTPUT ${DEV_CC_DB}
|
||||
COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
|
||||
|
319
ice40/gfx.cc
319
ice40/gfx.cc
@ -21,7 +21,7 @@
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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;
|
||||
el.x1 = x + local_swbox_x2;
|
||||
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;
|
||||
g.push_back(el);
|
||||
}
|
||||
@ -403,7 +565,7 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
|
||||
int input = idx % 4;
|
||||
el.x1 = x + lut_swbox_x2;
|
||||
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;
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -662,22 +921,22 @@ void pipGfx(std::vector<GraphicElement> &g, int x, int y, float x1, float y1, fl
|
||||
el.style = style;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) {
|
||||
ty = y1 + 0.25 * fabsf(x1 - x2);
|
||||
if (fabsf(y1 - swy2) < 0.001 && fabsf(y2 - swy2) < 0.001) {
|
||||
ty = swy2 - 0.25 * fabsf(x1 - x2);
|
||||
goto edge_pip;
|
||||
}
|
||||
|
||||
@ -727,7 +986,7 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
|
||||
el.style = style;
|
||||
el.x1 = x + logic_cell_x1;
|
||||
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;
|
||||
g.push_back(el);
|
||||
return;
|
||||
@ -744,8 +1003,46 @@ void gfxTilePip(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId src,
|
||||
el.style = style;
|
||||
el.x1 = x + lut_swbox_x1;
|
||||
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.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * out_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;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
202
ice40/gfx.h
202
ice40/gfx.h
@ -205,6 +205,13 @@ enum GfxTileWireId
|
||||
TILE_WIRE_LUTFF_GLOBAL_CLK,
|
||||
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_MUX,
|
||||
|
||||
@ -509,12 +516,205 @@ enum GfxTileWireId
|
||||
TILE_WIRE_SP12_H_L_22,
|
||||
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_PLLOUT_A,
|
||||
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,
|
||||
GraphicElement::style_t style);
|
||||
|
||||
|
@ -733,7 +733,7 @@ static void pack_special(Context *ctx)
|
||||
|
||||
if (pi.name == ctx->id("PACKAGEPIN")) {
|
||||
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 {
|
||||
// We drop this port and instead place the PLL adequately below.
|
||||
pad_packagepin_net = port.second.net;
|
||||
@ -743,9 +743,22 @@ static void pack_special(Context *ctx)
|
||||
}
|
||||
if (pi.name == ctx->id("REFERENCECLK")) {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -766,7 +779,7 @@ static void pack_special(Context *ctx)
|
||||
auto pll_packagepin_driver = pad_packagepin_net->driver;
|
||||
NPNR_ASSERT(pll_packagepin_driver.cell != nullptr);
|
||||
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",
|
||||
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_bel_name = packagepin_cell->attrs.find(ctx->id("BEL"));
|
||||
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));
|
||||
}
|
||||
auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second));
|
||||
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(),
|
||||
ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str());
|
||||
}
|
||||
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));
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
pll_bel = bel;
|
||||
constrained = true;
|
||||
}
|
||||
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.
|
||||
auto port = packed->ports[ctx->id("LOCK")];
|
||||
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 all_luts = true;
|
||||
unsigned int lut_count = 0;
|
||||
@ -835,12 +850,12 @@ static void pack_special(Context *ctx)
|
||||
// Every user is a LUT, carry on now.
|
||||
} else if (found_lut && !all_luts && lut_count < 8) {
|
||||
// Strategy: create a pass-through LUT, move all non-LUT users behind it.
|
||||
log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx));
|
||||
log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx));
|
||||
auto pt = spliceLUT(ctx, packed.get(), port.name, true);
|
||||
new_cells.push_back(std::move(pt));
|
||||
} else {
|
||||
// Strategy: create a pass-through LUT, move every user behind it.
|
||||
log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx));
|
||||
log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx));
|
||||
auto pt = spliceLUT(ctx, packed.get(), port.name, false);
|
||||
new_cells.push_back(std::move(pt));
|
||||
}
|
||||
@ -864,7 +879,7 @@ static void pack_special(Context *ctx)
|
||||
auto target_bel = ctx->getBelByLocation(Loc(x, y, z++));
|
||||
auto target_bel_name = ctx->getBelName(target_bel).str(ctx);
|
||||
user.cell->attrs[ctx->id("BEL")] = target_bel_name;
|
||||
log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str());
|
||||
log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
ctx->settings.emplace(ctx->id("project/input/pcf"), filename);
|
||||
ctx->settings.emplace(ctx->id("input/pcf"), filename);
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
return false;
|
||||
|
@ -28,8 +28,8 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path)
|
||||
{
|
||||
root.put("project.arch.package", ctx->archArgs().package);
|
||||
if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end()) {
|
||||
std::string fn = ctx->settings[ctx->id("project/input/pcf")];
|
||||
if (ctx->settings.find(ctx->id("input/pcf")) != ctx->settings.end()) {
|
||||
std::string fn = ctx->settings[ctx->id("input/pcf")];
|
||||
root.put("project.input.pcf", make_relative(fn, path).string());
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ struct JsonNode
|
||||
std::map<string, JsonNode *> data_dict;
|
||||
std::vector<string> data_dict_keys;
|
||||
|
||||
JsonNode(std::istream &f)
|
||||
JsonNode(std::istream &f, int &lineno)
|
||||
{
|
||||
type = 0;
|
||||
data_number = 0;
|
||||
@ -63,6 +63,8 @@ struct JsonNode
|
||||
if (ch == EOF)
|
||||
log_error("Unexpected EOF in JSON file.\n");
|
||||
|
||||
if (ch == '\n')
|
||||
lineno++;
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
|
||||
continue;
|
||||
|
||||
@ -91,9 +93,12 @@ struct JsonNode
|
||||
break;
|
||||
}
|
||||
|
||||
if ('0' <= ch && ch <= '9') {
|
||||
if (('0' <= ch && ch <= '9') || ('-' == ch)) {
|
||||
type = 'N';
|
||||
data_number = ch - '0';
|
||||
if (ch == '-')
|
||||
data_number = 0;
|
||||
else
|
||||
data_number = ch - '0';
|
||||
data_string += ch;
|
||||
|
||||
while (1) {
|
||||
@ -114,6 +119,8 @@ struct JsonNode
|
||||
data_string += ch;
|
||||
}
|
||||
|
||||
if (data_string[0] == '-')
|
||||
data_number = -data_number;
|
||||
data_string = "";
|
||||
break;
|
||||
|
||||
@ -148,6 +155,8 @@ struct JsonNode
|
||||
if (ch == EOF)
|
||||
log_error("Unexpected EOF in JSON file.\n");
|
||||
|
||||
if (ch == '\n')
|
||||
lineno++;
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
|
||||
continue;
|
||||
|
||||
@ -155,7 +164,7 @@ struct JsonNode
|
||||
break;
|
||||
|
||||
f.unget();
|
||||
data_array.push_back(new JsonNode(f));
|
||||
data_array.push_back(new JsonNode(f, lineno));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -170,6 +179,8 @@ struct JsonNode
|
||||
if (ch == EOF)
|
||||
log_error("Unexpected EOF in JSON file.\n");
|
||||
|
||||
if (ch == '\n')
|
||||
lineno++;
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
|
||||
continue;
|
||||
|
||||
@ -177,7 +188,7 @@ struct JsonNode
|
||||
break;
|
||||
|
||||
f.unget();
|
||||
JsonNode key(f);
|
||||
JsonNode key(f, lineno);
|
||||
|
||||
while (1) {
|
||||
ch = f.get();
|
||||
@ -185,6 +196,8 @@ struct JsonNode
|
||||
if (ch == EOF)
|
||||
log_error("Unexpected EOF in JSON file.\n");
|
||||
|
||||
if (ch == '\n')
|
||||
lineno++;
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
|
||||
continue;
|
||||
|
||||
@ -192,10 +205,10 @@ struct JsonNode
|
||||
break;
|
||||
}
|
||||
|
||||
JsonNode *value = new JsonNode(f);
|
||||
JsonNode *value = new JsonNode(f, lineno);
|
||||
|
||||
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_keys.push_back(key.data_string);
|
||||
@ -204,7 +217,7 @@ struct JsonNode
|
||||
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 {
|
||||
using namespace JsonParser;
|
||||
int lineno = 1;
|
||||
|
||||
JsonNode root(f);
|
||||
JsonNode root(f, lineno);
|
||||
|
||||
if (root.type != 'D')
|
||||
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_break();
|
||||
ctx->settings.emplace(ctx->id("project/input/json"), filename);
|
||||
ctx->settings.emplace(ctx->id("input/json"), filename);
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
return false;
|
||||
|
@ -59,7 +59,7 @@ TEST_F(HX1KTest, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 27690);
|
||||
ASSERT_EQ(wire_count, 32802);
|
||||
}
|
||||
|
||||
TEST_F(HX1KTest, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(HX1KTest, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 319904);
|
||||
ASSERT_EQ(pip_count, 345504);
|
||||
}
|
||||
|
||||
TEST_F(HX1KTest, uphill_to_downhill)
|
||||
|
@ -59,7 +59,7 @@ TEST_F(HX8KTest, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 135182);
|
||||
ASSERT_EQ(wire_count, 165894);
|
||||
}
|
||||
|
||||
TEST_F(HX8KTest, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(HX8KTest, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 1652480);
|
||||
ASSERT_EQ(pip_count, 1806080);
|
||||
}
|
||||
|
||||
TEST_F(HX8KTest, uphill_to_downhill)
|
||||
|
@ -59,7 +59,7 @@ TEST_F(LP1KTest, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 27690);
|
||||
ASSERT_EQ(wire_count, 32802);
|
||||
}
|
||||
|
||||
TEST_F(LP1KTest, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(LP1KTest, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 319904);
|
||||
ASSERT_EQ(pip_count, 345504);
|
||||
}
|
||||
|
||||
TEST_F(LP1KTest, uphill_to_downhill)
|
||||
|
@ -59,7 +59,7 @@ TEST_F(LP384Test, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 8302);
|
||||
ASSERT_EQ(wire_count, 9830);
|
||||
}
|
||||
|
||||
TEST_F(LP384Test, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(LP384Test, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 86864);
|
||||
ASSERT_EQ(pip_count, 94544);
|
||||
}
|
||||
|
||||
TEST_F(LP384Test, uphill_to_downhill)
|
||||
|
@ -59,7 +59,7 @@ TEST_F(LP8KTest, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 135182);
|
||||
ASSERT_EQ(wire_count, 165894);
|
||||
}
|
||||
|
||||
TEST_F(LP8KTest, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(LP8KTest, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 1652480);
|
||||
ASSERT_EQ(pip_count, 1806080);
|
||||
}
|
||||
|
||||
TEST_F(LP8KTest, uphill_to_downhill)
|
||||
|
@ -59,7 +59,7 @@ TEST_F(UP5KTest, wire_names)
|
||||
assert(wire == ctx->getWireByName(name));
|
||||
wire_count++;
|
||||
}
|
||||
ASSERT_EQ(wire_count, 103391);
|
||||
ASSERT_EQ(wire_count, 124503);
|
||||
}
|
||||
|
||||
TEST_F(UP5KTest, pip_names)
|
||||
@ -70,7 +70,7 @@ TEST_F(UP5KTest, pip_names)
|
||||
assert(pip == ctx->getPipByName(name));
|
||||
pip_count++;
|
||||
}
|
||||
ASSERT_EQ(pip_count, 1219104);
|
||||
ASSERT_EQ(pip_count, 1324704);
|
||||
}
|
||||
|
||||
TEST_F(UP5KTest, uphill_to_downhill)
|
||||
|
Loading…
Reference in New Issue
Block a user