Merge github.com:YosysHQ/nextpnr into xc7

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

2
.gitignore vendored
View File

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

View File

@ -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())

View File

@ -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);
@ -131,6 +131,7 @@ private:
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 onHoverPropertyChanged(QtBrowserItem *))
};

View File

@ -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
View File

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

View File

@ -127,6 +127,13 @@ cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -
make -j$(nproc)
```
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)

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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));

View File

@ -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 {

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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
View File

@ -0,0 +1,63 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef SETTINGS_H
#define SETTINGS_H
#include <boost/lexical_cast.hpp>
#include "log.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
class Settings
{
public:
explicit Settings(Context *ctx) : ctx(ctx) {}
template <typename T> T get(const char *name, T defaultValue)
{
try {
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(defaultValue));
if (!pair.second) {
return boost::lexical_cast<T>(pair.first->second);
}
} catch (boost::bad_lexical_cast &) {
log_error("Problem reading setting %s, using default value\n", name);
}
return defaultValue;
}
template <typename T> void set(const char *name, T value)
{
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(value));
if (!pair.second) {
ctx->settings[pair.first->first] = value;
}
}
private:
Context *ctx;
};
NEXTPNR_NAMESPACE_END
#endif // SETTINGS_H

View File

@ -410,12 +410,13 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path)
log_info("estimated Fmax = %.2f MHz\n", 1e3 / ctx->getDelayNS(default_slack - min_slack));
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 ? '+' : ' ');

View File

@ -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

View File

@ -46,7 +46,9 @@ static std::tuple<int, int, std::string> split_identifier_name(const std::string
void IdString::initialize_arch(const BaseCtx *ctx)
{
#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
{
// 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
{
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)

View File

@ -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
{

View File

@ -35,26 +35,26 @@ bool Arch::slicesCompatible(const std::vector<const CellInfo *> &cells) const
{
// TODO: allow different LSR/CLK and MUX/SRMODE settings once
// 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;

View File

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

View File

@ -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

View File

@ -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")

View File

@ -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())); }
// ---------------------------------------------------------------

View File

@ -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);

View File

@ -109,6 +109,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, ArchArgs args,
connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem);
connect(designview, &DesignWidget::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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -28,6 +28,7 @@ NEXTPNR_NAMESPACE_BEGIN
void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir)
{
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);

View File

@ -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,7 +1289,8 @@ 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()):
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")
@ -1135,14 +1300,14 @@ 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()

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -746,6 +746,19 @@ static void pack_special(Context *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));
}
@ -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;

View File

@ -66,7 +66,7 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in)
log_error("unsupported pcf command '%s'\n", cmd.c_str());
}
}
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;

View File

@ -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());
}
}

View File

@ -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,8 +93,11 @@ struct JsonNode
break;
}
if ('0' <= ch && ch <= '9') {
if (('0' <= ch && ch <= '9') || ('-' == ch)) {
type = 'N';
if (ch == '-')
data_number = 0;
else
data_number = ch - '0';
data_string += ch;
@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)