aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc51
-rw-r--r--ecp5/arch.h31
-rw-r--r--ecp5/arch_pybindings.cc7
-rw-r--r--ecp5/bitstream.cc19
-rw-r--r--ecp5/family.cmake56
-rw-r--r--ecp5/main.cc4
-rw-r--r--ecp5/pack.cc14
7 files changed, 136 insertions, 46 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index da0f7b1a..91db8d81 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -28,6 +28,7 @@
#include "log.h"
#include "nextpnr.h"
#include "placer1.h"
+#include "placer_heap.h"
#include "router1.h"
#include "timing.h"
#include "util.h"
@@ -456,7 +457,8 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
auto src_loc = est_location(src), dst_loc = est_location(dst);
int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second);
- return (130 - 25 * args.speed) *
+
+ return (120 - 22 * args.speed) *
(6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
}
@@ -467,7 +469,6 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
return 0;
auto driver_loc = getBelLocation(driver.cell->bel);
auto sink_loc = getBelLocation(sink.cell->bel);
-
// Encourage use of direct interconnect
if (driver_loc.x == sink_loc.x && driver_loc.y == sink_loc.y) {
if ((sink.port == id_A0 || sink.port == id_A1) && (driver.port == id_F1) &&
@@ -485,7 +486,8 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
}
int dx = abs(driver_loc.x - sink_loc.x), dy = abs(driver_loc.y - sink_loc.y);
- return (130 - 25 * args.speed) *
+
+ return (120 - 22 * args.speed) *
(6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
}
@@ -502,14 +504,29 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
}
}
+delay_t Arch::getRipupDelayPenalty() const { return 400; }
+
// -----------------------------------------------------------------------
bool Arch::place()
{
- bool result = placer1(getCtx(), Placer1Cfg(getCtx()));
- if (result)
- permute_luts();
- return result;
+ std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
+
+ if (placer == "heap") {
+ PlacerHeapCfg cfg(getCtx());
+ cfg.criticalityExponent = 4;
+ cfg.ioBufTypes.insert(id_TRELLIS_IO);
+ if (!placer_heap(getCtx(), cfg))
+ return false;
+ } else if (placer == "sa") {
+ if (!placer1(getCtx(), Placer1Cfg(getCtx())))
+ return false;
+ } else {
+ log_error("ECP5 architecture does not support placer '%s'\n", placer.c_str());
+ }
+
+ permute_luts();
+ return true;
}
bool Arch::route()
@@ -605,6 +622,11 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
bool Arch::getDelayFromTimingDatabase(IdString tctype, IdString from, IdString to, DelayInfo &delay) const
{
+ auto fnd_dk = celldelay_cache.find({tctype, from, to});
+ if (fnd_dk != celldelay_cache.end()) {
+ delay = fnd_dk->second.second;
+ return fnd_dk->second.first;
+ }
for (int i = 0; i < speed_grade->num_cell_timings; i++) {
const auto &tc = speed_grade->cell_timings[i];
if (tc.cell_type == tctype.index) {
@@ -613,9 +635,11 @@ bool Arch::getDelayFromTimingDatabase(IdString tctype, IdString from, IdString t
if (dly.from_port == from.index && dly.to_port == to.index) {
delay.max_delay = dly.max_delay;
delay.min_delay = dly.min_delay;
+ celldelay_cache[{tctype, from, to}] = std::make_pair(true, delay);
return true;
}
}
+ celldelay_cache[{tctype, from, to}] = std::make_pair(false, DelayInfo());
return false;
}
}
@@ -645,7 +669,6 @@ void Arch::getSetupHoldFromTimingDatabase(IdString tctype, IdString clock, IdStr
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 = cell->sliceInfo.is_carry;
@@ -965,4 +988,16 @@ WireId Arch::getBankECLK(int bank, int eclk)
return getWireByLocAndBasename(Location(0, 0), "G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(eclk));
}
+#ifdef WITH_HEAP
+const std::string Arch::defaultPlacer = "heap";
+#else
+const std::string Arch::defaultPlacer = "sa";
+#endif
+
+const std::vector<std::string> Arch::availablePlacers = {"sa",
+#ifdef WITH_HEAP
+ "heap"
+#endif
+};
+
NEXTPNR_NAMESPACE_END
diff --git a/ecp5/arch.h b/ecp5/arch.h
index ab4a4e00..cee071e7 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -448,6 +448,30 @@ struct ArchArgs
} speed = SPEED_6;
};
+struct DelayKey
+{
+ IdString celltype, from, to;
+ inline bool operator==(const DelayKey &other) const
+ {
+ return celltype == other.celltype && from == other.from && to == other.to;
+ }
+};
+
+NEXTPNR_NAMESPACE_END
+namespace std {
+template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DelayKey>
+{
+ std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DelayKey &dk) const noexcept
+ {
+ std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.celltype);
+ seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.from) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ seed ^= std::hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
+ }
+};
+} // namespace std
+NEXTPNR_NAMESPACE_BEGIN
+
struct Arch : BaseCtx
{
const ChipInfoPOD *chip_info;
@@ -918,7 +942,7 @@ struct Arch : BaseCtx
delay_t estimateDelay(WireId src, WireId dst) const;
delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const;
delay_t getDelayEpsilon() const { return 20; }
- delay_t getRipupDelayPenalty() const { return 400; }
+ delay_t getRipupDelayPenalty() const;
float getDelayNS(delay_t v) const { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const
{
@@ -1019,6 +1043,11 @@ struct Arch : BaseCtx
IdString id_clk, id_lsr;
IdString id_clkmux, id_lsrmux;
IdString id_srmode, id_mode;
+
+ mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache;
+
+ static const std::string defaultPlacer;
+ static const std::vector<std::string> availablePlacers;
};
NEXTPNR_NAMESPACE_END
diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc
index 5e73a673..18d21112 100644
--- a/ecp5/arch_pybindings.cc
+++ b/ecp5/arch_pybindings.cc
@@ -133,6 +133,13 @@ void arch_wrap_python()
fn_wrapper_2a_v<Context, decltype(&Context::addClock), &Context::addClock, conv_from_str<IdString>,
pass_through<float>>::def_wrap(ctx_cls, "addClock");
+ fn_wrapper_5a_v<Context, decltype(&Context::createRectangularRegion), &Context::createRectangularRegion,
+ conv_from_str<IdString>, pass_through<int>, pass_through<int>, pass_through<int>,
+ pass_through<int>>::def_wrap(ctx_cls, "createRectangularRegion");
+ fn_wrapper_2a_v<Context, decltype(&Context::addBelToRegion), &Context::addBelToRegion, conv_from_str<IdString>,
+ conv_from_str<BelId>>::def_wrap(ctx_cls, "addBelToRegion");
+ fn_wrapper_2a_v<Context, decltype(&Context::constrainCellToRegion), &Context::constrainCellToRegion,
+ conv_from_str<IdString>, conv_from_str<IdString>>::def_wrap(ctx_cls, "constrainCellToRegion");
WRAP_RANGE(Bel, conv_to_str<BelId>);
WRAP_RANGE(Wire, conv_to_str<WireId>);
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index a9c82524..d549a727 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -134,7 +134,7 @@ inline int chtohex(char c)
return hex.find(c);
}
-std::vector<bool> parse_init_str(const std::string &str, int length)
+std::vector<bool> parse_init_str(const std::string &str, int length, const char *cellname)
{
// Parse a string that may be binary or hex
std::vector<bool> result;
@@ -161,7 +161,8 @@ std::vector<bool> parse_init_str(const std::string &str, int length)
log_error("hex string value too long, expected up to %d bits and found %d.\n", length, int(str.length()));
for (int i = 0; i < int(str.length()); i++) {
char c = str.at((str.size() - i) - 1);
- NPNR_ASSERT(c == '0' || c == '1' || c == 'X' || c == 'x');
+ if (c != '0' && c != '1' && c != 'X' && c != 'x')
+ log_error("Found illegal character '%c' while processing parameters for cell '%s'\n", c, cellname);
result.at(i) = (c == '1');
}
}
@@ -970,7 +971,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
for (int i = 0; i <= 0x3F; i++) {
IdString param = ctx->id("INITVAL_" +
fmt_str(std::hex << std::uppercase << std::setw(2) << std::setfill('0') << i));
- auto value = parse_init_str(str_or_default(ci->params, param, "0"), 320);
+ auto value = parse_init_str(str_or_default(ci->params, param, "0"), 320, ci->name.c_str(ctx));
for (int j = 0; j < 16; j++) {
// INIT parameter consists of 16 18-bit words with 2-bit padding
int ofs = 20 * j;
@@ -1078,17 +1079,21 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
tg.config.add_enum(dsp + ".MASKPAT_SOURCE",
str_or_default(ci->params, ctx->id("MASKPAT_SOURCE"), "STATIC"));
tg.config.add_word(dsp + ".MASK01",
- parse_init_str(str_or_default(ci->params, ctx->id("MASK01"), "0x00000000000000"), 56));
+ parse_init_str(str_or_default(ci->params, ctx->id("MASK01"), "0x00000000000000"), 56,
+ ci->name.c_str(ctx)));
tg.config.add_enum(dsp + ".CLK0_DIV", str_or_default(ci->params, ctx->id("CLK0_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK1_DIV", str_or_default(ci->params, ctx->id("CLK1_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK2_DIV", str_or_default(ci->params, ctx->id("CLK2_DIV"), "ENABLED"));
tg.config.add_enum(dsp + ".CLK3_DIV", str_or_default(ci->params, ctx->id("CLK3_DIV"), "ENABLED"));
tg.config.add_word(dsp + ".MCPAT",
- parse_init_str(str_or_default(ci->params, ctx->id("MCPAT"), "0x00000000000000"), 56));
+ parse_init_str(str_or_default(ci->params, ctx->id("MCPAT"), "0x00000000000000"), 56,
+ ci->name.c_str(ctx)));
tg.config.add_word(dsp + ".MASKPAT",
- parse_init_str(str_or_default(ci->params, ctx->id("MASKPAT"), "0x00000000000000"), 56));
+ parse_init_str(str_or_default(ci->params, ctx->id("MASKPAT"), "0x00000000000000"), 56,
+ ci->name.c_str(ctx)));
tg.config.add_word(dsp + ".RNDPAT",
- parse_init_str(str_or_default(ci->params, ctx->id("RNDPAT"), "0x00000000000000"), 56));
+ parse_init_str(str_or_default(ci->params, ctx->id("RNDPAT"), "0x00000000000000"), 56,
+ ci->name.c_str(ctx)));
tg.config.add_enum(dsp + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
tg.config.add_enum(dsp + ".RESETMODE", str_or_default(ci->params, ctx->id("RESETMODE"), "SYNC"));
tg.config.add_enum(dsp + ".FORCE_ZERO_BARREL_SHIFT",
diff --git a/ecp5/family.cmake b/ecp5/family.cmake
index 799851b2..ca7dc9e9 100644
--- a/ecp5/family.cmake
+++ b/ecp5/family.cmake
@@ -6,18 +6,18 @@ if (NOT EXTERNAL_CHIPDB)
set(TRELLIS_ROOT "/usr/local/share/trellis")
endif()
- file(GLOB found_pytrellis ${TRELLIS_ROOT}/libtrellis/pytrellis.*
- /usr/lib/pytrellis.*
- /usr/lib64/pytrellis.*
- /usr/lib/trellis/pytrellis.*
- /usr/lib64/trellis/pytrellis.*)
+ if (NOT DEFINED PYTRELLIS_LIBDIR)
+ find_library(PYTRELLIS pytrellis.so
+ PATHS ${TRELLIS_ROOT}/libtrellis
+ PATH_SUFFIXES trellis
+ DOC "Location of pytrellis library")
- if ("${found_pytrellis}" STREQUAL "")
- message(FATAL_ERROR "failed to locate pytrellis library!")
- endif()
+ if ("${PYTRELLIS}" STREQUAL "PYTRELLIS-NOTFOUND")
+ message(FATAL_ERROR "Failed to locate pytrellis library!")
+ endif()
- list(GET found_pytrellis 0 PYTRELLIS_LIB)
- get_filename_component(PYTRELLIS_LIBDIR ${PYTRELLIS_LIB} DIRECTORY)
+ get_filename_component(PYTRELLIS_LIBDIR ${PYTRELLIS} DIRECTORY)
+ endif()
set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/trellis_import.py)
@@ -27,9 +27,9 @@ if (NOT EXTERNAL_CHIPDB)
target_include_directories(ecp5_chipdb PRIVATE ${family}/)
if (CMAKE_HOST_WIN32)
- set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=\"${PYTRELLIS_LIBDIR}\;${TRELLIS_ROOT}/util/common\;${TRELLIS_ROOT}/timing/util\"")
+ set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=\"${PYTRELLIS_LIBDIR}\;${TRELLIS_ROOT}/util/common\;${TRELLIS_ROOT}/timing/util\"")
else()
- set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${PYTRELLIS_LIBDIR}\:${TRELLIS_ROOT}/util/common:${TRELLIS_ROOT}/timing/util")
+ set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${PYTRELLIS_LIBDIR}\:${TRELLIS_ROOT}/util/common:${TRELLIS_ROOT}/timing/util")
endif()
if (MSVC)
@@ -38,15 +38,15 @@ if (NOT EXTERNAL_CHIPDB)
foreach (dev ${devices})
set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.bin)
set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.bba)
- set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
+ set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
- COMMAND ${ENV_CMD} python3 ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}
- DEPENDS ${DB_PY}
- )
+ COMMAND ${ENV_CMD} python3 ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}
+ DEPENDS ${DB_PY}
+ )
add_custom_command(OUTPUT ${DEV_CC_DB}
- COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB}
- DEPENDS bbasm ${DEV_CC_BBA_DB}
- )
+ COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB}
+ DEPENDS bbasm ${DEV_CC_BBA_DB}
+ )
target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB})
set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE)
foreach (target ${family_targets})
@@ -58,17 +58,17 @@ if (NOT EXTERNAL_CHIPDB)
foreach (dev ${devices})
set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.cc)
set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/chipdbs/chipdb-${dev}.bba)
- set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
+ set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
- COMMAND ${ENV_CMD} python3 ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new
- COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
- DEPENDS ${DB_PY}
- )
+ COMMAND ${ENV_CMD} python3 ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new
+ COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
+ DEPENDS ${DB_PY}
+ )
add_custom_command(OUTPUT ${DEV_CC_DB}
- COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
- COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
- DEPENDS bbasm ${DEV_CC_BBA_DB}
- )
+ COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
+ COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
+ DEPENDS bbasm ${DEV_CC_BBA_DB}
+ )
target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB})
foreach (target ${family_targets})
target_sources(${target} PRIVATE $<TARGET_OBJECTS:ecp5_chipdb>)
diff --git a/ecp5/main.cc b/ecp5/main.cc
index 15027a5a..bb18aa58 100644
--- a/ecp5/main.cc
+++ b/ecp5/main.cc
@@ -149,8 +149,8 @@ std::unique_ptr<Context> ECP5CommandHandler::createContext()
chipArgs.speed = ArchArgs::SPEED_6;
}
}
-
- return std::unique_ptr<Context>(new Context(chipArgs));
+ auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
+ return ctx;
}
void ECP5CommandHandler::customAfterLoad(Context *ctx)
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 1b07c2ae..7f00de1f 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -1390,6 +1390,19 @@ class Ecp5Packer
}
}
+ // Miscellaneous packer tasks
+ void pack_misc()
+ {
+ for (auto cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type == id_USRMCLK) {
+ rename_port(ctx, ci, ctx->id("USRMCLKI"), id_PADDO);
+ rename_port(ctx, ci, ctx->id("USRMCLKTS"), id_PADDT);
+ rename_port(ctx, ci, ctx->id("USRMCLKO"), id_PADDI);
+ }
+ }
+ }
+
// Preplace PLL
void preplace_plls()
{
@@ -2371,6 +2384,7 @@ class Ecp5Packer
pack_ebr();
pack_dsps();
pack_dcus();
+ pack_misc();
preplace_plls();
pack_constants();
pack_dram();