Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr

This commit is contained in:
Clifford Wolf 2018-06-23 16:14:39 +02:00
commit 0ccd9febeb
41 changed files with 555 additions and 680 deletions

View File

@ -24,8 +24,7 @@
#include "util.h" #include "util.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdString rep_name)
IdString rep_name)
{ {
PortInfo &old = old_cell->ports.at(old_name); PortInfo &old = old_cell->ports.at(old_name);
PortInfo &rep = rep_cell->ports.at(rep_name); PortInfo &rep = rep_cell->ports.at(rep_name);
@ -69,8 +68,7 @@ void print_utilisation(const Context *ctx)
for (auto type : available_types) { for (auto type : available_types) {
IdString type_id = ctx->belTypeToId(type.first); IdString type_id = ctx->belTypeToId(type.first);
int used_bels = get_or_default(used_types, type.first, 0); int used_bels = get_or_default(used_types, type.first, 0);
log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), used_bels, log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), used_bels, type.second, 100 * used_bels / type.second);
type.second, 100 * used_bels / type.second);
} }
log_break(); log_break();
} }

View File

@ -32,8 +32,7 @@ Utilities for design manipulation, intended for use inside packing algorithms
*/ */
// Disconnect a net (if connected) from old, and connect it to rep // Disconnect a net (if connected) from old, and connect it to rep
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdString rep_name);
IdString rep_name);
// If a net drives a given port of a cell matching a predicate (in many // If a net drives a given port of a cell matching a predicate (in many
// cases more than one cell type, e.g. SB_DFFxx so a predicate is used), return // cases more than one cell type, e.g. SB_DFFxx so a predicate is used), return
@ -41,8 +40,7 @@ void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
// true, then this cell must be the only load. If ignore_cell is set, that cell // true, then this cell must be the only load. If ignore_cell is set, that cell
// is not considered // is not considered
template <typename F1> template <typename F1>
CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred, CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred, IdString port, bool exclusive = false,
IdString port, bool exclusive = false,
CellInfo *exclude = nullptr) CellInfo *exclude = nullptr)
{ {
if (net == nullptr) if (net == nullptr)
@ -56,16 +54,13 @@ CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
return nullptr; return nullptr;
} else if (net->users.size() == 2) { } else if (net->users.size() == 2) {
if (std::find_if(net->users.begin(), net->users.end(), if (std::find_if(net->users.begin(), net->users.end(),
[exclude](const PortRef &ref) { [exclude](const PortRef &ref) { return ref.cell == exclude; }) == net->users.end())
return ref.cell == exclude;
}) == net->users.end())
return nullptr; return nullptr;
} }
} }
} }
for (const auto &load : net->users) { for (const auto &load : net->users) {
if (load.cell != exclude && cell_pred(ctx, load.cell) && if (load.cell != exclude && cell_pred(ctx, load.cell) && load.port == port) {
load.port == port) {
return load.cell; return load.cell;
} }
} }
@ -74,9 +69,7 @@ CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
// If a net is driven by a given port of a cell matching a predicate, return // If a net is driven by a given port of a cell matching a predicate, return
// that cell, otherwise nullptr // that cell, otherwise nullptr
template <typename F1> template <typename F1> CellInfo *net_driven_by(const Context *ctx, const NetInfo *net, F1 cell_pred, IdString port)
CellInfo *net_driven_by(const Context *ctx, const NetInfo *net, F1 cell_pred,
IdString port)
{ {
if (net == nullptr) if (net == nullptr)
return nullptr; return nullptr;

View File

@ -107,8 +107,7 @@ PyMODINIT_FUNC PyInit_emb(void)
PyObject *m = PyModule_Create(&embmodule); PyObject *m = PyModule_Create(&embmodule);
if (m) { if (m) {
Py_INCREF(&StdoutType); Py_INCREF(&StdoutType);
PyModule_AddObject(m, "Stdout", PyModule_AddObject(m, "Stdout", reinterpret_cast<PyObject *>(&StdoutType));
reinterpret_cast<PyObject *>(&StdoutType));
} }
return m; return m;
} }

View File

@ -88,19 +88,17 @@ class SAPlacer
std::string loc_name = loc->second; std::string loc_name = loc->second;
BelId bel = ctx->getBelByName(ctx->id(loc_name)); BelId bel = ctx->getBelByName(ctx->id(loc_name));
if (bel == BelId()) { if (bel == BelId()) {
log_error( log_error("No Bel named \'%s\' located for "
"No Bel named \'%s\' located for " "this chip (processing BEL attribute on \'%s\')\n",
"this chip (processing BEL attribute on \'%s\')\n", loc_name.c_str(), cell->name.c_str(ctx));
loc_name.c_str(), cell->name.c_str(ctx));
} }
BelType bel_type = ctx->getBelType(bel); BelType bel_type = ctx->getBelType(bel);
if (bel_type != ctx->belTypeFromId(cell->type)) { if (bel_type != ctx->belTypeFromId(cell->type)) {
log_error("Bel \'%s\' of type \'%s\' does not match cell " log_error("Bel \'%s\' of type \'%s\' does not match cell "
"\'%s\' of type \'%s\'", "\'%s\' of type \'%s\'",
loc_name.c_str(), loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx),
ctx->belTypeToId(bel_type).c_str(ctx), cell->type.c_str(ctx));
cell->name.c_str(ctx), cell->type.c_str(ctx));
} }
ctx->bindBel(bel, cell->name, STRENGTH_USER); ctx->bindBel(bel, cell->name, STRENGTH_USER);
@ -119,25 +117,21 @@ class SAPlacer
autoplaced.push_back(cell.second); autoplaced.push_back(cell.second);
} }
} }
std::sort(autoplaced.begin(), autoplaced.end(), std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; });
[](CellInfo *a, CellInfo *b) { return a->name < b->name; });
ctx->shuffle(autoplaced); ctx->shuffle(autoplaced);
// Place cells randomly initially // Place cells randomly initially
log_info("Creating initial placement for remaining %d cells.\n", log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size()));
int(autoplaced.size()));
for (auto cell : autoplaced) { for (auto cell : autoplaced) {
place_initial(cell); place_initial(cell);
placed_cells++; placed_cells++;
if ((placed_cells - constr_placed_cells) % 500 == 0) if ((placed_cells - constr_placed_cells) % 500 == 0)
log_info(" initial placement placed %d/%d cells\n", log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
int(placed_cells - constr_placed_cells),
int(autoplaced.size())); int(autoplaced.size()));
} }
if ((placed_cells - constr_placed_cells) % 500 != 0) if ((placed_cells - constr_placed_cells) % 500 != 0)
log_info(" initial placement placed %d/%d cells\n", log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
int(placed_cells - constr_placed_cells),
int(autoplaced.size())); int(autoplaced.size()));
log_info("Running simulated annealing placer.\n"); log_info("Running simulated annealing placer.\n");
@ -184,9 +178,7 @@ class SAPlacer
if (temp <= 1e-3 && n_no_progress >= 5) { if (temp <= 1e-3 && n_no_progress >= 5) {
if (iter % 5 != 0) if (iter % 5 != 0)
log_info( log_info(" at iteration #%d: temp = %f, wire length = %f\n", iter, temp, double(curr_wirelength));
" at iteration #%d: temp = %f, wire length = %f\n",
iter, temp, double(curr_wirelength));
break; break;
} }
@ -235,15 +227,13 @@ class SAPlacer
if (cell != IdString()) if (cell != IdString())
cell_text = std::string("cell '") + cell.str(ctx) + "'"; cell_text = std::string("cell '") + cell.str(ctx) + "'";
if (ctx->force) { if (ctx->force) {
log_warning( log_warning("post-placement validity check failed for Bel '%s' "
"post-placement validity check failed for Bel '%s' " "(%s)\n",
"(%s)\n", ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
} else { } else {
log_error( log_error("post-placement validity check failed for Bel '%s' "
"post-placement validity check failed for Bel '%s' " "(%s)\n",
"(%s)\n", ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
} }
} }
} }
@ -267,8 +257,7 @@ class SAPlacer
} }
BelType targetType = ctx->belTypeFromId(cell->type); BelType targetType = ctx->belTypeFromId(cell->type);
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
if (ctx->getBelType(bel) == targetType && if (ctx->getBelType(bel) == targetType && checker->isValidBelForCell(cell, bel)) {
checker->isValidBelForCell(cell, bel)) {
if (ctx->checkBelAvail(bel)) { if (ctx->checkBelAvail(bel)) {
uint64_t score = ctx->rng64(); uint64_t score = ctx->rng64();
if (score <= best_score) { if (score <= best_score) {
@ -279,8 +268,7 @@ class SAPlacer
uint64_t score = ctx->rng64(); uint64_t score = ctx->rng64();
if (score <= best_ripup_score) { if (score <= best_ripup_score) {
best_ripup_score = score; best_ripup_score = score;
ripup_target = ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel));
ctx->cells.at(ctx->getBoundBelCell(bel));
ripup_bel = bel; ripup_bel = bel;
} }
} }
@ -288,8 +276,7 @@ class SAPlacer
} }
if (best_bel == BelId()) { if (best_bel == BelId()) {
if (iters == 0 || ripup_bel == BelId()) if (iters == 0 || ripup_bel == BelId())
log_error("failed to place cell '%s' of type '%s'\n", log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx));
cell->name.c_str(ctx), cell->type.c_str(ctx));
--iters; --iters;
ctx->unbindBel(ripup_target->bel); ctx->unbindBel(ripup_target->bel);
best_bel = ripup_bel; best_bel = ripup_bel;
@ -316,8 +303,7 @@ class SAPlacer
if (driver_cell->bel == BelId()) if (driver_cell->bel == BelId())
return 0; return 0;
ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb); ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb);
WireId drv_wire = ctx->getWireBelPin( WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port));
driver_cell->bel, ctx->portPinFromId(net->driver.port));
if (driver_gb) if (driver_gb)
return 0; return 0;
float worst_slack = 1000; float worst_slack = 1000;
@ -329,11 +315,9 @@ class SAPlacer
if (load_cell->bel == BelId()) if (load_cell->bel == BelId())
continue; continue;
if (timing_driven) { if (timing_driven) {
WireId user_wire = ctx->getWireBelPin( WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port));
load_cell->bel, ctx->portPinFromId(load.port));
delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire);
float slack = float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
if (slack < 0) if (slack < 0)
tns += slack; tns += slack;
worst_slack = std::min(slack, worst_slack); worst_slack = std::min(slack, worst_slack);
@ -351,11 +335,9 @@ class SAPlacer
} }
if (timing_driven) { if (timing_driven) {
wirelength = wirelength =
wirelen_t((((ymax - ymin) + (xmax - xmin)) * wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
} else { } else {
wirelength = wirelength = wirelen_t((ymax - ymin) + (xmax - xmin));
wirelen_t((ymax - ymin) + (xmax - xmin));
} }
return wirelength; return wirelength;
@ -394,8 +376,7 @@ class SAPlacer
ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
} }
if (!checker->isBelLocationValid(newBel) || if (!checker->isBelLocationValid(newBel) || ((other != IdString() && !checker->isBelLocationValid(oldBel)))) {
((other != IdString() && !checker->isBelLocationValid(oldBel)))) {
ctx->unbindBel(newBel); ctx->unbindBel(newBel);
if (other != IdString()) if (other != IdString())
ctx->unbindBel(oldBel); ctx->unbindBel(oldBel);
@ -415,8 +396,7 @@ class SAPlacer
delta = new_wirelength - curr_wirelength; delta = new_wirelength - curr_wirelength;
n_move++; n_move++;
// SA acceptance criterea // SA acceptance criterea
if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
std::exp(-delta / temp))) {
n_accept++; n_accept++;
if (delta < 2) if (delta < 2)
improved = true; improved = true;

View File

@ -43,10 +43,7 @@ NEXTPNR_NAMESPACE_BEGIN
// must be implemented in all architectures // must be implemented in all architectures
void arch_wrap_python(); void arch_wrap_python();
bool operator==(const PortRef &a, const PortRef &b) bool operator==(const PortRef &a, const PortRef &b) { return (a.cell == b.cell) && (a.port == b.port); }
{
return (a.cell == b.cell) && (a.port == b.port);
}
// Load a JSON file into a design // Load a JSON file into a design
void parse_json_shim(std::string filename, Context &d) void parse_json_shim(std::string filename, Context &d)
@ -75,9 +72,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
.def_readwrite("y2", &GraphicElement::y2) .def_readwrite("y2", &GraphicElement::y2)
.def_readwrite("text", &GraphicElement::text); .def_readwrite("text", &GraphicElement::text);
class_<PortRef>("PortRef") class_<PortRef>("PortRef").def_readwrite("cell", &PortRef::cell).def_readwrite("port", &PortRef::port);
.def_readwrite("cell", &PortRef::cell)
.def_readwrite("port", &PortRef::port);
class_<NetInfo, NetInfo *>("NetInfo") class_<NetInfo, NetInfo *>("NetInfo")
.def_readwrite("name", &NetInfo::name) .def_readwrite("name", &NetInfo::name)
@ -88,8 +83,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap"); WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap");
class_<std::vector<PortRef>>("PortRefVector") class_<std::vector<PortRef>>("PortRefVector").def(vector_indexing_suite<std::vector<PortRef>>());
.def(vector_indexing_suite<std::vector<PortRef>>());
enum_<PortType>("PortType") enum_<PortType>("PortType")
.value("PORT_IN", PORT_IN) .value("PORT_IN", PORT_IN)
@ -125,17 +119,13 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
def("load_design", load_design_shim); def("load_design", load_design_shim);
class_<IdString>("IdString") class_<IdString>("IdString")
.def("__str__", &IdString::global_str, .def("__str__", &IdString::global_str, return_value_policy<copy_const_reference>())
return_value_policy<copy_const_reference>())
.def(self < self) .def(self < self)
.def(self == self); .def(self == self);
arch_wrap_python(); arch_wrap_python();
} }
void arch_appendinittab() void arch_appendinittab() { PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME); }
{
PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME);
}
static wchar_t *program; static wchar_t *program;

View File

@ -45,26 +45,18 @@ template <typename T> struct string_wrapper
{ {
from_pystring_converter() from_pystring_converter()
{ {
converter::registry::push_back(&convertible, &construct, converter::registry::push_back(&convertible, &construct, boost::python::type_id<T>());
boost::python::type_id<T>());
}; };
static void *convertible(PyObject *object) static void *convertible(PyObject *object) { return PyUnicode_Check(object) ? object : 0; }
{
return PyUnicode_Check(object) ? object : 0;
}
static void construct(PyObject *object, static void construct(PyObject *object, converter::rvalue_from_python_stage1_data *data)
converter::rvalue_from_python_stage1_data *data)
{ {
const wchar_t *value = PyUnicode_AsUnicode(object); const wchar_t *value = PyUnicode_AsUnicode(object);
const std::wstring value_ws(value); const std::wstring value_ws(value);
if (value == 0) if (value == 0)
throw_error_already_set(); throw_error_already_set();
void *storage = void *storage = ((boost::python::converter::rvalue_from_python_storage<T> *)data)->storage.bytes;
((boost::python::converter::rvalue_from_python_storage<T> *)
data)
->storage.bytes;
new (storage) T(fn(std::string(value_ws.begin(), value_ws.end()))); new (storage) T(fn(std::string(value_ws.begin(), value_ws.end())));
data->convertible = storage; data->convertible = storage;
} }
@ -79,8 +71,7 @@ template <typename T> struct string_wrapper
std::string str(T &x) { return fn(x); } std::string str(T &x) { return fn(x); }
}; };
template <typename F1, typename F2> template <typename F1, typename F2> static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn)
static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn)
{ {
from_pystring_converter<F2>::fn = from_str_fn; from_pystring_converter<F2>::fn = from_str_fn;
from_pystring_converter<F2>(); from_pystring_converter<F2>();

View File

@ -61,8 +61,7 @@ template <typename T, typename P> struct iterator_wrapper
static void wrap(const char *python_name) static void wrap(const char *python_name)
{ {
class_<std::pair<T, T>>(python_name, no_init) class_<std::pair<T, T>>(python_name, no_init).def("__next__", next, P());
.def("__next__", next, P());
} }
}; };
@ -72,15 +71,11 @@ and end() which return iterator-like objects supporting ++, * and !=
Full STL iterator semantics are not required, unlike the standard Boost wrappers Full STL iterator semantics are not required, unlike the standard Boost wrappers
*/ */
template <typename T, typename P = return_value_policy<return_by_value>> template <typename T, typename P = return_value_policy<return_by_value>> struct range_wrapper
struct range_wrapper
{ {
typedef decltype(std::declval<T>().begin()) iterator_t; typedef decltype(std::declval<T>().begin()) iterator_t;
static std::pair<iterator_t, iterator_t> iter(T &range) static std::pair<iterator_t, iterator_t> iter(T &range) { return std::make_pair(range.begin(), range.end()); }
{
return std::make_pair(range.begin(), range.end());
}
static void wrap(const char *range_name, const char *iter_name) static void wrap(const char *range_name, const char *iter_name)
{ {
@ -122,8 +117,7 @@ template <typename T1, typename T2> struct pair_wrapper
static void wrap(const char *python_name) static void wrap(const char *python_name)
{ {
class_<std::pair<T &, int>>(python_name, no_init) class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next);
.def("__next__", next);
} }
}; };
@ -146,10 +140,7 @@ template <typename T1, typename T2> struct pair_wrapper
static int len(T &x) { return 2; } static int len(T &x) { return 2; }
static std::pair<T &, int> iter(T &x) static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); };
{
return std::make_pair(boost::ref(x), 0);
};
static void wrap(const char *pair_name, const char *iter_name) static void wrap(const char *pair_name, const char *iter_name)
{ {
@ -192,8 +183,7 @@ template <typename T1, typename T2> struct map_pair_wrapper
static void wrap(const char *python_name) static void wrap(const char *python_name)
{ {
class_<std::pair<T &, int>>(python_name, no_init) class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next);
.def("__next__", next);
} }
}; };
@ -206,10 +196,7 @@ template <typename T1, typename T2> struct map_pair_wrapper
static int len(T &x) { return 2; } static int len(T &x) { return 2; }
static std::pair<T &, int> iter(T &x) static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); };
{
return std::make_pair(boost::ref(x), 0);
};
static void wrap(const char *pair_name, const char *iter_name) static void wrap(const char *pair_name, const char *iter_name)
{ {
@ -229,8 +216,7 @@ Wrapper for a map, either an unordered_map, regular map or dict
template <typename T> struct map_wrapper template <typename T> struct map_wrapper
{ {
typedef typename std::remove_cv< typedef typename std::remove_cv<typename std::remove_reference<typename T::key_type>::type>::type K;
typename std::remove_reference<typename T::key_type>::type>::type K;
typedef typename T::mapped_type V; typedef typename T::mapped_type V;
typedef typename T::value_type KV; typedef typename T::value_type KV;
@ -253,13 +239,10 @@ template <typename T> struct map_wrapper
std::terminate(); std::terminate();
} }
static void wrap(const char *map_name, const char *kv_name, static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
const char *kv_iter_name, const char *iter_name)
{ {
map_pair_wrapper<typename KV::first_type, map_pair_wrapper<typename KV::first_type, typename KV::second_type>::wrap(kv_name, kv_iter_name);
typename KV::second_type>::wrap(kv_name, kv_iter_name); typedef range_wrapper<T, return_value_policy<copy_non_const_reference>> rw;
typedef range_wrapper<T, return_value_policy<copy_non_const_reference>>
rw;
typename rw::iter_wrap().wrap(iter_name); typename rw::iter_wrap().wrap(iter_name);
class_<T>(map_name, no_init) class_<T>(map_name, no_init)
.def("__iter__", rw::iter) .def("__iter__", rw::iter)
@ -269,9 +252,7 @@ template <typename T> struct map_wrapper
} }
}; };
#define WRAP_MAP(t, name) \ #define WRAP_MAP(t, name) map_wrapper<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
map_wrapper<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", \
#name "Iterator")
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -25,12 +25,10 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack);
delay_t slack);
// Follow a path, returning budget to annotate // Follow a path, returning budget to annotate
static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, delay_t slack)
delay_t slack)
{ {
delay_t value; delay_t value;
if (ctx->getPortClock(user.cell, user.port) != IdString()) { if (ctx->getPortClock(user.cell, user.port) != IdString()) {
@ -45,13 +43,11 @@ static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length,
if (port.second.type == PORT_OUT) { if (port.second.type == PORT_OUT) {
delay_t comb_delay; delay_t comb_delay;
// Look up delay through this path // Look up delay through this path
bool is_path = ctx->getCellDelay(user.cell, user.port, bool is_path = ctx->getCellDelay(user.cell, user.port, port.first, comb_delay);
port.first, comb_delay);
if (is_path) { if (is_path) {
NetInfo *net = port.second.net; NetInfo *net = port.second.net;
if (net) { if (net) {
delay_t path_budget = follow_net(ctx, net, path_length, delay_t path_budget = follow_net(ctx, net, path_length, slack - comb_delay);
slack - comb_delay);
value = std::min(value, path_budget); value = std::min(value, path_budget);
} }
} }
@ -65,13 +61,11 @@ static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length,
return value; return value;
} }
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack)
delay_t slack)
{ {
delay_t net_budget = slack / (path_length + 1); delay_t net_budget = slack / (path_length + 1);
for (auto &usr : net->users) { for (auto &usr : net->users) {
net_budget = std::min( net_budget = std::min(net_budget, follow_user_port(ctx, usr, path_length + 1, slack));
net_budget, follow_user_port(ctx, usr, path_length + 1, slack));
} }
return net_budget; return net_budget;
} }
@ -91,11 +85,9 @@ void assign_budget(Context *ctx, float default_clock)
for (auto cell : ctx->cells) { for (auto cell : ctx->cells) {
for (auto port : cell.second->ports) { for (auto port : cell.second->ports) {
if (port.second.type == PORT_OUT) { if (port.second.type == PORT_OUT) {
IdString clock_domain = IdString clock_domain = ctx->getPortClock(cell.second, port.first);
ctx->getPortClock(cell.second, port.first);
if (clock_domain != IdString()) { if (clock_domain != IdString()) {
delay_t slack = delay_t( delay_t slack = delay_t(1.0e12 / default_clock); // TODO: clock constraints
1.0e12 / default_clock); // TODO: clock constraints
if (port.second.net) if (port.second.net)
follow_net(ctx, port.second.net, 0, slack); follow_net(ctx, port.second.net, 0, slack);
} }
@ -109,13 +101,13 @@ void assign_budget(Context *ctx, float default_clock)
if (user.budget < 0) if (user.budget < 0)
log_warning("port %s.%s, connected to net '%s', has negative " log_warning("port %s.%s, connected to net '%s', has negative "
"timing budget of %fns\n", "timing budget of %fns\n",
user.cell->name.c_str(ctx), user.port.c_str(ctx), user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
net.first.c_str(ctx), ctx->getDelayNS(user.budget)); ctx->getDelayNS(user.budget));
if (ctx->verbose) if (ctx->verbose)
log_info("port %s.%s, connected to net '%s', has " log_info("port %s.%s, connected to net '%s', has "
"timing budget of %fns\n", "timing budget of %fns\n",
user.cell->name.c_str(ctx), user.port.c_str(ctx), user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
net.first.c_str(ctx), ctx->getDelayNS(user.budget)); ctx->getDelayNS(user.budget));
} }
} }

View File

@ -29,8 +29,7 @@ NEXTPNR_NAMESPACE_BEGIN
// Get a value from a map-style container, returning default if value is not // Get a value from a map-style container, returning default if value is not
// found // found
template <typename Container, typename KeyType, typename ValueType> template <typename Container, typename KeyType, typename ValueType>
ValueType get_or_default(const Container &ct, const KeyType &key, ValueType get_or_default(const Container &ct, const KeyType &key, ValueType def = ValueType())
ValueType def = ValueType())
{ {
auto found = ct.find(key); auto found = ct.find(key);
if (found == ct.end()) if (found == ct.end())
@ -41,8 +40,7 @@ ValueType get_or_default(const Container &ct, const KeyType &key,
// Get a value from a map-style container, converting to int, and returning // Get a value from a map-style container, converting to int, and returning
// default if value is not found // default if value is not found
template <typename Container, typename KeyType> template <typename Container, typename KeyType> int int_or_default(const Container &ct, const KeyType &key, int def = 0)
int int_or_default(const Container &ct, const KeyType &key, int def = 0)
{ {
auto found = ct.find(key); auto found = ct.find(key);
if (found == ct.end()) if (found == ct.end())
@ -59,8 +57,7 @@ bool bool_or_default(const Container &ct, const KeyType &key, bool def = false)
}; };
// Wrap an unordered_map, and allow it to be iterated over sorted by key // Wrap an unordered_map, and allow it to be iterated over sorted by key
template <typename K, typename V> template <typename K, typename V> std::map<K, V> sorted(const std::unordered_map<K, V> &orig)
std::map<K, V> sorted(const std::unordered_map<K, V> &orig)
{ {
return std::map<K, V>(orig.begin(), orig.end()); return std::map<K, V>(orig.begin(), orig.end());
}; };

View File

@ -23,10 +23,7 @@ NEXTPNR_NAMESPACE_BEGIN
PlaceValidityChecker::PlaceValidityChecker(Context *ctx) {} PlaceValidityChecker::PlaceValidityChecker(Context *ctx) {}
bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel) bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel) { return true; }
{
return true;
}
bool PlaceValidityChecker::isBelLocationValid(BelId bel) { return true; } bool PlaceValidityChecker::isBelLocationValid(BelId bel) { return true; }

View File

@ -29,10 +29,10 @@
#endif #endif
#include <boost/filesystem/convenience.hpp> #include <boost/filesystem/convenience.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iostream>
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "version.h" #include "version.h"
#include <iostream>
USING_NEXTPNR_NAMESPACE USING_NEXTPNR_NAMESPACE
@ -55,18 +55,14 @@ int main(int argc, char *argv[])
po::positional_options_description pos; po::positional_options_description pos;
#ifndef NO_PYTHON #ifndef NO_PYTHON
options.add_options()("run", po::value<std::vector<std::string>>(), options.add_options()("run", po::value<std::vector<std::string>>(), "python file to execute");
"python file to execute");
pos.add("run", -1); pos.add("run", -1);
#endif #endif
options.add_options()("version,V", "show version"); options.add_options()("version,V", "show version");
po::variables_map vm; po::variables_map vm;
try { try {
po::parsed_options parsed = po::command_line_parser(argc, argv) po::parsed_options parsed = po::command_line_parser(argc, argv).options(options).positional(pos).run();
.options(options)
.positional(pos)
.run();
po::store(parsed, vm); po::store(parsed, vm);
@ -79,18 +75,16 @@ int main(int argc, char *argv[])
} }
if (vm.count("help") || argc == 1) { if (vm.count("help") || argc == 1) {
std::cout << boost::filesystem::basename(argv[0]) std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
<< " -- Next Generation Place and Route (git " "sha1 " GIT_COMMIT_HASH_STR ")\n";
"sha1 " GIT_COMMIT_HASH_STR ")\n";
std::cout << "\n"; std::cout << "\n";
std::cout << options << "\n"; std::cout << options << "\n";
return argc != 1; return argc != 1;
} }
if (vm.count("version")) { if (vm.count("version")) {
std::cout << boost::filesystem::basename(argv[0]) std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
<< " -- Next Generation Place and Route (git " "sha1 " GIT_COMMIT_HASH_STR ")\n";
"sha1 " GIT_COMMIT_HASH_STR ")\n";
return 1; return 1;
} }
@ -115,8 +109,7 @@ int main(int argc, char *argv[])
#ifndef NO_PYTHON #ifndef NO_PYTHON
if (vm.count("run")) { if (vm.count("run")) {
std::vector<std::string> files = std::vector<std::string> files = vm["run"].as<std::vector<std::string>>();
vm["run"].as<std::vector<std::string>>();
for (auto filename : files) for (auto filename : files)
execute_python_file(filename.c_str()); execute_python_file(filename.c_str());
} }

View File

@ -36,8 +36,7 @@ static void initBasenameResource() { Q_INIT_RESOURCE(base); }
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) : QMainWindow(parent), ctx(_ctx)
: QMainWindow(parent), ctx(_ctx)
{ {
initBasenameResource(); initBasenameResource();
qRegisterMetaType<std::string>(); qRegisterMetaType<std::string>();
@ -69,8 +68,7 @@ BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent)
designview->setMaximumWidth(300); designview->setMaximumWidth(300);
splitter_h->addWidget(designview); splitter_h->addWidget(designview);
connect(designview, SIGNAL(info(std::string)), this, connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string)));
SLOT(writeInfo(std::string)));
tabWidget = new QTabWidget(); tabWidget = new QTabWidget();
#ifndef NO_PYTHON #ifndef NO_PYTHON

View File

@ -37,10 +37,7 @@ enum class ElementType
class ElementTreeItem : public QTreeWidgetItem class ElementTreeItem : public QTreeWidgetItem
{ {
public: public:
ElementTreeItem(ElementType t, QString str) ElementTreeItem(ElementType t, QString str) : QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(str)), type(t) {}
: QTreeWidgetItem((QTreeWidget *)nullptr, QStringList(str)), type(t)
{
}
virtual ~ElementTreeItem(){}; virtual ~ElementTreeItem(){};
ElementType getType() { return type; }; ElementType getType() { return type; };
@ -52,11 +49,7 @@ class ElementTreeItem : public QTreeWidgetItem
class BelTreeItem : public ElementTreeItem class BelTreeItem : public ElementTreeItem
{ {
public: public:
BelTreeItem(IdString d, ElementType type, QString str) BelTreeItem(IdString d, ElementType type, QString str) : ElementTreeItem(type, str) { this->data = d; }
: ElementTreeItem(type, str)
{
this->data = d;
}
virtual ~BelTreeItem(){}; virtual ~BelTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
@ -68,11 +61,7 @@ class BelTreeItem : public ElementTreeItem
class WireTreeItem : public ElementTreeItem class WireTreeItem : public ElementTreeItem
{ {
public: public:
WireTreeItem(IdString d, ElementType type, QString str) WireTreeItem(IdString d, ElementType type, QString str) : ElementTreeItem(type, str) { this->data = d; }
: ElementTreeItem(type, str)
{
this->data = d;
}
virtual ~WireTreeItem(){}; virtual ~WireTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
@ -84,11 +73,7 @@ class WireTreeItem : public ElementTreeItem
class PipTreeItem : public ElementTreeItem class PipTreeItem : public ElementTreeItem
{ {
public: public:
PipTreeItem(IdString d, ElementType type, QString str) PipTreeItem(IdString d, ElementType type, QString str) : ElementTreeItem(type, str) { this->data = d; }
: ElementTreeItem(type, str)
{
this->data = d;
}
virtual ~PipTreeItem(){}; virtual ~PipTreeItem(){};
IdString getData() { return this->data; }; IdString getData() { return this->data; };
@ -97,8 +82,7 @@ class PipTreeItem : public ElementTreeItem
IdString data; IdString data;
}; };
DesignWidget::DesignWidget(Context *_ctx, QWidget *parent) DesignWidget::DesignWidget(Context *_ctx, QWidget *parent) : QWidget(parent), ctx(_ctx)
: QWidget(parent), ctx(_ctx)
{ {
treeWidget = new QTreeWidget(); treeWidget = new QTreeWidget();
@ -115,8 +99,7 @@ DesignWidget::DesignWidget(Context *_ctx, QWidget *parent)
QList<QTreeWidgetItem *> bel_items; QList<QTreeWidgetItem *> bel_items;
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
auto name = ctx->getBelName(bel); auto name = ctx->getBelName(bel);
bel_items.append(new BelTreeItem(name, ElementType::BEL, bel_items.append(new BelTreeItem(name, ElementType::BEL, QString(name.c_str(ctx))));
QString(name.c_str(ctx))));
} }
bel_root->addChildren(bel_items); bel_root->addChildren(bel_items);
@ -127,8 +110,7 @@ DesignWidget::DesignWidget(Context *_ctx, QWidget *parent)
treeWidget->insertTopLevelItem(0, wire_root); treeWidget->insertTopLevelItem(0, wire_root);
for (auto wire : ctx->getWires()) { for (auto wire : ctx->getWires()) {
auto name = ctx->getWireName(wire); auto name = ctx->getWireName(wire);
wire_items.append(new WireTreeItem(name, ElementType::WIRE, wire_items.append(new WireTreeItem(name, ElementType::WIRE, QString(name.c_str(ctx))));
QString(name.c_str(ctx))));
} }
wire_root->addChildren(wire_items); wire_root->addChildren(wire_items);
@ -139,8 +121,7 @@ DesignWidget::DesignWidget(Context *_ctx, QWidget *parent)
treeWidget->insertTopLevelItem(0, pip_root); treeWidget->insertTopLevelItem(0, pip_root);
for (auto pip : ctx->getPips()) { for (auto pip : ctx->getPips()) {
auto name = ctx->getPipName(pip); auto name = ctx->getPipName(pip);
pip_items.append(new PipTreeItem(name, ElementType::PIP, pip_items.append(new PipTreeItem(name, ElementType::PIP, QString(name.c_str(ctx))));
QString(name.c_str(ctx))));
} }
pip_root->addChildren(pip_items); pip_root->addChildren(pip_items);
@ -165,11 +146,9 @@ DesignWidget::DesignWidget(Context *_ctx, QWidget *parent)
setLayout(mainLayout); setLayout(mainLayout);
// Connection // Connection
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &DesignWidget::prepareMenu);
&DesignWidget::prepareMenu);
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), SLOT(onItemClicked(QTreeWidgetItem *, int)));
SLOT(onItemClicked(QTreeWidgetItem *, int)));
} }
DesignWidget::~DesignWidget() DesignWidget::~DesignWidget()
@ -188,8 +167,7 @@ void DesignWidget::addProperty(QtVariantProperty *property, const QString &id)
void DesignWidget::clearProperties() void DesignWidget::clearProperties()
{ {
QMap<QtProperty *, QString>::ConstIterator itProp = QMap<QtProperty *, QString>::ConstIterator itProp = propertyToId.constBegin();
propertyToId.constBegin();
while (itProp != propertyToId.constEnd()) { while (itProp != propertyToId.constEnd()) {
delete itProp.key(); delete itProp.key();
itProp++; itProp++;
@ -210,23 +188,20 @@ void DesignWidget::onItemClicked(QTreeWidgetItem *item, int pos)
if (type == ElementType::BEL) { if (type == ElementType::BEL) {
IdString c = static_cast<BelTreeItem *>(item)->getData(); IdString c = static_cast<BelTreeItem *>(item)->getData();
QtVariantProperty *topItem = QtVariantProperty *topItem = variantManager->addProperty(QVariant::String, QString("Name"));
variantManager->addProperty(QVariant::String, QString("Name"));
topItem->setValue(QString(c.c_str(ctx))); topItem->setValue(QString(c.c_str(ctx)));
addProperty(topItem, QString("Name")); addProperty(topItem, QString("Name"));
} else if (type == ElementType::WIRE) { } else if (type == ElementType::WIRE) {
IdString c = static_cast<WireTreeItem *>(item)->getData(); IdString c = static_cast<WireTreeItem *>(item)->getData();
QtVariantProperty *topItem = QtVariantProperty *topItem = variantManager->addProperty(QVariant::String, QString("Name"));
variantManager->addProperty(QVariant::String, QString("Name"));
topItem->setValue(QString(c.c_str(ctx))); topItem->setValue(QString(c.c_str(ctx)));
addProperty(topItem, QString("Name")); addProperty(topItem, QString("Name"));
} else if (type == ElementType::PIP) { } else if (type == ElementType::PIP) {
IdString c = static_cast<PipTreeItem *>(item)->getData(); IdString c = static_cast<PipTreeItem *>(item)->getData();
QtVariantProperty *topItem = QtVariantProperty *topItem = variantManager->addProperty(QVariant::String, QString("Name"));
variantManager->addProperty(QVariant::String, QString("Name"));
topItem->setValue(QString(c.c_str(ctx))); topItem->setValue(QString(c.c_str(ctx)));
addProperty(topItem, QString("Name")); addProperty(topItem, QString("Name"));
} }
@ -250,9 +225,6 @@ void DesignWidget::prepareMenu(const QPoint &pos)
menu.exec(tree->mapToGlobal(pos)); menu.exec(tree->mapToGlobal(pos));
} }
void DesignWidget::selectObject() void DesignWidget::selectObject() { Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n"); }
{
Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n");
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -23,8 +23,7 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
MainWindow::MainWindow(Context *_ctx, QWidget *parent) MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent)
: BaseMainWindow(_ctx, parent)
{ {
initMainResource(); initMainResource();

View File

@ -31,8 +31,8 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
void PolyLine::buildPoint(LineShaderData *building, const QVector2D *prev, void PolyLine::buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur,
const QVector2D *cur, const QVector2D *next) const const QVector2D *next) const
{ {
// buildPoint emits two vertices per line point, along with normals to move // buildPoint emits two vertices per line point, along with normals to move
// them the right directio when rendering and miter to compensate for // them the right directio when rendering and miter to compensate for
@ -164,13 +164,10 @@ void PolyLine::build(LineShaderData &target) const
bool LineShader::compile(void) bool LineShader::compile(void)
{ {
program_ = new QOpenGLShaderProgram(parent_); program_ = new QOpenGLShaderProgram(parent_);
program_->addShaderFromSourceCode(QOpenGLShader::Vertex, program_->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource_);
vertexShaderSource_); program_->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource_);
program_->addShaderFromSourceCode(QOpenGLShader::Fragment,
fragmentShaderSource_);
if (!program_->link()) { if (!program_->link()) {
printf("could not link program: %s\n", printf("could not link program: %s\n", program_->log().toStdString().c_str());
program_->log().toStdString().c_str());
return false; return false;
} }
@ -205,44 +202,35 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection)
program_->bind(); program_->bind();
buffers_.position.bind(); buffers_.position.bind();
buffers_.position.allocate(&line.vertices[0], buffers_.position.allocate(&line.vertices[0], sizeof(Vertex2DPOD) * line.vertices.size());
sizeof(Vertex2DPOD) * line.vertices.size());
buffers_.normal.bind(); buffers_.normal.bind();
buffers_.normal.allocate(&line.normals[0], buffers_.normal.allocate(&line.normals[0], sizeof(Vertex2DPOD) * line.normals.size());
sizeof(Vertex2DPOD) * line.normals.size());
buffers_.miter.bind(); buffers_.miter.bind();
buffers_.miter.allocate(&line.miters[0], buffers_.miter.allocate(&line.miters[0], sizeof(GLfloat) * line.miters.size());
sizeof(GLfloat) * line.miters.size());
buffers_.index.bind(); buffers_.index.bind();
buffers_.index.allocate(&line.indices[0], buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size());
sizeof(GLuint) * line.indices.size());
program_->setUniformValue(uniforms_.projection, projection); program_->setUniformValue(uniforms_.projection, projection);
program_->setUniformValue(uniforms_.thickness, line.thickness); program_->setUniformValue(uniforms_.thickness, line.thickness);
program_->setUniformValue(uniforms_.color, line.color.r, line.color.g, program_->setUniformValue(uniforms_.color, line.color.r, line.color.g, line.color.b, line.color.a);
line.color.b, line.color.a);
buffers_.position.bind(); buffers_.position.bind();
program_->enableAttributeArray("position"); program_->enableAttributeArray("position");
gl->glVertexAttribPointer(attributes_.position, 2, GL_FLOAT, GL_FALSE, 0, gl->glVertexAttribPointer(attributes_.position, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
(void *)0);
buffers_.normal.bind(); buffers_.normal.bind();
program_->enableAttributeArray("normal"); program_->enableAttributeArray("normal");
gl->glVertexAttribPointer(attributes_.normal, 2, GL_FLOAT, GL_FALSE, 0, gl->glVertexAttribPointer(attributes_.normal, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
(void *)0);
buffers_.miter.bind(); buffers_.miter.bind();
program_->enableAttributeArray("miter"); program_->enableAttributeArray("miter");
gl->glVertexAttribPointer(attributes_.miter, 1, GL_FLOAT, GL_FALSE, 0, gl->glVertexAttribPointer(attributes_.miter, 1, GL_FLOAT, GL_FALSE, 0, (void *)0);
(void *)0);
buffers_.index.bind(); buffers_.index.bind();
gl->glDrawElements(GL_TRIANGLES, line.indices.size(), GL_UNSIGNED_INT, gl->glDrawElements(GL_TRIANGLES, line.indices.size(), GL_UNSIGNED_INT, (void *)0);
(void *)0);
program_->disableAttributeArray("miter"); program_->disableAttributeArray("miter");
program_->disableAttributeArray("normal"); program_->disableAttributeArray("normal");
@ -253,8 +241,7 @@ void LineShader::draw(const LineShaderData &line, const QMatrix4x4 &projection)
} }
FPGAViewWidget::FPGAViewWidget(QWidget *parent) FPGAViewWidget::FPGAViewWidget(QWidget *parent)
: QOpenGLWidget(parent), moveX_(0), moveY_(0), zoom_(10.0f), : QOpenGLWidget(parent), moveX_(0), moveY_(0), zoom_(10.0f), lineShader_(this)
lineShader_(this)
{ {
ctx_ = qobject_cast<BaseMainWindow *>(getMainWindow())->getContext(); ctx_ = qobject_cast<BaseMainWindow *>(getMainWindow())->getContext();
auto fmt = format(); auto fmt = format();
@ -263,8 +250,7 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent)
setFormat(fmt); setFormat(fmt);
fmt = format(); fmt = format();
printf("FPGAViewWidget running on OpenGL %d.%d\n", fmt.majorVersion(), printf("FPGAViewWidget running on OpenGL %d.%d\n", fmt.majorVersion(), fmt.minorVersion());
fmt.minorVersion());
if (fmt.majorVersion() < 3) { if (fmt.majorVersion() < 3) {
printf("Could not get OpenGL 3.0 context. Aborting.\n"); printf("Could not get OpenGL 3.0 context. Aborting.\n");
log_abort(); log_abort();
@ -344,8 +330,7 @@ void FPGAViewWidget::drawElement(LineShaderData &out, const GraphicElement &el)
} }
if (el.type == GraphicElement::G_LINE) { if (el.type == GraphicElement::G_LINE) {
PolyLine(offset + scale * el.x1, offset + scale * el.y1, PolyLine(offset + scale * el.x1, offset + scale * el.y1, offset + scale * el.x2, offset + scale * el.y2)
offset + scale * el.x2, offset + scale * el.y2)
.build(out); .build(out);
} }
} }

View File

@ -51,15 +51,8 @@ struct ColorPOD
GLfloat b; GLfloat b;
GLfloat a; GLfloat a;
ColorPOD(GLfloat R, GLfloat G, GLfloat B, GLfloat A) ColorPOD(GLfloat R, GLfloat G, GLfloat B, GLfloat A) : r(R), g(G), b(B), a(A) {}
: r(R), g(G), b(B), a(A) ColorPOD(const QColor &color) : r(color.redF()), g(color.greenF()), b(color.blueF()), a(color.alphaF()) {}
{
}
ColorPOD(const QColor &color)
: r(color.redF()), g(color.greenF()), b(color.blueF()),
a(color.alphaF())
{
}
} __attribute__((packed)); } __attribute__((packed));
// LineShaderData is a built set of vertices that can be rendered by the // LineShaderData is a built set of vertices that can be rendered by the
@ -75,10 +68,7 @@ struct LineShaderData
GLfloat thickness; GLfloat thickness;
ColorPOD color; ColorPOD color;
LineShaderData(GLfloat Thickness, QColor Color) LineShaderData(GLfloat Thickness, QColor Color) : thickness(Thickness), color(Color) {}
: thickness(Thickness), color(Color)
{
}
}; };
// PolyLine is a set of segments defined by points, that can be built to a // PolyLine is a set of segments defined by points, that can be built to a
@ -89,8 +79,7 @@ class PolyLine
std::vector<QVector2D> points_; std::vector<QVector2D> points_;
bool closed_; bool closed_;
void buildPoint(LineShaderData *building, const QVector2D *prev, void buildPoint(LineShaderData *building, const QVector2D *prev, const QVector2D *cur, const QVector2D *next) const;
const QVector2D *cur, const QVector2D *next) const;
public: public:
// Create an empty PolyLine. // Create an empty PolyLine.
@ -212,11 +201,10 @@ class LineShader
" gl_Position = projection * vec4(p, 0.0, 1.0);\n" " gl_Position = projection * vec4(p, 0.0, 1.0);\n"
"}\n"; "}\n";
static constexpr const char *fragmentShaderSource_ = static constexpr const char *fragmentShaderSource_ = "uniform lowp vec4 color;\n"
"uniform lowp vec4 color;\n" "void main() {\n"
"void main() {\n" " gl_FragColor = color;\n"
" gl_FragColor = color;\n" "}\n";
"}\n";
// Must be called on initialization. // Must be called on initialization.
bool compile(void); bool compile(void);

View File

@ -21,6 +21,8 @@
#include <QAction> #include <QAction>
#include <QFileDialog> #include <QFileDialog>
#include <QIcon> #include <QIcon>
#include <QInputDialog>
#include <QLineEdit>
#include "bitstream.h" #include "bitstream.h"
#include "design_utils.h" #include "design_utils.h"
#include "jsonparse.h" #include "jsonparse.h"
@ -34,8 +36,7 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
MainWindow::MainWindow(Context *_ctx, QWidget *parent) MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent), timing_driven(false)
: BaseMainWindow(_ctx, parent)
{ {
initMainResource(); initMainResource();
@ -45,18 +46,19 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent)
task = new TaskManager(_ctx); task = new TaskManager(_ctx);
connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string))); connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string)));
connect(task, SIGNAL(loadfile_finished(bool)), this, connect(task, SIGNAL(loadfile_finished(bool)), this, SLOT(loadfile_finished(bool)));
SLOT(loadfile_finished(bool)));
connect(task, SIGNAL(pack_finished(bool)), this, SLOT(pack_finished(bool))); connect(task, SIGNAL(pack_finished(bool)), this, SLOT(pack_finished(bool)));
connect(task, SIGNAL(place_finished(bool)), this, connect(task, SIGNAL(budget_finish(bool)), this, SLOT(budget_finish(bool)));
SLOT(place_finished(bool))); connect(task, SIGNAL(place_finished(bool)), this, SLOT(place_finished(bool)));
connect(task, SIGNAL(route_finished(bool)), this, connect(task, SIGNAL(route_finished(bool)), this, SLOT(route_finished(bool)));
SLOT(route_finished(bool)));
connect(task, SIGNAL(taskCanceled()), this, SLOT(taskCanceled())); connect(task, SIGNAL(taskCanceled()), this, SLOT(taskCanceled()));
connect(task, SIGNAL(taskStarted()), this, SLOT(taskStarted())); connect(task, SIGNAL(taskStarted()), this, SLOT(taskStarted()));
connect(task, SIGNAL(taskPaused()), this, SLOT(taskPaused())); connect(task, SIGNAL(taskPaused()), this, SLOT(taskPaused()));
connect(this, SIGNAL(budget(double)), task, SIGNAL(budget(double)));
connect(this, SIGNAL(place(bool)), task, SIGNAL(place(bool)));
createMenu(); createMenu();
} }
@ -75,12 +77,20 @@ void MainWindow::createMenu()
connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack())); connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack()));
actionPack->setEnabled(false); actionPack->setEnabled(false);
actionAssignBudget = new QAction("Assign Budget", this);
QIcon iconAssignBudget;
iconAssignBudget.addFile(QStringLiteral(":/icons/resources/time_add.png"));
actionAssignBudget->setIcon(iconAssignBudget);
actionAssignBudget->setStatusTip("Assign time budget for current design");
connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget()));
actionAssignBudget->setEnabled(false);
actionPlace = new QAction("Place", this); actionPlace = new QAction("Place", this);
QIcon iconPlace; QIcon iconPlace;
iconPlace.addFile(QStringLiteral(":/icons/resources/place.png")); iconPlace.addFile(QStringLiteral(":/icons/resources/place.png"));
actionPlace->setIcon(iconPlace); actionPlace->setIcon(iconPlace);
actionPlace->setStatusTip("Place current design"); actionPlace->setStatusTip("Place current design");
connect(actionPlace, SIGNAL(triggered()), task, SIGNAL(place())); connect(actionPlace, SIGNAL(triggered()), this, SLOT(place()));
actionPlace->setEnabled(false); actionPlace->setEnabled(false);
actionRoute = new QAction("Route", this); actionRoute = new QAction("Route", this);
@ -95,10 +105,12 @@ void MainWindow::createMenu()
addToolBar(Qt::TopToolBarArea, taskFPGABar); addToolBar(Qt::TopToolBarArea, taskFPGABar);
taskFPGABar->addAction(actionPack); taskFPGABar->addAction(actionPack);
taskFPGABar->addAction(actionAssignBudget);
taskFPGABar->addAction(actionPlace); taskFPGABar->addAction(actionPlace);
taskFPGABar->addAction(actionRoute); taskFPGABar->addAction(actionRoute);
menu_Design->addAction(actionPack); menu_Design->addAction(actionPack);
menu_Design->addAction(actionAssignBudget);
menu_Design->addAction(actionPlace); menu_Design->addAction(actionPlace);
menu_Design->addAction(actionRoute); menu_Design->addAction(actionRoute);
@ -136,13 +148,13 @@ void MainWindow::createMenu()
void MainWindow::open() void MainWindow::open()
{ {
QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), QString("*.json"));
QString("*.json"));
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
tabWidget->setCurrentWidget(info); tabWidget->setCurrentWidget(info);
std::string fn = fileName.toStdString(); std::string fn = fileName.toStdString();
disableActions(); disableActions();
timing_driven = false;
Q_EMIT task->loadfile(fn); Q_EMIT task->loadfile(fn);
} }
} }
@ -152,6 +164,7 @@ bool MainWindow::save() { return false; }
void MainWindow::disableActions() void MainWindow::disableActions()
{ {
actionPack->setEnabled(false); actionPack->setEnabled(false);
actionAssignBudget->setEnabled(false);
actionPlace->setEnabled(false); actionPlace->setEnabled(false);
actionRoute->setEnabled(false); actionRoute->setEnabled(false);
@ -176,10 +189,23 @@ void MainWindow::pack_finished(bool status)
if (status) { if (status) {
log("Packing design successful.\n"); log("Packing design successful.\n");
actionPlace->setEnabled(true); actionPlace->setEnabled(true);
actionAssignBudget->setEnabled(true);
} else { } else {
log("Packing design failed.\n"); log("Packing design failed.\n");
} }
} }
void MainWindow::budget_finish(bool status)
{
disableActions();
if (status) {
log("Assigning timing budget successful.\n");
actionPlace->setEnabled(true);
} else {
log("Assigning timing budget failed.\n");
}
}
void MainWindow::place_finished(bool status) void MainWindow::place_finished(bool status)
{ {
disableActions(); disableActions();
@ -219,4 +245,17 @@ void MainWindow::taskPaused()
actionStop->setEnabled(true); actionStop->setEnabled(true);
} }
void MainWindow::budget()
{
bool ok;
double freq = QInputDialog::getDouble(this, "Assign timing budget", "Frequency [MHz]:", 50, 0, 250, 2, &ok);
if (ok) {
freq *= 1e6;
timing_driven = true;
Q_EMIT budget(freq);
}
}
void MainWindow::place() { Q_EMIT place(timing_driven); }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -36,11 +36,20 @@ class MainWindow : public BaseMainWindow
public: public:
void createMenu(); void createMenu();
Q_SIGNALS:
void budget(double freq);
void place(bool timing_driven);
protected Q_SLOTS: protected Q_SLOTS:
virtual void open(); virtual void open();
virtual bool save(); virtual bool save();
void budget();
void place();
void loadfile_finished(bool status); void loadfile_finished(bool status);
void pack_finished(bool status); void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status); void place_finished(bool status);
void route_finished(bool status); void route_finished(bool status);
@ -53,11 +62,14 @@ class MainWindow : public BaseMainWindow
TaskManager *task; TaskManager *task;
QAction *actionPack; QAction *actionPack;
QAction *actionAssignBudget;
QAction *actionPlace; QAction *actionPlace;
QAction *actionRoute; QAction *actionRoute;
QAction *actionPlay; QAction *actionPlay;
QAction *actionPause; QAction *actionPause;
QAction *actionStop; QAction *actionStop;
bool timing_driven;
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -6,5 +6,6 @@
<file>resources/pack.png</file> <file>resources/pack.png</file>
<file>resources/place.png</file> <file>resources/place.png</file>
<file>resources/route.png</file> <file>resources/route.png</file>
<file>resources/time_add.png</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

View File

@ -72,20 +72,30 @@ void Worker::pack()
{ {
Q_EMIT taskStarted(); Q_EMIT taskStarted();
try { try {
Q_EMIT pack_finished(pack_design(ctx)); bool res = pack_design(ctx);
print_utilisation(ctx);
Q_EMIT pack_finished(res);
} catch (WorkerInterruptionRequested) { } catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled(); Q_EMIT taskCanceled();
} }
} }
void Worker::place() void Worker::budget(double freq)
{ {
Q_EMIT taskStarted(); Q_EMIT taskStarted();
try { try {
double freq = 50e6;
assign_budget(ctx, freq); assign_budget(ctx, freq);
print_utilisation(ctx); Q_EMIT budget_finish(true);
Q_EMIT place_finished(place_design_sa(ctx)); } catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled();
}
}
void Worker::place(bool timing_driven)
{
Q_EMIT taskStarted();
try {
Q_EMIT place_finished(place_design_sa(ctx, timing_driven));
} catch (WorkerInterruptionRequested) { } catch (WorkerInterruptionRequested) {
Q_EMIT taskCanceled(); Q_EMIT taskCanceled();
} }
@ -110,17 +120,16 @@ TaskManager::TaskManager(Context *ctx) : toTerminate(false), toPause(false)
connect(this, &TaskManager::loadfile, worker, &Worker::loadfile); connect(this, &TaskManager::loadfile, worker, &Worker::loadfile);
connect(this, &TaskManager::pack, worker, &Worker::pack); connect(this, &TaskManager::pack, worker, &Worker::pack);
connect(this, &TaskManager::budget, worker, &Worker::budget);
connect(this, &TaskManager::place, worker, &Worker::place); connect(this, &TaskManager::place, worker, &Worker::place);
connect(this, &TaskManager::route, worker, &Worker::route); connect(this, &TaskManager::route, worker, &Worker::route);
connect(worker, &Worker::log, this, &TaskManager::info); connect(worker, &Worker::log, this, &TaskManager::info);
connect(worker, &Worker::loadfile_finished, this, connect(worker, &Worker::loadfile_finished, this, &TaskManager::loadfile_finished);
&TaskManager::loadfile_finished);
connect(worker, &Worker::pack_finished, this, &TaskManager::pack_finished); connect(worker, &Worker::pack_finished, this, &TaskManager::pack_finished);
connect(worker, &Worker::place_finished, this, connect(worker, &Worker::budget_finish, this, &TaskManager::budget_finish);
&TaskManager::place_finished); connect(worker, &Worker::place_finished, this, &TaskManager::place_finished);
connect(worker, &Worker::route_finished, this, connect(worker, &Worker::route_finished, this, &TaskManager::route_finished);
&TaskManager::route_finished);
connect(worker, &Worker::taskCanceled, this, &TaskManager::taskCanceled); connect(worker, &Worker::taskCanceled, this, &TaskManager::taskCanceled);
connect(worker, &Worker::taskStarted, this, &TaskManager::taskStarted); connect(worker, &Worker::taskStarted, this, &TaskManager::taskStarted);

View File

@ -36,12 +36,14 @@ class Worker : public QObject
public Q_SLOTS: public Q_SLOTS:
void loadfile(const std::string &); void loadfile(const std::string &);
void pack(); void pack();
void place(); void budget(double freq);
void place(bool timing_driven);
void route(); void route();
Q_SIGNALS: Q_SIGNALS:
void log(const std::string &text); void log(const std::string &text);
void loadfile_finished(bool status); void loadfile_finished(bool status);
void pack_finished(bool status); void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status); void place_finished(bool status);
void route_finished(bool status); void route_finished(bool status);
void taskCanceled(); void taskCanceled();
@ -72,13 +74,15 @@ class TaskManager : public QObject
void terminate(); void terminate();
void loadfile(const std::string &); void loadfile(const std::string &);
void pack(); void pack();
void place(); void budget(double freq);
void place(bool timing_driven);
void route(); void route();
// redirected signals // redirected signals
void log(const std::string &text); void log(const std::string &text);
void loadfile_finished(bool status); void loadfile_finished(bool status);
void pack_finished(bool status); void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status); void place_finished(bool status);
void route_finished(bool status); void route_finished(bool status);
void taskCanceled(); void taskCanceled();

View File

@ -37,8 +37,7 @@ InfoTab::InfoTab(QWidget *parent) : QWidget(parent)
contextMenu = plainTextEdit->createStandardContextMenu(); contextMenu = plainTextEdit->createStandardContextMenu();
contextMenu->addSeparator(); contextMenu->addSeparator();
contextMenu->addAction(clearAction); contextMenu->addAction(clearAction);
connect(plainTextEdit, SIGNAL(customContextMenuRequested(const QPoint)), connect(plainTextEdit, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
this, SLOT(showContextMenu(const QPoint)));
QGridLayout *mainLayout = new QGridLayout(); QGridLayout *mainLayout = new QGridLayout();
mainLayout->addWidget(plainTextEdit); mainLayout->addWidget(plainTextEdit);
@ -52,10 +51,7 @@ void InfoTab::info(std::string str)
plainTextEdit->moveCursor(QTextCursor::End); plainTextEdit->moveCursor(QTextCursor::End);
} }
void InfoTab::showContextMenu(const QPoint &pt) void InfoTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
{
contextMenu->exec(mapToGlobal(pt));
}
void InfoTab::clearBuffer() { plainTextEdit->clear(); } void InfoTab::clearBuffer() { plainTextEdit->clear(); }

View File

@ -33,8 +33,7 @@ LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0)
contextMenu->addAction(clearAction); contextMenu->addAction(clearAction);
connect(this, SIGNAL(returnPressed()), SLOT(textInserted())); connect(this, SIGNAL(returnPressed()), SLOT(textInserted()));
connect(this, SIGNAL(customContextMenuRequested(const QPoint)), this, connect(this, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
SLOT(showContextMenu(const QPoint)));
} }
void LineEditor::keyPressEvent(QKeyEvent *ev) void LineEditor::keyPressEvent(QKeyEvent *ev)
@ -74,10 +73,7 @@ void LineEditor::textInserted()
Q_EMIT textLineInserted(lines.back()); Q_EMIT textLineInserted(lines.back());
} }
void LineEditor::showContextMenu(const QPoint &pt) void LineEditor::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
{
contextMenu->exec(mapToGlobal(pt));
}
void LineEditor::clearHistory() void LineEditor::clearHistory()
{ {

View File

@ -16,7 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* *
*/ */
#ifndef NO_PYTHON #ifndef NO_PYTHON
#include "pythontab.h" #include "pythontab.h"
#include <QGridLayout> #include <QGridLayout>
@ -44,8 +44,7 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent)
contextMenu = plainTextEdit->createStandardContextMenu(); contextMenu = plainTextEdit->createStandardContextMenu();
contextMenu->addSeparator(); contextMenu->addSeparator();
contextMenu->addAction(clearAction); contextMenu->addAction(clearAction);
connect(plainTextEdit, SIGNAL(customContextMenuRequested(const QPoint)), connect(plainTextEdit, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint)));
this, SLOT(showContextMenu(const QPoint)));
lineEdit = new LineEditor(); lineEdit = new LineEditor();
lineEdit->setMinimumHeight(30); lineEdit->setMinimumHeight(30);
@ -57,8 +56,7 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent)
mainLayout->addWidget(lineEdit, 1, 0); mainLayout->addWidget(lineEdit, 1, 0);
setLayout(mainLayout); setLayout(mainLayout);
connect(lineEdit, SIGNAL(textLineInserted(QString)), this, connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString)));
SLOT(editLineReturnPressed(QString)));
write = [this](std::string s) { write = [this](std::string s) {
plainTextEdit->moveCursor(QTextCursor::End); plainTextEdit->moveCursor(QTextCursor::End);
@ -88,9 +86,7 @@ int PythonTab::executePython(std::string &command)
if (m == NULL) if (m == NULL)
return -1; return -1;
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
v = PyRun_StringFlags(command.c_str(), v = PyRun_StringFlags(command.c_str(), (command.empty() ? Py_file_input : Py_single_input), d, d, NULL);
(command.empty() ? Py_file_input : Py_single_input),
d, d, NULL);
if (v == NULL) { if (v == NULL) {
PyObject *exception, *v, *tb; PyObject *exception, *v, *tb;
@ -111,8 +107,7 @@ int PythonTab::executePython(std::string &command)
PyErr_Clear(); PyErr_Clear();
PyObject *objectsRepresentation = PyObject_Str(v); PyObject *objectsRepresentation = PyObject_Str(v);
std::string errorStr = std::string errorStr = PyUnicode_AsUTF8(objectsRepresentation) + std::string("\n");
PyUnicode_AsUTF8(objectsRepresentation) + std::string("\n");
print(errorStr); print(errorStr);
Py_DECREF(objectsRepresentation); Py_DECREF(objectsRepresentation);
Py_XDECREF(exception); Py_XDECREF(exception);
@ -131,10 +126,7 @@ void PythonTab::editLineReturnPressed(QString text)
executePython(input); executePython(input);
} }
void PythonTab::showContextMenu(const QPoint &pt) void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
{
contextMenu->exec(mapToGlobal(pt));
}
void PythonTab::clearBuffer() { plainTextEdit->clear(); } void PythonTab::clearBuffer() { plainTextEdit->clear(); }

View File

@ -25,16 +25,13 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
PlaceValidityChecker::PlaceValidityChecker(Context *ctx) PlaceValidityChecker::PlaceValidityChecker(Context *ctx)
: ctx(ctx), id_icestorm_lc(ctx, "ICESTORM_LC"), id_sb_io(ctx, "SB_IO"), : ctx(ctx), id_icestorm_lc(ctx, "ICESTORM_LC"), id_sb_io(ctx, "SB_IO"), id_sb_gb(ctx, "SB_GB"),
id_sb_gb(ctx, "SB_GB"), id_cen(ctx, "CEN"), id_clk(ctx, "CLK"), id_cen(ctx, "CEN"), id_clk(ctx, "CLK"), id_sr(ctx, "SR"), id_i0(ctx, "I0"), id_i1(ctx, "I1"),
id_sr(ctx, "SR"), id_i0(ctx, "I0"), id_i1(ctx, "I1"), id_i2(ctx, "I2"), id_i3(ctx, "I3"), id_dff_en(ctx, "DFF_ENABLE"), id_neg_clk(ctx, "NEG_CLK")
id_i2(ctx, "I2"), id_i3(ctx, "I3"), id_dff_en(ctx, "DFF_ENABLE"),
id_neg_clk(ctx, "NEG_CLK")
{ {
} }
static const NetInfo *get_net_or_empty(const CellInfo *cell, static const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
const IdString port)
{ {
auto found = cell->ports.find(port); auto found = cell->ports.find(port);
if (found != cell->ports.end()) if (found != cell->ports.end())
@ -43,8 +40,7 @@ static const NetInfo *get_net_or_empty(const CellInfo *cell,
return nullptr; return nullptr;
}; };
bool PlaceValidityChecker::logicCellsCompatible( bool PlaceValidityChecker::logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells)
const Context *ctx, const std::vector<const CellInfo *> &cells)
{ {
bool dffs_exist = false, dffs_neg = false; bool dffs_exist = false, dffs_neg = false;
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
@ -80,10 +76,8 @@ bool PlaceValidityChecker::logicCellsCompatible(
} }
} }
const NetInfo *i0 = get_net_or_empty(cell, id_i0), const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1),
*i1 = get_net_or_empty(cell, id_i1), *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3);
*i2 = get_net_or_empty(cell, id_i2),
*i3 = get_net_or_empty(cell, id_i3);
if (i0 != nullptr) if (i0 != nullptr)
locals_count++; locals_count++;
if (i1 != nullptr) if (i1 != nullptr)
@ -140,15 +134,13 @@ bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel)
} else if (cell->type == id_sb_gb) { } else if (cell->type == id_sb_gb) {
bool is_reset = false, is_cen = false; bool is_reset = false, is_cen = false;
assert(cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net != nullptr); assert(cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net != nullptr);
for (auto user : for (auto user : cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net->users) {
cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net->users) {
if (is_reset_port(ctx, user)) if (is_reset_port(ctx, user))
is_reset = true; is_reset = true;
if (is_enable_port(ctx, user)) if (is_enable_port(ctx, user))
is_cen = true; is_cen = true;
} }
IdString glb_net = ctx->getWireName( IdString glb_net = ctx->getWireName(ctx->getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
ctx->getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
int glb_id = std::stoi(std::string("") + glb_net.str(ctx).back()); int glb_id = std::stoi(std::string("") + glb_net.str(ctx).back());
if (is_reset && is_cen) if (is_reset && is_cen)
return false; return false;

View File

@ -39,8 +39,7 @@ class PlaceValidityChecker
bool isBelLocationValid(BelId bel); bool isBelLocationValid(BelId bel);
private: private:
bool logicCellsCompatible(const Context *ctx, bool logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells);
const std::vector<const CellInfo *> &cells);
Context *ctx; Context *ctx;
IdString id_icestorm_lc, id_sb_io, id_sb_gb; IdString id_icestorm_lc, id_sb_io, id_sb_gb;
IdString id_cen, id_clk, id_sr; IdString id_cen, id_clk, id_sr;

View File

@ -28,8 +28,7 @@ inline TileType tile_at(const Context *ctx, int x, int y)
return ctx->chip_info->tile_grid[y * ctx->chip_info->width + x]; return ctx->chip_info->tile_grid[y * ctx->chip_info->width + x];
} }
const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const std::string &name)
const std::string &name)
{ {
for (int i = 0; i < tile.num_config_entries; i++) { for (int i = 0; i < tile.num_config_entries; i++) {
if (std::string(tile.entries[i].name.get()) == name) { if (std::string(tile.entries[i].name.get()) == name) {
@ -39,8 +38,7 @@ const ConfigEntryPOD &find_config(const TileInfoPOD &tile,
assert(false); assert(false);
} }
std::tuple<int8_t, int8_t, int8_t> get_ieren(const BitstreamInfoPOD &bi, std::tuple<int8_t, int8_t, int8_t> get_ieren(const BitstreamInfoPOD &bi, int8_t x, int8_t y, int8_t z)
int8_t x, int8_t y, int8_t z)
{ {
for (int i = 0; i < bi.num_ierens; i++) { for (int i = 0; i < bi.num_ierens; i++) {
auto ie = bi.ierens[i]; auto ie = bi.ierens[i];
@ -52,9 +50,8 @@ std::tuple<int8_t, int8_t, int8_t> get_ieren(const BitstreamInfoPOD &bi,
return std::make_tuple(-1, -1, -1); return std::make_tuple(-1, -1, -1);
}; };
void set_config(const TileInfoPOD &ti, void set_config(const TileInfoPOD &ti, std::vector<std::vector<int8_t>> &tile_cfg, const std::string &name, bool value,
std::vector<std::vector<int8_t>> &tile_cfg, int index = -1)
const std::string &name, bool value, int index = -1)
{ {
const ConfigEntryPOD &cfg = find_config(ti, name); const ConfigEntryPOD &cfg = find_config(ti, name);
if (index == -1) { if (index == -1) {
@ -68,8 +65,7 @@ void set_config(const TileInfoPOD &ti,
int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col);
cbit = value; cbit = value;
if (cbit && !value) if (cbit && !value)
log_error("clearing already set config bit %s[%d]", name.c_str(), log_error("clearing already set config bit %s[%d]", name.c_str(), index);
index);
} }
} }
@ -82,8 +78,7 @@ int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0)
return defval; return defval;
} }
std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std::string defval = "")
std::string defval = "")
{ {
auto found = cell->params.find(param); auto found = cell->params.find(param);
if (found != cell->params.end()) if (found != cell->params.end())
@ -136,12 +131,8 @@ void write_asc(const Context *ctx, std::ostream &out)
const PipInfoPOD &pi = ci.pip_data[pip.index]; const PipInfoPOD &pi = ci.pip_data[pip.index];
const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index];
for (int i = 0; i < swi.num_bits; i++) { for (int i = 0; i < swi.num_bits; i++) {
bool val = bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0;
(pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; int8_t &cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col);
int8_t &cbit = config.at(swi.y)
.at(swi.x)
.at(swi.cbits[i].row)
.at(swi.cbits[i].col);
if (bool(cbit) != 0) if (bool(cbit) != 0)
assert(false); assert(false);
cbit = val; cbit = val;
@ -152,24 +143,19 @@ void write_asc(const Context *ctx, std::ostream &out)
for (auto cell : ctx->cells) { for (auto cell : ctx->cells) {
BelId bel = cell.second->bel; BelId bel = cell.second->bel;
if (bel == BelId()) { if (bel == BelId()) {
std::cout << "Found unplaced cell " << cell.first.str(ctx) std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl;
<< " while generating bitstream!" << std::endl;
continue; continue;
} }
const BelInfoPOD &beli = ci.bel_data[bel.index]; const BelInfoPOD &beli = ci.bel_data[bel.index];
int x = beli.x, y = beli.y, z = beli.z; int x = beli.x, y = beli.y, z = beli.z;
if (cell.second->type == ctx->id("ICESTORM_LC")) { if (cell.second->type == ctx->id("ICESTORM_LC")) {
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
unsigned lut_init = unsigned lut_init = get_param_or_def(cell.second, ctx->id("LUT_INIT"));
get_param_or_def(cell.second, ctx->id("LUT_INIT"));
bool neg_clk = get_param_or_def(cell.second, ctx->id("NEG_CLK")); bool neg_clk = get_param_or_def(cell.second, ctx->id("NEG_CLK"));
bool dff_enable = bool dff_enable = get_param_or_def(cell.second, ctx->id("DFF_ENABLE"));
get_param_or_def(cell.second, ctx->id("DFF_ENABLE"));
bool async_sr = get_param_or_def(cell.second, ctx->id("ASYNC_SR")); bool async_sr = get_param_or_def(cell.second, ctx->id("ASYNC_SR"));
bool set_noreset = bool set_noreset = get_param_or_def(cell.second, ctx->id("SET_NORESET"));
get_param_or_def(cell.second, ctx->id("SET_NORESET")); bool carry_enable = get_param_or_def(cell.second, ctx->id("CARRY_ENABLE"));
bool carry_enable =
get_param_or_def(cell.second, ctx->id("CARRY_ENABLE"));
std::vector<bool> lc(20, false); std::vector<bool> lc(20, false);
// From arachne-pnr // From arachne-pnr
static std::vector<int> lut_perm = { static std::vector<int> lut_perm = {
@ -185,23 +171,17 @@ void write_asc(const Context *ctx, std::ostream &out)
lc.at(19) = async_sr; lc.at(19) = async_sr;
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), lc.at(i), i);
lc.at(i), i);
if (dff_enable) if (dff_enable)
set_config(ti, config.at(y).at(x), "NegClk", neg_clk); set_config(ti, config.at(y).at(x), "NegClk", neg_clk);
} else if (cell.second->type == ctx->id("SB_IO")) { } else if (cell.second->type == ctx->id("SB_IO")) {
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
unsigned pin_type = unsigned pin_type = get_param_or_def(cell.second, ctx->id("PIN_TYPE"));
get_param_or_def(cell.second, ctx->id("PIN_TYPE")); bool neg_trigger = get_param_or_def(cell.second, ctx->id("NEG_TRIGGER"));
bool neg_trigger =
get_param_or_def(cell.second, ctx->id("NEG_TRIGGER"));
bool pullup = get_param_or_def(cell.second, ctx->id("PULLUP")); bool pullup = get_param_or_def(cell.second, ctx->id("PULLUP"));
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
bool val = (pin_type >> i) & 0x01; bool val = (pin_type >> i) & 0x01;
set_config(ti, config.at(y).at(x), set_config(ti, config.at(y).at(x), "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i), val);
"IOB_" + std::to_string(z) + ".PINTYPE_" +
std::to_string(i),
val);
} }
auto ieren = get_ieren(bi, x, y, z); auto ieren = get_ieren(bi, x, y, z);
@ -210,33 +190,24 @@ void write_asc(const Context *ctx, std::ostream &out)
assert(iez != -1); assert(iez != -1);
bool input_en = false; bool input_en = false;
if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) ||
IdString()) || (ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) {
(ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] !=
IdString())) {
input_en = true; input_en = true;
} }
if (ctx->args.type == ArchArgs::LP1K || if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) {
ctx->args.type == ArchArgs::HX1K) { set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), !input_en);
set_config(ti, config.at(iey).at(iex), set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup);
"IoCtrl.IE_" + std::to_string(iez), !input_en);
set_config(ti, config.at(iey).at(iex),
"IoCtrl.REN_" + std::to_string(iez), !pullup);
} else { } else {
set_config(ti, config.at(iey).at(iex), set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), input_en);
"IoCtrl.IE_" + std::to_string(iez), input_en); set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup);
set_config(ti, config.at(iey).at(iex),
"IoCtrl.REN_" + std::to_string(iez), !pullup);
} }
if (ctx->args.type == ArchArgs::UP5K) { if (ctx->args.type == ArchArgs::UP5K) {
if (iez == 0) { if (iez == 0) {
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", !pullup);
!pullup);
} else if (iez == 1) { } else if (iez == 1) {
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", !pullup);
!pullup);
} }
} }
} else if (cell.second->type == ctx->id("SB_GB")) { } else if (cell.second->type == ctx->id("SB_GB")) {
@ -246,29 +217,21 @@ void write_asc(const Context *ctx, std::ostream &out)
int x = beli.x, y = beli.y; int x = beli.x, y = beli.y;
const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT]; const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT];
const TileInfoPOD &ti_ramb = bi.tiles_nonrouting[TILE_RAMB]; const TileInfoPOD &ti_ramb = bi.tiles_nonrouting[TILE_RAMB];
if (!(ctx->args.type == ArchArgs::LP1K || if (!(ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) {
ctx->args.type == ArchArgs::HX1K)) { set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp", true);
set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp",
true);
} }
bool negclk_r = get_param_or_def(cell.second, ctx->id("NEG_CLK_R")); bool negclk_r = get_param_or_def(cell.second, ctx->id("NEG_CLK_R"));
bool negclk_w = get_param_or_def(cell.second, ctx->id("NEG_CLK_W")); bool negclk_w = get_param_or_def(cell.second, ctx->id("NEG_CLK_W"));
int write_mode = int write_mode = get_param_or_def(cell.second, ctx->id("WRITE_MODE"));
get_param_or_def(cell.second, ctx->id("WRITE_MODE"));
int read_mode = get_param_or_def(cell.second, ctx->id("READ_MODE")); int read_mode = get_param_or_def(cell.second, ctx->id("READ_MODE"));
set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w); set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w);
set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r); set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_0", set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_0", write_mode & 0x1);
write_mode & 0x1); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1);
write_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", } else if (cell.second->type == ctx->id("SB_WARMBOOT") || cell.second->type == ctx->id("ICESTORM_LFOSC")) {
read_mode & 0x1);
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3",
read_mode & 0x2);
} else if (cell.second->type == ctx->id("SB_WARMBOOT") ||
cell.second->type == ctx->id("ICESTORM_LFOSC")) {
// No config needed // No config needed
} else { } else {
assert(false); assert(false);
@ -276,8 +239,7 @@ void write_asc(const Context *ctx, std::ostream &out)
} }
// Set config bits in unused IO and RAM // Set config bits in unused IO and RAM
for (auto bel : ctx->getBels()) { for (auto bel : ctx->getBels()) {
if (ctx->bel_to_cell[bel.index] == IdString() && if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) {
ctx->getBelType(bel) == TYPE_SB_IO) {
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
const BelInfoPOD &beli = ci.bel_data[bel.index]; const BelInfoPOD &beli = ci.bel_data[bel.index];
int x = beli.x, y = beli.y, z = beli.z; int x = beli.x, y = beli.y, z = beli.z;
@ -285,21 +247,16 @@ void write_asc(const Context *ctx, std::ostream &out)
int iex, iey, iez; int iex, iey, iez;
std::tie(iex, iey, iez) = ieren; std::tie(iex, iey, iez) = ieren;
if (iez != -1) { if (iez != -1) {
if (ctx->args.type == ArchArgs::LP1K || if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) {
ctx->args.type == ArchArgs::HX1K) { set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true);
set_config(ti, config.at(iey).at(iex), set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false);
"IoCtrl.IE_" + std::to_string(iez), true);
set_config(ti, config.at(iey).at(iex),
"IoCtrl.REN_" + std::to_string(iez), false);
} }
} }
} else if (ctx->bel_to_cell[bel.index] == IdString() && } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
const BelInfoPOD &beli = ci.bel_data[bel.index]; const BelInfoPOD &beli = ci.bel_data[bel.index];
int x = beli.x, y = beli.y; int x = beli.x, y = beli.y;
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB];
if ((ctx->args.type == ArchArgs::LP1K || if ((ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) {
ctx->args.type == ArchArgs::HX1K)) {
set_config(ti, config.at(y).at(x), "RamConfig.PowerUp", true); set_config(ti, config.at(y).at(x), "RamConfig.PowerUp", true);
} }
} }
@ -313,67 +270,48 @@ void write_asc(const Context *ctx, std::ostream &out)
// set all ColBufCtrl bits (FIXME) // set all ColBufCtrl bits (FIXME)
bool setColBufCtrl = true; bool setColBufCtrl = true;
if (ctx->args.type == ArchArgs::LP1K || if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) {
ctx->args.type == ArchArgs::HX1K) {
if (tile == TILE_RAMB || tile == TILE_RAMT) { if (tile == TILE_RAMB || tile == TILE_RAMT) {
setColBufCtrl = (y == 3 || y == 5 || y == 11 || y == 13); setColBufCtrl = (y == 3 || y == 5 || y == 11 || y == 13);
} else { } else {
setColBufCtrl = (y == 4 || y == 5 || y == 12 || y == 13); setColBufCtrl = (y == 4 || y == 5 || y == 12 || y == 13);
} }
} else if (ctx->args.type == ArchArgs::LP8K || } else if (ctx->args.type == ArchArgs::LP8K || ctx->args.type == ArchArgs::HX8K) {
ctx->args.type == ArchArgs::HX8K) {
setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25); setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25);
} else if (ctx->args.type == ArchArgs::UP5K) { } else if (ctx->args.type == ArchArgs::UP5K) {
setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || y == 26 || y == 27);
y == 26 || y == 27);
} }
if (setColBufCtrl) { if (setColBufCtrl) {
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0", set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0", true);
true); set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_1", true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_1", set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_2", true);
true); set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_3", true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_2", set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_4", true);
true); set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_5", true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_3", set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_6", true);
true); set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_7", true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_4",
true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_5",
true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_6",
true);
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_7",
true);
} }
// Weird UltraPlus bits // Weird UltraPlus bits
if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 || if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 || tile == TILE_DSP3 ||
tile == TILE_DSP3 || tile == TILE_IPCON) { tile == TILE_IPCON) {
if (ctx->args.type == ArchArgs::UP5K && x == 25 && y == 14) { if (ctx->args.type == ArchArgs::UP5K && x == 25 && y == 14) {
// Mystery bits not set in this one tile // Mystery bits not set in this one tile
} else { } else {
for (int lc_idx = 0; lc_idx < 8; lc_idx++) { for (int lc_idx = 0; lc_idx < 8; lc_idx++) {
static const std::vector<int> ip_dsp_lut_perm = { static const std::vector<int> ip_dsp_lut_perm = {
4, 14, 15, 5, 6, 16, 17, 7, 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0,
3, 13, 12, 2, 1, 11, 10, 0,
}; };
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
set_config(ti, config.at(y).at(x), set_config(ti, config.at(y).at(x), "LC_" + std::to_string(lc_idx), ((i % 8) >= 4),
"LC_" + std::to_string(lc_idx), ip_dsp_lut_perm.at(i));
((i % 8) >= 4), ip_dsp_lut_perm.at(i));
if (tile == TILE_IPCON) if (tile == TILE_IPCON)
set_config(ti, config.at(y).at(x), set_config(ti, config.at(y).at(x),
"Cascade.IPCON_LC0" + "Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true);
std::to_string(lc_idx) +
"_inmux02_5",
true);
else else
set_config(ti, config.at(y).at(x), set_config(ti, config.at(y).at(x),
"Cascade.MULT" + "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" +
std::to_string( std::to_string(lc_idx) + "_inmux02_5",
int(tile - TILE_DSP0)) +
"_LC0" + std::to_string(lc_idx) +
"_inmux02_5",
true); true);
} }
} }
@ -441,17 +379,15 @@ void write_asc(const Context *ctx, std::ostream &out)
out << ".ram_data " << x << " " << y << std::endl; out << ".ram_data " << x << " " << y << std::endl;
for (int w = 0; w < 16; w++) { for (int w = 0; w < 16; w++) {
std::vector<bool> bits(256); std::vector<bool> bits(256);
std::string init = get_param_str_or_def( std::string init =
cell.second, get_param_str_or_def(cell.second, ctx->id(std::string("INIT_") + get_hexdigit(w)));
ctx->id(std::string("INIT_") + get_hexdigit(w)));
assert(init != ""); assert(init != "");
for (size_t i = 0; i < init.size(); i++) { for (size_t i = 0; i < init.size(); i++) {
bool val = (init.at((init.size() - 1) - i) == '1'); bool val = (init.at((init.size() - 1) - i) == '1');
bits.at(i) = val; bits.at(i) = val;
} }
for (int i = bits.size() - 4; i >= 0; i -= 4) { for (int i = bits.size() - 4; i >= 0; i -= 4) {
int c = bits.at(i) + (bits.at(i + 1) << 1) + int c = bits.at(i) + (bits.at(i + 1) << 1) + (bits.at(i + 2) << 2) + (bits.at(i + 3) << 3);
(bits.at(i + 2) << 2) + (bits.at(i + 3) << 3);
out << char(std::tolower(get_hexdigit(c))); out << char(std::tolower(get_hexdigit(c)));
} }
out << std::endl; out << std::endl;

View File

@ -24,8 +24,7 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
void add_port(const Context *ctx, CellInfo *cell, std::string name, void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir)
PortType dir)
{ {
IdString id = ctx->id(name); IdString id = ctx->id(name);
cell->ports[id] = PortInfo{id, nullptr, dir}; cell->ports[id] = PortInfo{id, nullptr, dir};
@ -36,8 +35,7 @@ CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name)
static int auto_idx = 0; static int auto_idx = 0;
CellInfo *new_cell = new CellInfo(); CellInfo *new_cell = new CellInfo();
if (name.empty()) { if (name.empty()) {
new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++));
std::to_string(auto_idx++));
} else { } else {
new_cell->name = ctx->id(name); new_cell->name = ctx->id(name);
} }
@ -143,8 +141,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
} }
} }
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
bool pass_thru_lut)
{ {
lc->params[ctx->id("DFF_ENABLE")] = "1"; lc->params[ctx->id("DFF_ENABLE")] = "1";
std::string config = dff->type.str(ctx).substr(6); std::string config = dff->type.str(ctx).substr(6);
@ -214,22 +211,18 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio)
assert(false); assert(false);
} }
NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net; NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net;
CellInfo *tbuf = CellInfo *tbuf = net_driven_by(
net_driven_by(ctx, donet, ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); },
[](const Context *ctx, const CellInfo *cell) { ctx->id("Y"));
return cell->type == ctx->id("$_TBUF_");
},
ctx->id("Y"));
if (tbuf) { if (tbuf) {
sbio->params[ctx->id("PIN_TYPE")] = "41"; sbio->params[ctx->id("PIN_TYPE")] = "41";
replace_port(tbuf, ctx->id("A"), sbio, ctx->id("D_OUT_0")); replace_port(tbuf, ctx->id("A"), sbio, ctx->id("D_OUT_0"));
replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE")); replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE"));
ctx->nets.erase(donet->name); ctx->nets.erase(donet->name);
if (!donet->users.empty()) if (!donet->users.empty())
log_error( log_error("unsupported tristate IO pattern for IO buffer '%s', "
"unsupported tristate IO pattern for IO buffer '%s', " "instantiate SB_IO manually to ensure correct behaviour\n",
"instantiate SB_IO manually to ensure correct behaviour\n", nxio->name.c_str(ctx));
nxio->name.c_str(ctx));
ctx->cells.erase(tbuf->name); ctx->cells.erase(tbuf->name);
} }
} }

View File

@ -30,89 +30,53 @@ NEXTPNR_NAMESPACE_BEGIN
CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name = ""); CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name = "");
// Return true if a cell is a LUT // Return true if a cell is a LUT
inline bool is_lut(const Context *ctx, const CellInfo *cell) inline bool is_lut(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); }
{
return cell->type == ctx->id("SB_LUT4");
}
// Return true if a cell is a flipflop // Return true if a cell is a flipflop
inline bool is_ff(const Context *ctx, const CellInfo *cell) inline bool is_ff(const Context *ctx, const CellInfo *cell)
{ {
return cell->type == ctx->id("SB_DFF") || return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") ||
cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") ||
cell->type == ctx->id("SB_DFFSR") || cell->type == ctx->id("SB_DFFESR") || cell->type == ctx->id("SB_DFFER") ||
cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFESS") || cell->type == ctx->id("SB_DFFES") ||
cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFN") || cell->type == ctx->id("SB_DFFNE") ||
cell->type == ctx->id("SB_DFFS") || cell->type == ctx->id("SB_DFFNSR") || cell->type == ctx->id("SB_DFFNR") ||
cell->type == ctx->id("SB_DFFESR") || cell->type == ctx->id("SB_DFFNSS") || cell->type == ctx->id("SB_DFFNS") ||
cell->type == ctx->id("SB_DFFER") || cell->type == ctx->id("SB_DFFNESR") || cell->type == ctx->id("SB_DFFNER") ||
cell->type == ctx->id("SB_DFFESS") || cell->type == ctx->id("SB_DFFNESS") || cell->type == ctx->id("SB_DFFNES");
cell->type == ctx->id("SB_DFFES") ||
cell->type == ctx->id("SB_DFFN") ||
cell->type == ctx->id("SB_DFFNE") ||
cell->type == ctx->id("SB_DFFNSR") ||
cell->type == ctx->id("SB_DFFNR") ||
cell->type == ctx->id("SB_DFFNSS") ||
cell->type == ctx->id("SB_DFFNS") ||
cell->type == ctx->id("SB_DFFNESR") ||
cell->type == ctx->id("SB_DFFNER") ||
cell->type == ctx->id("SB_DFFNESS") ||
cell->type == ctx->id("SB_DFFNES");
} }
inline bool is_carry(const Context *ctx, const CellInfo *cell) inline bool is_carry(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); }
{
return cell->type == ctx->id("SB_CARRY");
}
inline bool is_lc(const Context *ctx, const CellInfo *cell) inline bool is_lc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); }
{
return cell->type == ctx->id("ICESTORM_LC");
}
// Return true if a cell is a SB_IO // Return true if a cell is a SB_IO
inline bool is_sb_io(const Context *ctx, const CellInfo *cell) inline bool is_sb_io(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); }
{
return cell->type == ctx->id("SB_IO");
}
// Return true if a cell is a global buffer // Return true if a cell is a global buffer
inline bool is_gbuf(const Context *ctx, const CellInfo *cell) inline bool is_gbuf(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); }
{
return cell->type == ctx->id("SB_GB");
}
// Return true if a cell is a RAM // Return true if a cell is a RAM
inline bool is_ram(const Context *ctx, const CellInfo *cell) inline bool is_ram(const Context *ctx, const CellInfo *cell)
{ {
return cell->type == ctx->id("SB_RAM40_4K") || return cell->type == ctx->id("SB_RAM40_4K") || cell->type == ctx->id("SB_RAM40_4KNR") ||
cell->type == ctx->id("SB_RAM40_4KNR") || cell->type == ctx->id("SB_RAM40_4KNW") || cell->type == ctx->id("SB_RAM40_4KNRNW");
cell->type == ctx->id("SB_RAM40_4KNW") ||
cell->type == ctx->id("SB_RAM40_4KNRNW");
} }
inline bool is_sb_lfosc(const Context *ctx, const CellInfo *cell) inline bool is_sb_lfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LFOSC"); }
{
return cell->type == ctx->id("SB_LFOSC");
}
inline bool is_sb_hfosc(const Context *ctx, const CellInfo *cell) inline bool is_sb_hfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_HFOSC"); }
{
return cell->type == ctx->id("SB_HFOSC");
}
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports // Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
// as needed. Set no_dff if a DFF is not being used, so that the output // as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected // can be reconnected
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = true);
bool no_dff = true);
// Convert a SB_DFFx primitive to (part of) an ICESTORM_LC, setting parameters // Convert a SB_DFFx primitive to (part of) an ICESTORM_LC, setting parameters
// and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will // and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will
// be configured as pass through and D connected to I0, otherwise D will be // be configured as pass through and D connected to I0, otherwise D will be
// ignored // ignored
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
bool pass_thru_lut = false);
// Convert a nextpnr IO buffer to a SB_IO // Convert a nextpnr IO buffer to a SB_IO
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio); void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio);

View File

@ -38,18 +38,14 @@ static void pack_lut_lutffs(Context *ctx)
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (ctx->verbose) if (ctx->verbose)
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
ci->type.c_str(ctx));
if (is_lut(ctx, ci)) { if (is_lut(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_LC");
ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));
std::copy(ci->attrs.begin(), ci->attrs.end(),
std::inserter(packed->attrs, packed->attrs.begin()));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
new_cells.push_back(packed); new_cells.push_back(packed);
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
packed->name.c_str(ctx));
// See if we can pack into a DFF // See if we can pack into a DFF
// TODO: LUT cascade // TODO: LUT cascade
NetInfo *o = ci->ports.at(ctx->id("O")).net; NetInfo *o = ci->ports.at(ctx->id("O")).net;
@ -60,8 +56,7 @@ static void pack_lut_lutffs(Context *ctx)
if (ctx->verbose) if (ctx->verbose)
log_info("found attached dff %s\n", dff->name.c_str(ctx)); log_info("found attached dff %s\n", dff->name.c_str(ctx));
auto dff_bel = dff->attrs.find(ctx->id("BEL")); auto dff_bel = dff->attrs.find(ctx->id("BEL"));
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
lut_bel->second != dff_bel->second) {
// Locations don't match, can't pack // Locations don't match, can't pack
} else { } else {
lut_to_lc(ctx, ci, packed, false); lut_to_lc(ctx, ci, packed, false);
@ -71,8 +66,7 @@ static void pack_lut_lutffs(Context *ctx)
packed->attrs[ctx->id("BEL")] = dff_bel->second; packed->attrs[ctx->id("BEL")] = dff_bel->second;
packed_cells.insert(dff->name); packed_cells.insert(dff->name);
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
dff->name.c_str(ctx), packed->name.c_str(ctx));
packed_dff = true; packed_dff = true;
} }
} }
@ -100,13 +94,10 @@ static void pack_nonlut_ffs(Context *ctx)
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_ff(ctx, ci)) { if (is_ff(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_DFFLC");
ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));
std::copy(ci->attrs.begin(), ci->attrs.end(),
std::inserter(packed->attrs, packed->attrs.begin()));
if (ctx->verbose) if (ctx->verbose)
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
packed->name.c_str(ctx));
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
new_cells.push_back(packed); new_cells.push_back(packed);
dff_to_lc(ctx, ci, packed, true); dff_to_lc(ctx, ci, packed, true);
@ -131,15 +122,11 @@ static void pack_carries(Context *ctx)
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_carry(ctx, ci)) { if (is_carry(ctx, ci)) {
packed_cells.insert(cell.first); packed_cells.insert(cell.first);
CellInfo *carry_ci_lc = CellInfo *carry_ci_lc = net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc, ctx->id("I3"), false);
net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc,
ctx->id("I3"), false);
if (!ci->ports.at(ctx->id("I0")).net) if (!ci->ports.at(ctx->id("I0")).net)
log_error("SB_CARRY '%s' has disconnected port I0\n", log_error("SB_CARRY '%s' has disconnected port I0\n", cell.first.c_str(ctx));
cell.first.c_str(ctx));
if (!ci->ports.at(ctx->id("I1")).net) if (!ci->ports.at(ctx->id("I1")).net)
log_error("SB_CARRY '%s' has disconnected port I1\n", log_error("SB_CARRY '%s' has disconnected port I1\n", cell.first.c_str(ctx));
cell.first.c_str(ctx));
std::unordered_set<IdString> i0_matches, i1_matches; std::unordered_set<IdString> i0_matches, i1_matches;
auto &i0_usrs = ci->ports.at(ctx->id("I0")).net->users; auto &i0_usrs = ci->ports.at(ctx->id("I0")).net->users;
@ -154,8 +141,7 @@ static void pack_carries(Context *ctx)
i1_matches.insert(usr.cell->name); i1_matches.insert(usr.cell->name);
} }
std::set<IdString> carry_lcs; std::set<IdString> carry_lcs;
std::set_intersection(i0_matches.begin(), i0_matches.end(), std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(),
i1_matches.begin(), i1_matches.end(),
std::inserter(carry_lcs, carry_lcs.begin())); std::inserter(carry_lcs, carry_lcs.begin()));
CellInfo *carry_lc = nullptr; CellInfo *carry_lc = nullptr;
if (carry_ci_lc) { if (carry_ci_lc) {
@ -167,27 +153,22 @@ static void pack_carries(Context *ctx)
carry_lc = carry_ci_lc; carry_lc = carry_ci_lc;
} else { } else {
if (carry_lcs.empty()) if (carry_lcs.empty())
log_error( log_error("SB_CARRY '%s' cannot be packed into any logic "
"SB_CARRY '%s' cannot be packed into any logic " "cell (no logic cell connects to both I0 and I1)\n",
"cell (no logic cell connects to both I0 and I1)\n", cell.first.c_str(ctx));
cell.first.c_str(ctx));
carry_lc = ctx->cells.at(*carry_lcs.begin()); carry_lc = ctx->cells.at(*carry_lcs.begin());
} }
carry_lc->attrs[ctx->id("CARRY_ENABLE")] = "1"; carry_lc->attrs[ctx->id("CARRY_ENABLE")] = "1";
replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN")); replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN"));
replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT")); replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT"));
i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) {
[ci, ctx](const PortRef &pr) { return pr.cell == ci && pr.port == ctx->id("I0");
return pr.cell == ci && }));
pr.port == ctx->id("I0");
}));
i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx](const PortRef &pr) {
[ci, ctx](const PortRef &pr) { return pr.cell == ci && pr.port == ctx->id("I1");
return pr.cell == ci && }));
pr.port == ctx->id("I1");
}));
} }
} }
for (auto pcell : packed_cells) { for (auto pcell : packed_cells) {
@ -206,30 +187,24 @@ static void pack_ram(Context *ctx)
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_ram(ctx, ci)) { if (is_ram(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM");
ci->name.str(ctx) + "_RAM");
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
new_cells.push_back(packed); new_cells.push_back(packed);
for (auto param : ci->params) for (auto param : ci->params)
packed->params[param.first] = param.second; packed->params[param.first] = param.second;
packed->params[ctx->id("NEG_CLK_W")] = packed->params[ctx->id("NEG_CLK_W")] =
std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
ci->type == ctx->id("SB_RAM40_4KNRNW"));
packed->params[ctx->id("NEG_CLK_R")] = packed->params[ctx->id("NEG_CLK_R")] =
std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
ci->type == ctx->id("SB_RAM40_4KNRNW"));
packed->type = ctx->id("ICESTORM_RAM"); packed->type = ctx->id("ICESTORM_RAM");
for (auto port : ci->ports) { for (auto port : ci->ports) {
PortInfo &pi = port.second; PortInfo &pi = port.second;
std::string newname = pi.name.str(ctx); std::string newname = pi.name.str(ctx);
size_t bpos = newname.find('['); size_t bpos = newname.find('[');
if (bpos != std::string::npos) { if (bpos != std::string::npos) {
newname = newname.substr(0, bpos) + "_" + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
newname.substr(bpos + 1,
(newname.size() - bpos) - 2);
} }
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed, replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed, ctx->id(newname));
ctx->id(newname));
} }
} }
} }
@ -243,18 +218,15 @@ static void pack_ram(Context *ctx)
} }
// Merge a net into a constant net // Merge a net into a constant net
static void set_net_constant(const Context *ctx, NetInfo *orig, static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
NetInfo *constnet, bool constval)
{ {
orig->driver.cell = nullptr; orig->driver.cell = nullptr;
for (auto user : orig->users) { for (auto user : orig->users) {
if (user.cell != nullptr) { if (user.cell != nullptr) {
CellInfo *uc = user.cell; CellInfo *uc = user.cell;
if (ctx->verbose) if (ctx->verbose)
log_info("%s user %s\n", orig->name.c_str(ctx), log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
uc->name.c_str(ctx)); if ((is_lut(ctx, uc) || is_lc(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) {
if ((is_lut(ctx, uc) || is_lc(ctx, uc)) &&
(user.port.str(ctx).at(0) == 'I') && !constval) {
uc->ports[user.port].net = nullptr; uc->ports[user.port].net = nullptr;
} else { } else {
uc->ports[user.port].net = constnet; uc->ports[user.port].net = constnet;
@ -270,16 +242,14 @@ static void pack_constants(Context *ctx)
{ {
log_info("Packing constants..\n"); log_info("Packing constants..\n");
CellInfo *gnd_cell = CellInfo *gnd_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND");
create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND");
gnd_cell->params[ctx->id("LUT_INIT")] = "0"; gnd_cell->params[ctx->id("LUT_INIT")] = "0";
NetInfo *gnd_net = new NetInfo; NetInfo *gnd_net = new NetInfo;
gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->name = ctx->id("$PACKER_GND_NET");
gnd_net->driver.cell = gnd_cell; gnd_net->driver.cell = gnd_cell;
gnd_net->driver.port = ctx->id("O"); gnd_net->driver.port = ctx->id("O");
CellInfo *vcc_cell = CellInfo *vcc_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC");
create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC");
vcc_cell->params[ctx->id("LUT_INIT")] = "1"; vcc_cell->params[ctx->id("LUT_INIT")] = "1";
NetInfo *vcc_net = new NetInfo; NetInfo *vcc_net = new NetInfo;
vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->name = ctx->id("$PACKER_VCC_NET");
@ -292,13 +262,11 @@ static void pack_constants(Context *ctx)
for (auto net : sorted(ctx->nets)) { for (auto net : sorted(ctx->nets)) {
NetInfo *ni = net.second; NetInfo *ni = net.second;
if (ni->driver.cell != nullptr && if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
ni->driver.cell->type == ctx->id("GND")) {
set_net_constant(ctx, ni, gnd_net, false); set_net_constant(ctx, ni, gnd_net, false);
gnd_used = true; gnd_used = true;
dead_nets.push_back(net.first); dead_nets.push_back(net.first);
} else if (ni->driver.cell != nullptr && } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
ni->driver.cell->type == ctx->id("VCC")) {
set_net_constant(ctx, ni, vcc_net, true); set_net_constant(ctx, ni, vcc_net, true);
vcc_used = true; vcc_used = true;
dead_nets.push_back(net.first); dead_nets.push_back(net.first);
@ -321,8 +289,7 @@ static void pack_constants(Context *ctx)
static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{ {
return cell->type == ctx->id("$nextpnr_ibuf") || return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
cell->type == ctx->id("$nextpnr_obuf") ||
cell->type == ctx->id("$nextpnr_iobuf"); cell->type == ctx->id("$nextpnr_iobuf");
} }
@ -338,22 +305,16 @@ static void pack_io(Context *ctx)
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_nextpnr_iob(ctx, ci)) { if (is_nextpnr_iob(ctx, ci)) {
CellInfo *sb = nullptr; CellInfo *sb = nullptr;
if (ci->type == ctx->id("$nextpnr_ibuf") || if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
ci->type == ctx->id("$nextpnr_iobuf")) { sb = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci);
sb = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net,
is_sb_io, ctx->id("PACKAGE_PIN"), true,
ci);
} else if (ci->type == ctx->id("$nextpnr_obuf")) { } else if (ci->type == ctx->id("$nextpnr_obuf")) {
sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci);
is_sb_io, ctx->id("PACKAGE_PIN"), true,
ci);
} }
if (sb != nullptr) { if (sb != nullptr) {
// Trivial case, SB_IO used. Just destroy the net and the // Trivial case, SB_IO used. Just destroy the net and the
// iobuf // iobuf
log_info("%s feeds SB_IO %s, removing %s %s.\n", log_info("%s feeds SB_IO %s, removing %s %s.\n", ci->name.c_str(ctx), sb->name.c_str(ctx),
ci->name.c_str(ctx), sb->name.c_str(ctx),
ci->type.c_str(ctx), ci->name.c_str(ctx)); ci->type.c_str(ctx), ci->name.c_str(ctx));
NetInfo *net = sb->ports.at(ctx->id("PACKAGE_PIN")).net; NetInfo *net = sb->ports.at(ctx->id("PACKAGE_PIN")).net;
if (net != nullptr) { if (net != nullptr) {
@ -362,14 +323,12 @@ static void pack_io(Context *ctx)
} }
} else { } else {
// Create a SB_IO buffer // Create a SB_IO buffer
sb = create_ice_cell(ctx, ctx->id("SB_IO"), sb = create_ice_cell(ctx, ctx->id("SB_IO"), ci->name.str(ctx) + "$sb_io");
ci->name.str(ctx) + "$sb_io");
nxio_to_sb(ctx, ci, sb); nxio_to_sb(ctx, ci, sb);
new_cells.push_back(sb); new_cells.push_back(sb);
} }
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
std::copy(ci->attrs.begin(), ci->attrs.end(), std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(sb->attrs, sb->attrs.begin()));
std::inserter(sb->attrs, sb->attrs.begin()));
} }
} }
for (auto pcell : packed_cells) { for (auto pcell : packed_cells) {
@ -380,11 +339,9 @@ static void pack_io(Context *ctx)
} }
} }
static void insert_global(Context *ctx, NetInfo *net, bool is_reset, static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen)
bool is_cen)
{ {
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk"));
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
CellInfo *gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name); CellInfo *gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name);
gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net; gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net;
PortRef pr; PortRef pr;
@ -401,8 +358,7 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset,
gb->ports[ctx->id("GLOBAL_BUFFER_OUTPUT")].net = glbnet; gb->ports[ctx->id("GLOBAL_BUFFER_OUTPUT")].net = glbnet;
std::vector<PortRef> keep_users; std::vector<PortRef> keep_users;
for (auto user : net->users) { for (auto user : net->users) {
if (is_clock_port(ctx, user) || if (is_clock_port(ctx, user) || (is_reset && is_reset_port(ctx, user)) ||
(is_reset && is_reset_port(ctx, user)) ||
(is_cen && is_enable_port(ctx, user))) { (is_cen && is_enable_port(ctx, user))) {
user.cell->ports[user.port].net = glbnet; user.cell->ports[user.port].net = glbnet;
glbnet->users.push_back(user); glbnet->users.push_back(user);
@ -443,25 +399,19 @@ static void promote_globals(Context *ctx)
if (is_gbuf(ctx, cell.second)) if (is_gbuf(ctx, cell.second))
--gbs_available; --gbs_available;
while (prom_globals < gbs_available) { while (prom_globals < gbs_available) {
auto global_clock = auto global_clock = std::max_element(clock_count.begin(), clock_count.end(),
std::max_element(clock_count.begin(), clock_count.end(), [](const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
[](const std::pair<IdString, int> &a, return a.second < b.second;
const std::pair<IdString, int> &b) { });
return a.second < b.second;
});
auto global_reset = auto global_reset = std::max_element(reset_count.begin(), reset_count.end(),
std::max_element(reset_count.begin(), reset_count.end(), [](const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
[](const std::pair<IdString, int> &a, return a.second < b.second;
const std::pair<IdString, int> &b) { });
return a.second < b.second; auto global_cen = std::max_element(cen_count.begin(), cen_count.end(),
}); [](const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
auto global_cen = return a.second < b.second;
std::max_element(cen_count.begin(), cen_count.end(), });
[](const std::pair<IdString, int> &a,
const std::pair<IdString, int> &b) {
return a.second < b.second;
});
if (global_reset->second > global_clock->second && prom_resets < 4) { if (global_reset->second > global_clock->second && prom_resets < 4) {
NetInfo *rstnet = ctx->nets[global_reset->first]; NetInfo *rstnet = ctx->nets[global_reset->first];
insert_global(ctx, rstnet, true, false); insert_global(ctx, rstnet, true, false);
@ -502,15 +452,13 @@ static void pack_intosc(Context *ctx)
for (auto cell : sorted(ctx->cells)) { for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_sb_lfosc(ctx, ci)) { if (is_sb_lfosc(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC");
ci->name.str(ctx) + "_OSC");
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
new_cells.push_back(packed); new_cells.push_back(packed);
replace_port(ci, ctx->id("CLKLFEN"), packed, ctx->id("CLKLFEN")); replace_port(ci, ctx->id("CLKLFEN"), packed, ctx->id("CLKLFEN"));
replace_port(ci, ctx->id("CLKLFPU"), packed, ctx->id("CLKLFPU")); replace_port(ci, ctx->id("CLKLFPU"), packed, ctx->id("CLKLFPU"));
if (bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))) { if (bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))) {
replace_port(ci, ctx->id("CLKLF"), packed, replace_port(ci, ctx->id("CLKLF"), packed, ctx->id("CLKLF_FABRIC"));
ctx->id("CLKLF_FABRIC"));
} else { } else {
replace_port(ci, ctx->id("CLKLF"), packed, ctx->id("CLKLF")); replace_port(ci, ctx->id("CLKLF"), packed, ctx->id("CLKLF"));
} }

View File

@ -47,8 +47,7 @@ bool apply_pcf(Context *ctx, std::istream &in)
std::string cmd = words.at(0); std::string cmd = words.at(0);
if (cmd == "set_io") { if (cmd == "set_io") {
size_t args_end = 1; size_t args_end = 1;
while (args_end < words.size() && while (args_end < words.size() && words.at(args_end).at(0) == '-')
words.at(args_end).at(0) == '-')
args_end++; args_end++;
std::string cell = words.at(args_end); std::string cell = words.at(args_end);
std::string pin = words.at(args_end + 1); std::string pin = words.at(args_end + 1);
@ -58,10 +57,8 @@ bool apply_pcf(Context *ctx, std::istream &in)
} else { } else {
BelId pin_bel = ctx->getPackagePinBel(pin); BelId pin_bel = ctx->getPackagePinBel(pin);
if (pin_bel == BelId()) if (pin_bel == BelId())
log_error("package does not have a pin named %s\n", log_error("package does not have a pin named %s\n", pin.c_str());
pin.c_str()); fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(pin_bel).str(ctx);
fnd_cell->second->attrs[ctx->id("BEL")] =
ctx->getBelName(pin_bel).str(ctx);
log_info("constrained '%s' to bel '%s'\n", cell.c_str(), log_info("constrained '%s' to bel '%s'\n", cell.c_str(),
fnd_cell->second->attrs[ctx->id("BEL")].c_str()); fnd_cell->second->attrs[ctx->id("BEL")].c_str());
} }

View File

@ -45,9 +45,7 @@ void arch_wrap_python()
class_<PipId>("PipId").def_readwrite("index", &PipId::index); class_<PipId>("PipId").def_readwrite("index", &PipId::index);
class_<BelPin>("BelPin") class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
.def_readwrite("bel", &BelPin::bel)
.def_readwrite("pin", &BelPin::pin);
enum_<PortPin>("PortPin") enum_<PortPin>("PortPin")
#define X(t) .value("PIN_" #t, PIN_##t) #define X(t) .value("PIN_" #t, PIN_##t)

View File

@ -1,3 +1,22 @@
/*
* 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.
*
*/
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <vector> #include <vector>

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(HX1KTest, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(HX1KTest, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(HX8KTest, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(HX8KTest, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(LP1KTest, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(LP1KTest, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(LP384Test, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(LP384Test, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(LP8KTest, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(LP8KTest, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;

View File

@ -1,3 +1,22 @@
/*
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"

View File

@ -1,3 +1,23 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* 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.
*
*/
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "nextpnr.h" #include "nextpnr.h"
@ -59,8 +79,7 @@ TEST_F(UP5KTest, uphill_to_downhill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto uphill_pip : ctx->getPipsUphill(dst)) { for (auto uphill_pip : ctx->getPipsUphill(dst)) {
bool found_downhill = false; bool found_downhill = false;
for (auto downhill_pip : ctx->getPipsDownhill( for (auto downhill_pip : ctx->getPipsDownhill(ctx->getPipSrcWire(uphill_pip))) {
ctx->getPipSrcWire(uphill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_downhill); ASSERT_FALSE(found_downhill);
found_downhill = true; found_downhill = true;
@ -76,8 +95,7 @@ TEST_F(UP5KTest, downhill_to_uphill)
for (auto dst : ctx->getWires()) { for (auto dst : ctx->getWires()) {
for (auto downhill_pip : ctx->getPipsDownhill(dst)) { for (auto downhill_pip : ctx->getPipsDownhill(dst)) {
bool found_uphill = false; bool found_uphill = false;
for (auto uphill_pip : ctx->getPipsUphill( for (auto uphill_pip : ctx->getPipsUphill(ctx->getPipDstWire(downhill_pip))) {
ctx->getPipDstWire(downhill_pip))) {
if (uphill_pip == downhill_pip) { if (uphill_pip == downhill_pip) {
ASSERT_FALSE(found_uphill); ASSERT_FALSE(found_uphill);
found_uphill = true; found_uphill = true;