Update from increased clangformat line length
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
727f99267c
commit
1e8840b0f9
@ -24,8 +24,7 @@
|
||||
#include "util.h"
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
||||
IdString rep_name)
|
||||
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdString rep_name)
|
||||
{
|
||||
PortInfo &old = old_cell->ports.at(old_name);
|
||||
PortInfo &rep = rep_cell->ports.at(rep_name);
|
||||
@ -69,8 +68,7 @@ void print_utilisation(const Context *ctx)
|
||||
for (auto type : available_types) {
|
||||
IdString type_id = ctx->belTypeToId(type.first);
|
||||
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,
|
||||
type.second, 100 * used_bels / type.second);
|
||||
log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), used_bels, type.second, 100 * used_bels / type.second);
|
||||
}
|
||||
log_break();
|
||||
}
|
||||
|
@ -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
|
||||
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
||||
IdString rep_name);
|
||||
void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdString rep_name);
|
||||
|
||||
// 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
|
||||
@ -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
|
||||
// is not considered
|
||||
template <typename F1>
|
||||
CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
|
||||
IdString port, bool exclusive = false,
|
||||
CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred, IdString port, bool exclusive = false,
|
||||
CellInfo *exclude = nullptr)
|
||||
{
|
||||
if (net == nullptr)
|
||||
@ -56,16 +54,13 @@ CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
|
||||
return nullptr;
|
||||
} else if (net->users.size() == 2) {
|
||||
if (std::find_if(net->users.begin(), net->users.end(),
|
||||
[exclude](const PortRef &ref) {
|
||||
return ref.cell == exclude;
|
||||
}) == net->users.end())
|
||||
[exclude](const PortRef &ref) { return ref.cell == exclude; }) == net->users.end())
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &load : net->users) {
|
||||
if (load.cell != exclude && cell_pred(ctx, load.cell) &&
|
||||
load.port == port) {
|
||||
if (load.cell != exclude && cell_pred(ctx, load.cell) && load.port == port) {
|
||||
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
|
||||
// that cell, otherwise nullptr
|
||||
template <typename F1>
|
||||
CellInfo *net_driven_by(const Context *ctx, const NetInfo *net, F1 cell_pred,
|
||||
IdString port)
|
||||
template <typename F1> CellInfo *net_driven_by(const Context *ctx, const NetInfo *net, F1 cell_pred, IdString port)
|
||||
{
|
||||
if (net == nullptr)
|
||||
return nullptr;
|
||||
|
@ -88,8 +88,7 @@ class SAPlacer
|
||||
std::string loc_name = loc->second;
|
||||
BelId bel = ctx->getBelByName(ctx->id(loc_name));
|
||||
if (bel == BelId()) {
|
||||
log_error(
|
||||
"No Bel named \'%s\' located for "
|
||||
log_error("No Bel named \'%s\' located for "
|
||||
"this chip (processing BEL attribute on \'%s\')\n",
|
||||
loc_name.c_str(), cell->name.c_str(ctx));
|
||||
}
|
||||
@ -98,9 +97,8 @@ class SAPlacer
|
||||
if (bel_type != ctx->belTypeFromId(cell->type)) {
|
||||
log_error("Bel \'%s\' of type \'%s\' does not match cell "
|
||||
"\'%s\' of type \'%s\'",
|
||||
loc_name.c_str(),
|
||||
ctx->belTypeToId(bel_type).c_str(ctx),
|
||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(ctx), cell->name.c_str(ctx),
|
||||
cell->type.c_str(ctx));
|
||||
}
|
||||
|
||||
ctx->bindBel(bel, cell->name, STRENGTH_USER);
|
||||
@ -119,25 +117,21 @@ class SAPlacer
|
||||
autoplaced.push_back(cell.second);
|
||||
}
|
||||
}
|
||||
std::sort(autoplaced.begin(), autoplaced.end(),
|
||||
[](CellInfo *a, CellInfo *b) { return a->name < b->name; });
|
||||
std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; });
|
||||
ctx->shuffle(autoplaced);
|
||||
|
||||
// Place cells randomly initially
|
||||
log_info("Creating initial placement for remaining %d cells.\n",
|
||||
int(autoplaced.size()));
|
||||
log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size()));
|
||||
|
||||
for (auto cell : autoplaced) {
|
||||
place_initial(cell);
|
||||
placed_cells++;
|
||||
if ((placed_cells - constr_placed_cells) % 500 == 0)
|
||||
log_info(" initial placement placed %d/%d cells\n",
|
||||
int(placed_cells - constr_placed_cells),
|
||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||
int(autoplaced.size()));
|
||||
}
|
||||
if ((placed_cells - constr_placed_cells) % 500 != 0)
|
||||
log_info(" initial placement placed %d/%d cells\n",
|
||||
int(placed_cells - constr_placed_cells),
|
||||
log_info(" initial placement placed %d/%d cells\n", int(placed_cells - constr_placed_cells),
|
||||
int(autoplaced.size()));
|
||||
|
||||
log_info("Running simulated annealing placer.\n");
|
||||
@ -184,9 +178,7 @@ class SAPlacer
|
||||
|
||||
if (temp <= 1e-3 && n_no_progress >= 5) {
|
||||
if (iter % 5 != 0)
|
||||
log_info(
|
||||
" at iteration #%d: temp = %f, wire length = %f\n",
|
||||
iter, temp, double(curr_wirelength));
|
||||
log_info(" at iteration #%d: temp = %f, wire length = %f\n", iter, temp, double(curr_wirelength));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -235,13 +227,11 @@ class SAPlacer
|
||||
if (cell != IdString())
|
||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
||||
if (ctx->force) {
|
||||
log_warning(
|
||||
"post-placement validity check failed for Bel '%s' "
|
||||
log_warning("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
} else {
|
||||
log_error(
|
||||
"post-placement validity check failed for Bel '%s' "
|
||||
log_error("post-placement validity check failed for Bel '%s' "
|
||||
"(%s)\n",
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
}
|
||||
@ -267,8 +257,7 @@ class SAPlacer
|
||||
}
|
||||
BelType targetType = ctx->belTypeFromId(cell->type);
|
||||
for (auto bel : ctx->getBels()) {
|
||||
if (ctx->getBelType(bel) == targetType &&
|
||||
checker->isValidBelForCell(cell, bel)) {
|
||||
if (ctx->getBelType(bel) == targetType && checker->isValidBelForCell(cell, bel)) {
|
||||
if (ctx->checkBelAvail(bel)) {
|
||||
uint64_t score = ctx->rng64();
|
||||
if (score <= best_score) {
|
||||
@ -279,8 +268,7 @@ class SAPlacer
|
||||
uint64_t score = ctx->rng64();
|
||||
if (score <= best_ripup_score) {
|
||||
best_ripup_score = score;
|
||||
ripup_target =
|
||||
ctx->cells.at(ctx->getBoundBelCell(bel));
|
||||
ripup_target = ctx->cells.at(ctx->getBoundBelCell(bel));
|
||||
ripup_bel = bel;
|
||||
}
|
||||
}
|
||||
@ -288,8 +276,7 @@ class SAPlacer
|
||||
}
|
||||
if (best_bel == BelId()) {
|
||||
if (iters == 0 || ripup_bel == BelId())
|
||||
log_error("failed to place cell '%s' of type '%s'\n",
|
||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
log_error("failed to place cell '%s' of type '%s'\n", cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
--iters;
|
||||
ctx->unbindBel(ripup_target->bel);
|
||||
best_bel = ripup_bel;
|
||||
@ -316,8 +303,7 @@ class SAPlacer
|
||||
if (driver_cell->bel == BelId())
|
||||
return 0;
|
||||
ctx->estimatePosition(driver_cell->bel, driver_x, driver_y, driver_gb);
|
||||
WireId drv_wire = ctx->getWireBelPin(
|
||||
driver_cell->bel, ctx->portPinFromId(net->driver.port));
|
||||
WireId drv_wire = ctx->getWireBelPin(driver_cell->bel, ctx->portPinFromId(net->driver.port));
|
||||
if (driver_gb)
|
||||
return 0;
|
||||
float worst_slack = 1000;
|
||||
@ -329,11 +315,9 @@ class SAPlacer
|
||||
if (load_cell->bel == BelId())
|
||||
continue;
|
||||
if (timing_driven) {
|
||||
WireId user_wire = ctx->getWireBelPin(
|
||||
load_cell->bel, ctx->portPinFromId(load.port));
|
||||
WireId user_wire = ctx->getWireBelPin(load_cell->bel, ctx->portPinFromId(load.port));
|
||||
delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire);
|
||||
float slack =
|
||||
ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
|
||||
float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl);
|
||||
if (slack < 0)
|
||||
tns += slack;
|
||||
worst_slack = std::min(slack, worst_slack);
|
||||
@ -351,11 +335,9 @@ class SAPlacer
|
||||
}
|
||||
if (timing_driven) {
|
||||
wirelength =
|
||||
wirelen_t((((ymax - ymin) + (xmax - xmin)) *
|
||||
std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
|
||||
wirelen_t((((ymax - ymin) + (xmax - xmin)) * std::min(5.0, (1.0 + std::exp(-worst_slack / 5)))));
|
||||
} else {
|
||||
wirelength =
|
||||
wirelen_t((ymax - ymin) + (xmax - xmin));
|
||||
wirelength = wirelen_t((ymax - ymin) + (xmax - xmin));
|
||||
}
|
||||
|
||||
return wirelength;
|
||||
@ -394,8 +376,7 @@ class SAPlacer
|
||||
ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
|
||||
}
|
||||
|
||||
if (!checker->isBelLocationValid(newBel) ||
|
||||
((other != IdString() && !checker->isBelLocationValid(oldBel)))) {
|
||||
if (!checker->isBelLocationValid(newBel) || ((other != IdString() && !checker->isBelLocationValid(oldBel)))) {
|
||||
ctx->unbindBel(newBel);
|
||||
if (other != IdString())
|
||||
ctx->unbindBel(oldBel);
|
||||
@ -415,8 +396,7 @@ class SAPlacer
|
||||
delta = new_wirelength - curr_wirelength;
|
||||
n_move++;
|
||||
// SA acceptance criterea
|
||||
if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <=
|
||||
std::exp(-delta / temp))) {
|
||||
if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
|
||||
n_accept++;
|
||||
if (delta < 2)
|
||||
improved = true;
|
||||
|
@ -43,10 +43,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
// must be implemented in all architectures
|
||||
void arch_wrap_python();
|
||||
|
||||
bool operator==(const PortRef &a, const PortRef &b)
|
||||
{
|
||||
return (a.cell == b.cell) && (a.port == b.port);
|
||||
}
|
||||
bool operator==(const PortRef &a, const PortRef &b) { return (a.cell == b.cell) && (a.port == b.port); }
|
||||
|
||||
// Load a JSON file into a design
|
||||
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("text", &GraphicElement::text);
|
||||
|
||||
class_<PortRef>("PortRef")
|
||||
.def_readwrite("cell", &PortRef::cell)
|
||||
.def_readwrite("port", &PortRef::port);
|
||||
class_<PortRef>("PortRef").def_readwrite("cell", &PortRef::cell).def_readwrite("port", &PortRef::port);
|
||||
|
||||
class_<NetInfo, NetInfo *>("NetInfo")
|
||||
.def_readwrite("name", &NetInfo::name)
|
||||
@ -88,8 +83,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
|
||||
WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap");
|
||||
|
||||
class_<std::vector<PortRef>>("PortRefVector")
|
||||
.def(vector_indexing_suite<std::vector<PortRef>>());
|
||||
class_<std::vector<PortRef>>("PortRefVector").def(vector_indexing_suite<std::vector<PortRef>>());
|
||||
|
||||
enum_<PortType>("PortType")
|
||||
.value("PORT_IN", PORT_IN)
|
||||
@ -125,17 +119,13 @@ BOOST_PYTHON_MODULE(MODULE_NAME)
|
||||
def("load_design", load_design_shim);
|
||||
|
||||
class_<IdString>("IdString")
|
||||
.def("__str__", &IdString::global_str,
|
||||
return_value_policy<copy_const_reference>())
|
||||
.def("__str__", &IdString::global_str, return_value_policy<copy_const_reference>())
|
||||
.def(self < self)
|
||||
.def(self == self);
|
||||
arch_wrap_python();
|
||||
}
|
||||
|
||||
void arch_appendinittab()
|
||||
{
|
||||
PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME);
|
||||
}
|
||||
void arch_appendinittab() { PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME); }
|
||||
|
||||
static wchar_t *program;
|
||||
|
||||
|
@ -45,26 +45,18 @@ template <typename T> struct string_wrapper
|
||||
{
|
||||
from_pystring_converter()
|
||||
{
|
||||
converter::registry::push_back(&convertible, &construct,
|
||||
boost::python::type_id<T>());
|
||||
converter::registry::push_back(&convertible, &construct, boost::python::type_id<T>());
|
||||
};
|
||||
|
||||
static void *convertible(PyObject *object)
|
||||
{
|
||||
return PyUnicode_Check(object) ? object : 0;
|
||||
}
|
||||
static void *convertible(PyObject *object) { return PyUnicode_Check(object) ? object : 0; }
|
||||
|
||||
static void construct(PyObject *object,
|
||||
converter::rvalue_from_python_stage1_data *data)
|
||||
static void construct(PyObject *object, converter::rvalue_from_python_stage1_data *data)
|
||||
{
|
||||
const wchar_t *value = PyUnicode_AsUnicode(object);
|
||||
const std::wstring value_ws(value);
|
||||
if (value == 0)
|
||||
throw_error_already_set();
|
||||
void *storage =
|
||||
((boost::python::converter::rvalue_from_python_storage<T> *)
|
||||
data)
|
||||
->storage.bytes;
|
||||
void *storage = ((boost::python::converter::rvalue_from_python_storage<T> *)data)->storage.bytes;
|
||||
new (storage) T(fn(std::string(value_ws.begin(), value_ws.end())));
|
||||
data->convertible = storage;
|
||||
}
|
||||
@ -79,8 +71,7 @@ template <typename T> struct string_wrapper
|
||||
std::string str(T &x) { return fn(x); }
|
||||
};
|
||||
|
||||
template <typename F1, typename F2>
|
||||
static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn)
|
||||
template <typename F1, typename F2> 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>();
|
||||
|
@ -61,8 +61,7 @@ template <typename T, typename P> struct iterator_wrapper
|
||||
|
||||
static void wrap(const char *python_name)
|
||||
{
|
||||
class_<std::pair<T, T>>(python_name, no_init)
|
||||
.def("__next__", next, P());
|
||||
class_<std::pair<T, T>>(python_name, no_init).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
|
||||
*/
|
||||
|
||||
template <typename T, typename P = return_value_policy<return_by_value>>
|
||||
struct range_wrapper
|
||||
template <typename T, typename P = return_value_policy<return_by_value>> struct range_wrapper
|
||||
{
|
||||
typedef decltype(std::declval<T>().begin()) iterator_t;
|
||||
|
||||
static std::pair<iterator_t, iterator_t> iter(T &range)
|
||||
{
|
||||
return std::make_pair(range.begin(), range.end());
|
||||
}
|
||||
static std::pair<iterator_t, iterator_t> iter(T &range) { return std::make_pair(range.begin(), range.end()); }
|
||||
|
||||
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)
|
||||
{
|
||||
class_<std::pair<T &, int>>(python_name, no_init)
|
||||
.def("__next__", next);
|
||||
class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next);
|
||||
}
|
||||
};
|
||||
|
||||
@ -146,10 +140,7 @@ template <typename T1, typename T2> struct pair_wrapper
|
||||
|
||||
static int len(T &x) { return 2; }
|
||||
|
||||
static std::pair<T &, int> iter(T &x)
|
||||
{
|
||||
return std::make_pair(boost::ref(x), 0);
|
||||
};
|
||||
static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); };
|
||||
|
||||
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)
|
||||
{
|
||||
class_<std::pair<T &, int>>(python_name, no_init)
|
||||
.def("__next__", next);
|
||||
class_<std::pair<T &, int>>(python_name, no_init).def("__next__", next);
|
||||
}
|
||||
};
|
||||
|
||||
@ -206,10 +196,7 @@ template <typename T1, typename T2> struct map_pair_wrapper
|
||||
|
||||
static int len(T &x) { return 2; }
|
||||
|
||||
static std::pair<T &, int> iter(T &x)
|
||||
{
|
||||
return std::make_pair(boost::ref(x), 0);
|
||||
};
|
||||
static std::pair<T &, int> iter(T &x) { return std::make_pair(boost::ref(x), 0); };
|
||||
|
||||
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
|
||||
{
|
||||
typedef typename std::remove_cv<
|
||||
typename std::remove_reference<typename T::key_type>::type>::type K;
|
||||
typedef typename std::remove_cv<typename std::remove_reference<typename T::key_type>::type>::type K;
|
||||
typedef typename T::mapped_type V;
|
||||
typedef typename T::value_type KV;
|
||||
|
||||
@ -253,13 +239,10 @@ template <typename T> struct map_wrapper
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
static void wrap(const char *map_name, const char *kv_name,
|
||||
const char *kv_iter_name, const char *iter_name)
|
||||
static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name)
|
||||
{
|
||||
map_pair_wrapper<typename KV::first_type,
|
||||
typename KV::second_type>::wrap(kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T, return_value_policy<copy_non_const_reference>>
|
||||
rw;
|
||||
map_pair_wrapper<typename KV::first_type, typename KV::second_type>::wrap(kv_name, kv_iter_name);
|
||||
typedef range_wrapper<T, return_value_policy<copy_non_const_reference>> rw;
|
||||
typename rw::iter_wrap().wrap(iter_name);
|
||||
class_<T>(map_name, no_init)
|
||||
.def("__iter__", rw::iter)
|
||||
@ -269,9 +252,7 @@ template <typename T> struct map_wrapper
|
||||
}
|
||||
};
|
||||
|
||||
#define WRAP_MAP(t, name) \
|
||||
map_wrapper<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", \
|
||||
#name "Iterator")
|
||||
#define WRAP_MAP(t, name) map_wrapper<t>().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator")
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
|
@ -25,12 +25,10 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length,
|
||||
delay_t slack);
|
||||
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack);
|
||||
|
||||
// Follow a path, returning budget to annotate
|
||||
static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length,
|
||||
delay_t slack)
|
||||
static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, delay_t slack)
|
||||
{
|
||||
delay_t value;
|
||||
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) {
|
||||
delay_t comb_delay;
|
||||
// Look up delay through this path
|
||||
bool is_path = ctx->getCellDelay(user.cell, user.port,
|
||||
port.first, comb_delay);
|
||||
bool is_path = ctx->getCellDelay(user.cell, user.port, port.first, comb_delay);
|
||||
if (is_path) {
|
||||
NetInfo *net = port.second.net;
|
||||
if (net) {
|
||||
delay_t path_budget = follow_net(ctx, net, path_length,
|
||||
slack - comb_delay);
|
||||
delay_t path_budget = follow_net(ctx, net, path_length, slack - comb_delay);
|
||||
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;
|
||||
}
|
||||
|
||||
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length,
|
||||
delay_t slack)
|
||||
static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack)
|
||||
{
|
||||
delay_t net_budget = slack / (path_length + 1);
|
||||
for (auto &usr : net->users) {
|
||||
net_budget = std::min(
|
||||
net_budget, follow_user_port(ctx, usr, path_length + 1, slack));
|
||||
net_budget = std::min(net_budget, follow_user_port(ctx, usr, path_length + 1, slack));
|
||||
}
|
||||
return net_budget;
|
||||
}
|
||||
@ -91,11 +85,9 @@ void assign_budget(Context *ctx, float default_clock)
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto port : cell.second->ports) {
|
||||
if (port.second.type == PORT_OUT) {
|
||||
IdString clock_domain =
|
||||
ctx->getPortClock(cell.second, port.first);
|
||||
IdString clock_domain = ctx->getPortClock(cell.second, port.first);
|
||||
if (clock_domain != IdString()) {
|
||||
delay_t slack = delay_t(
|
||||
1.0e12 / default_clock); // TODO: clock constraints
|
||||
delay_t slack = delay_t(1.0e12 / default_clock); // TODO: clock constraints
|
||||
if (port.second.net)
|
||||
follow_net(ctx, port.second.net, 0, slack);
|
||||
}
|
||||
@ -109,13 +101,13 @@ void assign_budget(Context *ctx, float default_clock)
|
||||
if (user.budget < 0)
|
||||
log_warning("port %s.%s, connected to net '%s', has negative "
|
||||
"timing budget of %fns\n",
|
||||
user.cell->name.c_str(ctx), user.port.c_str(ctx),
|
||||
net.first.c_str(ctx), ctx->getDelayNS(user.budget));
|
||||
user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
|
||||
ctx->getDelayNS(user.budget));
|
||||
if (ctx->verbose)
|
||||
log_info("port %s.%s, connected to net '%s', has "
|
||||
"timing budget of %fns\n",
|
||||
user.cell->name.c_str(ctx), user.port.c_str(ctx),
|
||||
net.first.c_str(ctx), ctx->getDelayNS(user.budget));
|
||||
user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
|
||||
ctx->getDelayNS(user.budget));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
// Get a value from a map-style container, returning default if value is not
|
||||
// found
|
||||
template <typename Container, typename KeyType, typename ValueType>
|
||||
ValueType get_or_default(const Container &ct, const KeyType &key,
|
||||
ValueType def = ValueType())
|
||||
ValueType get_or_default(const Container &ct, const KeyType &key, ValueType def = ValueType())
|
||||
{
|
||||
auto found = ct.find(key);
|
||||
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
|
||||
// default if value is not found
|
||||
template <typename Container, typename KeyType>
|
||||
int int_or_default(const Container &ct, const KeyType &key, int def = 0)
|
||||
template <typename Container, typename KeyType> int int_or_default(const Container &ct, const KeyType &key, int def = 0)
|
||||
{
|
||||
auto found = ct.find(key);
|
||||
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
|
||||
template <typename K, typename V>
|
||||
std::map<K, V> sorted(const std::unordered_map<K, V> &orig)
|
||||
template <typename K, typename V> std::map<K, V> sorted(const std::unordered_map<K, V> &orig)
|
||||
{
|
||||
return std::map<K, V>(orig.begin(), orig.end());
|
||||
};
|
||||
|
@ -23,10 +23,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
PlaceValidityChecker::PlaceValidityChecker(Context *ctx) {}
|
||||
|
||||
bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel) { return true; }
|
||||
|
||||
bool PlaceValidityChecker::isBelLocationValid(BelId bel) { return true; }
|
||||
|
||||
|
@ -25,16 +25,13 @@
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
PlaceValidityChecker::PlaceValidityChecker(Context *ctx)
|
||||
: ctx(ctx), id_icestorm_lc(ctx, "ICESTORM_LC"), id_sb_io(ctx, "SB_IO"),
|
||||
id_sb_gb(ctx, "SB_GB"), id_cen(ctx, "CEN"), id_clk(ctx, "CLK"),
|
||||
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")
|
||||
: ctx(ctx), id_icestorm_lc(ctx, "ICESTORM_LC"), id_sb_io(ctx, "SB_IO"), id_sb_gb(ctx, "SB_GB"),
|
||||
id_cen(ctx, "CEN"), id_clk(ctx, "CLK"), 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")
|
||||
{
|
||||
}
|
||||
|
||||
static const NetInfo *get_net_or_empty(const CellInfo *cell,
|
||||
const IdString port)
|
||||
static const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
|
||||
{
|
||||
auto found = cell->ports.find(port);
|
||||
if (found != cell->ports.end())
|
||||
@ -43,8 +40,7 @@ static const NetInfo *get_net_or_empty(const CellInfo *cell,
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
bool PlaceValidityChecker::logicCellsCompatible(
|
||||
const Context *ctx, const std::vector<const CellInfo *> &cells)
|
||||
bool PlaceValidityChecker::logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells)
|
||||
{
|
||||
bool dffs_exist = false, dffs_neg = false;
|
||||
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),
|
||||
*i1 = get_net_or_empty(cell, id_i1),
|
||||
*i2 = get_net_or_empty(cell, id_i2),
|
||||
*i3 = get_net_or_empty(cell, id_i3);
|
||||
const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1),
|
||||
*i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3);
|
||||
if (i0 != nullptr)
|
||||
locals_count++;
|
||||
if (i1 != nullptr)
|
||||
@ -140,15 +134,13 @@ bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel)
|
||||
} else if (cell->type == id_sb_gb) {
|
||||
bool is_reset = false, is_cen = false;
|
||||
assert(cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net != nullptr);
|
||||
for (auto user :
|
||||
cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net->users) {
|
||||
for (auto user : cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net->users) {
|
||||
if (is_reset_port(ctx, user))
|
||||
is_reset = true;
|
||||
if (is_enable_port(ctx, user))
|
||||
is_cen = true;
|
||||
}
|
||||
IdString glb_net = ctx->getWireName(
|
||||
ctx->getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||
IdString glb_net = ctx->getWireName(ctx->getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||
int glb_id = std::stoi(std::string("") + glb_net.str(ctx).back());
|
||||
if (is_reset && is_cen)
|
||||
return false;
|
||||
|
@ -39,8 +39,7 @@ class PlaceValidityChecker
|
||||
bool isBelLocationValid(BelId bel);
|
||||
|
||||
private:
|
||||
bool logicCellsCompatible(const Context *ctx,
|
||||
const std::vector<const CellInfo *> &cells);
|
||||
bool logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells);
|
||||
Context *ctx;
|
||||
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
||||
IdString id_cen, id_clk, id_sr;
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
const ConfigEntryPOD &find_config(const TileInfoPOD &tile,
|
||||
const std::string &name)
|
||||
const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const std::string &name)
|
||||
{
|
||||
for (int i = 0; i < tile.num_config_entries; i++) {
|
||||
if (std::string(tile.entries[i].name.get()) == name) {
|
||||
@ -39,8 +38,7 @@ const ConfigEntryPOD &find_config(const TileInfoPOD &tile,
|
||||
assert(false);
|
||||
}
|
||||
|
||||
std::tuple<int8_t, int8_t, int8_t> get_ieren(const BitstreamInfoPOD &bi,
|
||||
int8_t x, int8_t y, int8_t z)
|
||||
std::tuple<int8_t, int8_t, int8_t> get_ieren(const BitstreamInfoPOD &bi, int8_t x, int8_t y, int8_t z)
|
||||
{
|
||||
for (int i = 0; i < bi.num_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);
|
||||
};
|
||||
|
||||
void set_config(const TileInfoPOD &ti,
|
||||
std::vector<std::vector<int8_t>> &tile_cfg,
|
||||
const std::string &name, bool value, int index = -1)
|
||||
void set_config(const TileInfoPOD &ti, std::vector<std::vector<int8_t>> &tile_cfg, const std::string &name, bool value,
|
||||
int index = -1)
|
||||
{
|
||||
const ConfigEntryPOD &cfg = find_config(ti, name);
|
||||
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);
|
||||
cbit = value;
|
||||
if (cbit && !value)
|
||||
log_error("clearing already set config bit %s[%d]", name.c_str(),
|
||||
index);
|
||||
log_error("clearing already set config bit %s[%d]", name.c_str(), index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +78,7 @@ int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0)
|
||||
return defval;
|
||||
}
|
||||
|
||||
std::string get_param_str_or_def(const CellInfo *cell, const IdString param,
|
||||
std::string defval = "")
|
||||
std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std::string defval = "")
|
||||
{
|
||||
auto found = cell->params.find(param);
|
||||
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 SwitchInfoPOD &swi = bi.switches[pi.switch_index];
|
||||
for (int i = 0; i < swi.num_bits; i++) {
|
||||
bool val =
|
||||
(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);
|
||||
bool val = (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);
|
||||
if (bool(cbit) != 0)
|
||||
assert(false);
|
||||
cbit = val;
|
||||
@ -152,24 +143,19 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
for (auto cell : ctx->cells) {
|
||||
BelId bel = cell.second->bel;
|
||||
if (bel == BelId()) {
|
||||
std::cout << "Found unplaced cell " << cell.first.str(ctx)
|
||||
<< " while generating bitstream!" << std::endl;
|
||||
std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
int x = beli.x, y = beli.y, z = beli.z;
|
||||
if (cell.second->type == ctx->id("ICESTORM_LC")) {
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
|
||||
unsigned lut_init =
|
||||
get_param_or_def(cell.second, ctx->id("LUT_INIT"));
|
||||
unsigned 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 dff_enable =
|
||||
get_param_or_def(cell.second, ctx->id("DFF_ENABLE"));
|
||||
bool 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 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 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"));
|
||||
std::vector<bool> lc(20, false);
|
||||
// From arachne-pnr
|
||||
static std::vector<int> lut_perm = {
|
||||
@ -185,23 +171,17 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
lc.at(19) = async_sr;
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z),
|
||||
lc.at(i), i);
|
||||
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), lc.at(i), i);
|
||||
if (dff_enable)
|
||||
set_config(ti, config.at(y).at(x), "NegClk", neg_clk);
|
||||
} else if (cell.second->type == ctx->id("SB_IO")) {
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||
unsigned 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"));
|
||||
unsigned 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 pullup = get_param_or_def(cell.second, ctx->id("PULLUP"));
|
||||
for (int i = 0; i < 6; i++) {
|
||||
bool val = (pin_type >> i) & 0x01;
|
||||
set_config(ti, config.at(y).at(x),
|
||||
"IOB_" + std::to_string(z) + ".PINTYPE_" +
|
||||
std::to_string(i),
|
||||
val);
|
||||
set_config(ti, config.at(y).at(x), "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i), val);
|
||||
}
|
||||
|
||||
auto ieren = get_ieren(bi, x, y, z);
|
||||
@ -210,33 +190,24 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
assert(iez != -1);
|
||||
|
||||
bool input_en = false;
|
||||
if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] !=
|
||||
IdString()) ||
|
||||
(ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] !=
|
||||
IdString())) {
|
||||
if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) ||
|
||||
(ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) {
|
||||
input_en = true;
|
||||
}
|
||||
|
||||
if (ctx->args.type == ArchArgs::LP1K ||
|
||||
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),
|
||||
"IoCtrl.REN_" + std::to_string(iez), !pullup);
|
||||
if (ctx->args.type == ArchArgs::LP1K || 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), "IoCtrl.REN_" + std::to_string(iez), !pullup);
|
||||
} else {
|
||||
set_config(ti, config.at(iey).at(iex),
|
||||
"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.IE_" + std::to_string(iez), input_en);
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup);
|
||||
}
|
||||
|
||||
if (ctx->args.type == ArchArgs::UP5K) {
|
||||
if (iez == 0) {
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39",
|
||||
!pullup);
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", !pullup);
|
||||
} else if (iez == 1) {
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35",
|
||||
!pullup);
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", !pullup);
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT];
|
||||
const TileInfoPOD &ti_ramb = bi.tiles_nonrouting[TILE_RAMB];
|
||||
if (!(ctx->args.type == ArchArgs::LP1K ||
|
||||
ctx->args.type == ArchArgs::HX1K)) {
|
||||
set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp",
|
||||
true);
|
||||
if (!(ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) {
|
||||
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_w = get_param_or_def(cell.second, ctx->id("NEG_CLK_W"));
|
||||
int write_mode =
|
||||
get_param_or_def(cell.second, ctx->id("WRITE_MODE"));
|
||||
int 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"));
|
||||
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), "RamConfig.CBIT_0",
|
||||
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_2",
|
||||
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")) {
|
||||
set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_0", 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_2", 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
|
||||
} else {
|
||||
assert(false);
|
||||
@ -276,8 +239,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
}
|
||||
// Set config bits in unused IO and RAM
|
||||
for (auto bel : ctx->getBels()) {
|
||||
if (ctx->bel_to_cell[bel.index] == IdString() &&
|
||||
ctx->getBelType(bel) == TYPE_SB_IO) {
|
||||
if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) {
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
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;
|
||||
std::tie(iex, iey, iez) = ieren;
|
||||
if (iez != -1) {
|
||||
if (ctx->args.type == ArchArgs::LP1K ||
|
||||
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),
|
||||
"IoCtrl.REN_" + std::to_string(iez), false);
|
||||
if (ctx->args.type == ArchArgs::LP1K || 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), "IoCtrl.REN_" + std::to_string(iez), false);
|
||||
}
|
||||
}
|
||||
} else if (ctx->bel_to_cell[bel.index] == IdString() &&
|
||||
ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
|
||||
} else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
int x = beli.x, y = beli.y;
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB];
|
||||
if ((ctx->args.type == ArchArgs::LP1K ||
|
||||
ctx->args.type == ArchArgs::HX1K)) {
|
||||
if ((ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) {
|
||||
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)
|
||||
bool setColBufCtrl = true;
|
||||
if (ctx->args.type == ArchArgs::LP1K ||
|
||||
ctx->args.type == ArchArgs::HX1K) {
|
||||
if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) {
|
||||
if (tile == TILE_RAMB || tile == TILE_RAMT) {
|
||||
setColBufCtrl = (y == 3 || y == 5 || y == 11 || y == 13);
|
||||
} else {
|
||||
setColBufCtrl = (y == 4 || y == 5 || y == 12 || y == 13);
|
||||
}
|
||||
} else if (ctx->args.type == ArchArgs::LP8K ||
|
||||
ctx->args.type == ArchArgs::HX8K) {
|
||||
} else if (ctx->args.type == ArchArgs::LP8K || ctx->args.type == ArchArgs::HX8K) {
|
||||
setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25);
|
||||
} else if (ctx->args.type == ArchArgs::UP5K) {
|
||||
setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 ||
|
||||
y == 26 || y == 27);
|
||||
setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || y == 26 || y == 27);
|
||||
}
|
||||
if (setColBufCtrl) {
|
||||
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0",
|
||||
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_2",
|
||||
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_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);
|
||||
set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0", 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_2", 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_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
|
||||
if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 ||
|
||||
tile == TILE_DSP3 || tile == TILE_IPCON) {
|
||||
if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 || tile == TILE_DSP3 ||
|
||||
tile == TILE_IPCON) {
|
||||
if (ctx->args.type == ArchArgs::UP5K && x == 25 && y == 14) {
|
||||
// Mystery bits not set in this one tile
|
||||
} else {
|
||||
for (int lc_idx = 0; lc_idx < 8; lc_idx++) {
|
||||
static const std::vector<int> ip_dsp_lut_perm = {
|
||||
4, 14, 15, 5, 6, 16, 17, 7,
|
||||
3, 13, 12, 2, 1, 11, 10, 0,
|
||||
4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0,
|
||||
};
|
||||
for (int i = 0; i < 16; i++)
|
||||
set_config(ti, config.at(y).at(x),
|
||||
"LC_" + std::to_string(lc_idx),
|
||||
((i % 8) >= 4), ip_dsp_lut_perm.at(i));
|
||||
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(lc_idx), ((i % 8) >= 4),
|
||||
ip_dsp_lut_perm.at(i));
|
||||
if (tile == TILE_IPCON)
|
||||
set_config(ti, config.at(y).at(x),
|
||||
"Cascade.IPCON_LC0" +
|
||||
std::to_string(lc_idx) +
|
||||
"_inmux02_5",
|
||||
true);
|
||||
"Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true);
|
||||
else
|
||||
set_config(ti, config.at(y).at(x),
|
||||
"Cascade.MULT" +
|
||||
std::to_string(
|
||||
int(tile - TILE_DSP0)) +
|
||||
"_LC0" + std::to_string(lc_idx) +
|
||||
"_inmux02_5",
|
||||
"Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" +
|
||||
std::to_string(lc_idx) + "_inmux02_5",
|
||||
true);
|
||||
}
|
||||
}
|
||||
@ -441,17 +379,15 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
out << ".ram_data " << x << " " << y << std::endl;
|
||||
for (int w = 0; w < 16; w++) {
|
||||
std::vector<bool> bits(256);
|
||||
std::string init = get_param_str_or_def(
|
||||
cell.second,
|
||||
ctx->id(std::string("INIT_") + get_hexdigit(w)));
|
||||
std::string init =
|
||||
get_param_str_or_def(cell.second, ctx->id(std::string("INIT_") + get_hexdigit(w)));
|
||||
assert(init != "");
|
||||
for (size_t i = 0; i < init.size(); i++) {
|
||||
bool val = (init.at((init.size() - 1) - i) == '1');
|
||||
bits.at(i) = val;
|
||||
}
|
||||
for (int i = bits.size() - 4; i >= 0; i -= 4) {
|
||||
int c = bits.at(i) + (bits.at(i + 1) << 1) +
|
||||
(bits.at(i + 2) << 2) + (bits.at(i + 3) << 3);
|
||||
int c = bits.at(i) + (bits.at(i + 1) << 1) + (bits.at(i + 2) << 2) + (bits.at(i + 3) << 3);
|
||||
out << char(std::tolower(get_hexdigit(c)));
|
||||
}
|
||||
out << std::endl;
|
||||
|
@ -24,8 +24,7 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void add_port(const Context *ctx, CellInfo *cell, std::string name,
|
||||
PortType dir)
|
||||
void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir)
|
||||
{
|
||||
IdString id = ctx->id(name);
|
||||
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;
|
||||
CellInfo *new_cell = new CellInfo();
|
||||
if (name.empty()) {
|
||||
new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" +
|
||||
std::to_string(auto_idx++));
|
||||
new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++));
|
||||
} else {
|
||||
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,
|
||||
bool pass_thru_lut)
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
||||
{
|
||||
lc->params[ctx->id("DFF_ENABLE")] = "1";
|
||||
std::string config = dff->type.str(ctx).substr(6);
|
||||
@ -214,11 +211,8 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio)
|
||||
assert(false);
|
||||
}
|
||||
NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net;
|
||||
CellInfo *tbuf =
|
||||
net_driven_by(ctx, donet,
|
||||
[](const Context *ctx, const CellInfo *cell) {
|
||||
return cell->type == ctx->id("$_TBUF_");
|
||||
},
|
||||
CellInfo *tbuf = net_driven_by(
|
||||
ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); },
|
||||
ctx->id("Y"));
|
||||
if (tbuf) {
|
||||
sbio->params[ctx->id("PIN_TYPE")] = "41";
|
||||
@ -226,8 +220,7 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio)
|
||||
replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE"));
|
||||
ctx->nets.erase(donet->name);
|
||||
if (!donet->users.empty())
|
||||
log_error(
|
||||
"unsupported tristate IO pattern for IO buffer '%s', "
|
||||
log_error("unsupported tristate IO pattern for IO buffer '%s', "
|
||||
"instantiate SB_IO manually to ensure correct behaviour\n",
|
||||
nxio->name.c_str(ctx));
|
||||
ctx->cells.erase(tbuf->name);
|
||||
|
@ -30,89 +30,53 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name = "");
|
||||
|
||||
// Return true if a cell is a LUT
|
||||
inline bool is_lut(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_LUT4");
|
||||
}
|
||||
inline bool is_lut(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); }
|
||||
|
||||
// Return true if a cell is a flipflop
|
||||
inline bool is_ff(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_DFF") ||
|
||||
cell->type == ctx->id("SB_DFFE") ||
|
||||
cell->type == ctx->id("SB_DFFSR") ||
|
||||
cell->type == ctx->id("SB_DFFR") ||
|
||||
cell->type == ctx->id("SB_DFFSS") ||
|
||||
cell->type == ctx->id("SB_DFFS") ||
|
||||
cell->type == ctx->id("SB_DFFESR") ||
|
||||
cell->type == ctx->id("SB_DFFER") ||
|
||||
cell->type == ctx->id("SB_DFFESS") ||
|
||||
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");
|
||||
return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") ||
|
||||
cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") ||
|
||||
cell->type == ctx->id("SB_DFFESR") || cell->type == ctx->id("SB_DFFER") ||
|
||||
cell->type == ctx->id("SB_DFFESS") || 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)
|
||||
{
|
||||
return cell->type == ctx->id("SB_CARRY");
|
||||
}
|
||||
inline bool is_carry(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); }
|
||||
|
||||
inline bool is_lc(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("ICESTORM_LC");
|
||||
}
|
||||
inline bool is_lc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); }
|
||||
|
||||
// Return true if a cell is a SB_IO
|
||||
inline bool is_sb_io(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_IO");
|
||||
}
|
||||
inline bool is_sb_io(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); }
|
||||
|
||||
// Return true if a cell is a global buffer
|
||||
inline bool is_gbuf(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_GB");
|
||||
}
|
||||
inline bool is_gbuf(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); }
|
||||
|
||||
// Return true if a cell is a RAM
|
||||
inline bool is_ram(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_RAM40_4K") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNR") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNW") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNRNW");
|
||||
return cell->type == ctx->id("SB_RAM40_4K") || cell->type == ctx->id("SB_RAM40_4KNR") ||
|
||||
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)
|
||||
{
|
||||
return cell->type == ctx->id("SB_LFOSC");
|
||||
}
|
||||
inline bool is_sb_lfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LFOSC"); }
|
||||
|
||||
inline bool is_sb_hfosc(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_HFOSC");
|
||||
}
|
||||
inline bool is_sb_hfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_HFOSC"); }
|
||||
|
||||
// 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
|
||||
// can be reconnected
|
||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc,
|
||||
bool no_dff = true);
|
||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = true);
|
||||
|
||||
// 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
|
||||
// be configured as pass through and D connected to I0, otherwise D will be
|
||||
// ignored
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc,
|
||||
bool pass_thru_lut = false);
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||
|
||||
// Convert a nextpnr IO buffer to a SB_IO
|
||||
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio);
|
||||
|
148
ice40/pack.cc
148
ice40/pack.cc
@ -38,18 +38,14 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx),
|
||||
ci->type.c_str(ctx));
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
if (is_lut(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"),
|
||||
ci->name.str(ctx) + "_LC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_LC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
// See if we can pack into a DFF
|
||||
// TODO: LUT cascade
|
||||
NetInfo *o = ci->ports.at(ctx->id("O")).net;
|
||||
@ -60,8 +56,7 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
if (ctx->verbose)
|
||||
log_info("found attached dff %s\n", dff->name.c_str(ctx));
|
||||
auto dff_bel = dff->attrs.find(ctx->id("BEL"));
|
||||
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() &&
|
||||
lut_bel->second != dff_bel->second) {
|
||||
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
|
||||
// Locations don't match, can't pack
|
||||
} else {
|
||||
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_cells.insert(dff->name);
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n",
|
||||
dff->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
packed_dff = true;
|
||||
}
|
||||
}
|
||||
@ -100,13 +94,10 @@ static void pack_nonlut_ffs(Context *ctx)
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ff(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"),
|
||||
ci->name.str(ctx) + "_DFFLC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_DFFLC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
dff_to_lc(ctx, ci, packed, true);
|
||||
@ -131,15 +122,11 @@ static void pack_carries(Context *ctx)
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_carry(ctx, ci)) {
|
||||
packed_cells.insert(cell.first);
|
||||
CellInfo *carry_ci_lc =
|
||||
net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc,
|
||||
ctx->id("I3"), false);
|
||||
CellInfo *carry_ci_lc = 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)
|
||||
log_error("SB_CARRY '%s' has disconnected port I0\n",
|
||||
cell.first.c_str(ctx));
|
||||
log_error("SB_CARRY '%s' has disconnected port I0\n", cell.first.c_str(ctx));
|
||||
if (!ci->ports.at(ctx->id("I1")).net)
|
||||
log_error("SB_CARRY '%s' has disconnected port I1\n",
|
||||
cell.first.c_str(ctx));
|
||||
log_error("SB_CARRY '%s' has disconnected port I1\n", cell.first.c_str(ctx));
|
||||
|
||||
std::unordered_set<IdString> i0_matches, i1_matches;
|
||||
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);
|
||||
}
|
||||
std::set<IdString> carry_lcs;
|
||||
std::set_intersection(i0_matches.begin(), i0_matches.end(),
|
||||
i1_matches.begin(), i1_matches.end(),
|
||||
std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(),
|
||||
std::inserter(carry_lcs, carry_lcs.begin()));
|
||||
CellInfo *carry_lc = nullptr;
|
||||
if (carry_ci_lc) {
|
||||
@ -167,8 +153,7 @@ static void pack_carries(Context *ctx)
|
||||
carry_lc = carry_ci_lc;
|
||||
} else {
|
||||
if (carry_lcs.empty())
|
||||
log_error(
|
||||
"SB_CARRY '%s' cannot be packed into any logic "
|
||||
log_error("SB_CARRY '%s' cannot be packed into any logic "
|
||||
"cell (no logic cell connects to both I0 and I1)\n",
|
||||
cell.first.c_str(ctx));
|
||||
carry_lc = ctx->cells.at(*carry_lcs.begin());
|
||||
@ -177,16 +162,12 @@ static void pack_carries(Context *ctx)
|
||||
replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN"));
|
||||
replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT"));
|
||||
|
||||
i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(),
|
||||
[ci, ctx](const PortRef &pr) {
|
||||
return pr.cell == ci &&
|
||||
pr.port == ctx->id("I0");
|
||||
i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) {
|
||||
return pr.cell == ci && pr.port == ctx->id("I0");
|
||||
}));
|
||||
|
||||
i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(),
|
||||
[ci, ctx](const PortRef &pr) {
|
||||
return pr.cell == ci &&
|
||||
pr.port == ctx->id("I1");
|
||||
i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx](const PortRef &pr) {
|
||||
return pr.cell == ci && pr.port == ctx->id("I1");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -206,30 +187,24 @@ static void pack_ram(Context *ctx)
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ram(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_RAM"),
|
||||
ci->name.str(ctx) + "_RAM");
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM");
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
for (auto param : ci->params)
|
||||
packed->params[param.first] = param.second;
|
||||
packed->params[ctx->id("NEG_CLK_W")] =
|
||||
std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") ||
|
||||
ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||
std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||
packed->params[ctx->id("NEG_CLK_R")] =
|
||||
std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") ||
|
||||
ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||
std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW"));
|
||||
packed->type = ctx->id("ICESTORM_RAM");
|
||||
for (auto port : ci->ports) {
|
||||
PortInfo &pi = port.second;
|
||||
std::string newname = pi.name.str(ctx);
|
||||
size_t bpos = newname.find('[');
|
||||
if (bpos != std::string::npos) {
|
||||
newname = newname.substr(0, bpos) + "_" +
|
||||
newname.substr(bpos + 1,
|
||||
(newname.size() - bpos) - 2);
|
||||
newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2);
|
||||
}
|
||||
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed,
|
||||
ctx->id(newname));
|
||||
replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed, ctx->id(newname));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,18 +218,15 @@ static void pack_ram(Context *ctx)
|
||||
}
|
||||
|
||||
// Merge a net into a constant net
|
||||
static void set_net_constant(const Context *ctx, NetInfo *orig,
|
||||
NetInfo *constnet, bool constval)
|
||||
static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
|
||||
{
|
||||
orig->driver.cell = nullptr;
|
||||
for (auto user : orig->users) {
|
||||
if (user.cell != nullptr) {
|
||||
CellInfo *uc = user.cell;
|
||||
if (ctx->verbose)
|
||||
log_info("%s user %s\n", orig->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) {
|
||||
log_info("%s user %s\n", orig->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) {
|
||||
uc->ports[user.port].net = nullptr;
|
||||
} else {
|
||||
uc->ports[user.port].net = constnet;
|
||||
@ -270,16 +242,14 @@ static void pack_constants(Context *ctx)
|
||||
{
|
||||
log_info("Packing constants..\n");
|
||||
|
||||
CellInfo *gnd_cell =
|
||||
create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND");
|
||||
CellInfo *gnd_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND");
|
||||
gnd_cell->params[ctx->id("LUT_INIT")] = "0";
|
||||
NetInfo *gnd_net = new NetInfo;
|
||||
gnd_net->name = ctx->id("$PACKER_GND_NET");
|
||||
gnd_net->driver.cell = gnd_cell;
|
||||
gnd_net->driver.port = ctx->id("O");
|
||||
|
||||
CellInfo *vcc_cell =
|
||||
create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC");
|
||||
CellInfo *vcc_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC");
|
||||
vcc_cell->params[ctx->id("LUT_INIT")] = "1";
|
||||
NetInfo *vcc_net = new NetInfo;
|
||||
vcc_net->name = ctx->id("$PACKER_VCC_NET");
|
||||
@ -292,13 +262,11 @@ static void pack_constants(Context *ctx)
|
||||
|
||||
for (auto net : sorted(ctx->nets)) {
|
||||
NetInfo *ni = net.second;
|
||||
if (ni->driver.cell != nullptr &&
|
||||
ni->driver.cell->type == ctx->id("GND")) {
|
||||
if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
|
||||
set_net_constant(ctx, ni, gnd_net, false);
|
||||
gnd_used = true;
|
||||
dead_nets.push_back(net.first);
|
||||
} else if (ni->driver.cell != nullptr &&
|
||||
ni->driver.cell->type == ctx->id("VCC")) {
|
||||
} else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
|
||||
set_net_constant(ctx, ni, vcc_net, true);
|
||||
vcc_used = true;
|
||||
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)
|
||||
{
|
||||
return cell->type == ctx->id("$nextpnr_ibuf") ||
|
||||
cell->type == ctx->id("$nextpnr_obuf") ||
|
||||
return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
|
||||
cell->type == ctx->id("$nextpnr_iobuf");
|
||||
}
|
||||
|
||||
@ -338,22 +305,16 @@ static void pack_io(Context *ctx)
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_nextpnr_iob(ctx, ci)) {
|
||||
CellInfo *sb = nullptr;
|
||||
if (ci->type == ctx->id("$nextpnr_ibuf") ||
|
||||
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);
|
||||
if (ci->type == ctx->id("$nextpnr_ibuf") || 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);
|
||||
|
||||
} else if (ci->type == ctx->id("$nextpnr_obuf")) {
|
||||
sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net,
|
||||
is_sb_io, ctx->id("PACKAGE_PIN"), true,
|
||||
ci);
|
||||
sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci);
|
||||
}
|
||||
if (sb != nullptr) {
|
||||
// Trivial case, SB_IO used. Just destroy the net and the
|
||||
// iobuf
|
||||
log_info("%s feeds SB_IO %s, removing %s %s.\n",
|
||||
ci->name.c_str(ctx), sb->name.c_str(ctx),
|
||||
log_info("%s feeds SB_IO %s, removing %s %s.\n", ci->name.c_str(ctx), sb->name.c_str(ctx),
|
||||
ci->type.c_str(ctx), ci->name.c_str(ctx));
|
||||
NetInfo *net = sb->ports.at(ctx->id("PACKAGE_PIN")).net;
|
||||
if (net != nullptr) {
|
||||
@ -362,14 +323,12 @@ static void pack_io(Context *ctx)
|
||||
}
|
||||
} else {
|
||||
// Create a SB_IO buffer
|
||||
sb = create_ice_cell(ctx, ctx->id("SB_IO"),
|
||||
ci->name.str(ctx) + "$sb_io");
|
||||
sb = create_ice_cell(ctx, ctx->id("SB_IO"), ci->name.str(ctx) + "$sb_io");
|
||||
nxio_to_sb(ctx, ci, sb);
|
||||
new_cells.push_back(sb);
|
||||
}
|
||||
packed_cells.insert(ci->name);
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
std::inserter(sb->attrs, sb->attrs.begin()));
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(sb->attrs, sb->attrs.begin()));
|
||||
}
|
||||
}
|
||||
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,
|
||||
bool is_cen)
|
||||
static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen)
|
||||
{
|
||||
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") +
|
||||
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||
std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||
CellInfo *gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name);
|
||||
gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net;
|
||||
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;
|
||||
std::vector<PortRef> keep_users;
|
||||
for (auto user : net->users) {
|
||||
if (is_clock_port(ctx, user) ||
|
||||
(is_reset && is_reset_port(ctx, user)) ||
|
||||
if (is_clock_port(ctx, user) || (is_reset && is_reset_port(ctx, user)) ||
|
||||
(is_cen && is_enable_port(ctx, user))) {
|
||||
user.cell->ports[user.port].net = glbnet;
|
||||
glbnet->users.push_back(user);
|
||||
@ -443,23 +399,17 @@ static void promote_globals(Context *ctx)
|
||||
if (is_gbuf(ctx, cell.second))
|
||||
--gbs_available;
|
||||
while (prom_globals < gbs_available) {
|
||||
auto global_clock =
|
||||
std::max_element(clock_count.begin(), clock_count.end(),
|
||||
[](const std::pair<IdString, int> &a,
|
||||
const std::pair<IdString, int> &b) {
|
||||
auto global_clock = std::max_element(clock_count.begin(), clock_count.end(),
|
||||
[](const std::pair<IdString, int> &a, const std::pair<IdString, int> &b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
|
||||
auto global_reset =
|
||||
std::max_element(reset_count.begin(), reset_count.end(),
|
||||
[](const std::pair<IdString, int> &a,
|
||||
const std::pair<IdString, int> &b) {
|
||||
auto global_reset = std::max_element(reset_count.begin(), reset_count.end(),
|
||||
[](const std::pair<IdString, int> &a, 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 = 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) {
|
||||
@ -502,15 +452,13 @@ static void pack_intosc(Context *ctx)
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_sb_lfosc(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"),
|
||||
ci->name.str(ctx) + "_OSC");
|
||||
CellInfo *packed = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC");
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
replace_port(ci, ctx->id("CLKLFEN"), packed, ctx->id("CLKLFEN"));
|
||||
replace_port(ci, ctx->id("CLKLFPU"), packed, ctx->id("CLKLFPU"));
|
||||
if (bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))) {
|
||||
replace_port(ci, ctx->id("CLKLF"), packed,
|
||||
ctx->id("CLKLF_FABRIC"));
|
||||
replace_port(ci, ctx->id("CLKLF"), packed, ctx->id("CLKLF_FABRIC"));
|
||||
} else {
|
||||
replace_port(ci, ctx->id("CLKLF"), packed, ctx->id("CLKLF"));
|
||||
}
|
||||
|
@ -47,8 +47,7 @@ bool apply_pcf(Context *ctx, std::istream &in)
|
||||
std::string cmd = words.at(0);
|
||||
if (cmd == "set_io") {
|
||||
size_t args_end = 1;
|
||||
while (args_end < words.size() &&
|
||||
words.at(args_end).at(0) == '-')
|
||||
while (args_end < words.size() && words.at(args_end).at(0) == '-')
|
||||
args_end++;
|
||||
std::string cell = words.at(args_end);
|
||||
std::string pin = words.at(args_end + 1);
|
||||
@ -58,10 +57,8 @@ bool apply_pcf(Context *ctx, std::istream &in)
|
||||
} else {
|
||||
BelId pin_bel = ctx->getPackagePinBel(pin);
|
||||
if (pin_bel == BelId())
|
||||
log_error("package does not have a pin named %s\n",
|
||||
pin.c_str());
|
||||
fnd_cell->second->attrs[ctx->id("BEL")] =
|
||||
ctx->getBelName(pin_bel).str(ctx);
|
||||
log_error("package does not have a pin named %s\n", pin.c_str());
|
||||
fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(pin_bel).str(ctx);
|
||||
log_info("constrained '%s' to bel '%s'\n", cell.c_str(),
|
||||
fnd_cell->second->attrs[ctx->id("BEL")].c_str());
|
||||
}
|
||||
|
@ -45,9 +45,7 @@ void arch_wrap_python()
|
||||
|
||||
class_<PipId>("PipId").def_readwrite("index", &PipId::index);
|
||||
|
||||
class_<BelPin>("BelPin")
|
||||
.def_readwrite("bel", &BelPin::bel)
|
||||
.def_readwrite("pin", &BelPin::pin);
|
||||
class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin);
|
||||
|
||||
enum_<PortPin>("PortPin")
|
||||
#define X(t) .value("PIN_" #t, PIN_##t)
|
||||
|
Loading…
Reference in New Issue
Block a user