ecp5: Proof-of-concept using IdStringList for bel names
This uses the new IdStringList API to store bel names for the ECP5. Note that other arches and the GUI do not yet build with this proof-of-concept patch. getBelByName still uses the old implementation and could be more efficiently implemented with further development. Signed-off-by: D. Shah <dave@ds0.me>
This commit is contained in:
parent
0dbe7f96a3
commit
6d23461bcd
@ -36,10 +36,10 @@ void archcheck_names(const Context *ctx)
|
|||||||
|
|
||||||
log_info("Checking bel names..\n");
|
log_info("Checking bel names..\n");
|
||||||
for (BelId bel : ctx->getBels()) {
|
for (BelId bel : ctx->getBels()) {
|
||||||
IdString name = ctx->getBelName(bel);
|
IdStringList name = ctx->getBelName(bel);
|
||||||
BelId bel2 = ctx->getBelByName(name);
|
BelId bel2 = ctx->getBelByName(name);
|
||||||
if (bel != bel2) {
|
if (bel != bel2) {
|
||||||
log_error("bel != bel2, name = %s\n", name.c_str(ctx));
|
log_error("bel != bel2, name = %s\n", ctx->nameOfBel(bel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,14 @@ TimingConstrObjectId BaseCtx::timingWildcardObject()
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string &StrRingBuffer::next()
|
||||||
|
{
|
||||||
|
std::string &s = buffer.at(index++);
|
||||||
|
if (index >= N)
|
||||||
|
index = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
TimingConstrObjectId BaseCtx::timingClockDomainObject(NetInfo *clockDomain)
|
TimingConstrObjectId BaseCtx::timingClockDomainObject(NetInfo *clockDomain)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(clockDomain->clkconstr != nullptr);
|
NPNR_ASSERT(clockDomain->clkconstr != nullptr);
|
||||||
@ -283,7 +291,9 @@ void BaseCtx::removeConstraint(IdString constrName)
|
|||||||
const char *BaseCtx::nameOfBel(BelId bel) const
|
const char *BaseCtx::nameOfBel(BelId bel) const
|
||||||
{
|
{
|
||||||
const Context *ctx = getCtx();
|
const Context *ctx = getCtx();
|
||||||
return ctx->getBelName(bel).c_str(ctx);
|
std::string &s = ctx->log_strs.next();
|
||||||
|
ctx->getBelName(bel).build_str(ctx, s);
|
||||||
|
return s.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *BaseCtx::nameOfWire(WireId wire) const
|
const char *BaseCtx::nameOfWire(WireId wire) const
|
||||||
@ -304,6 +314,12 @@ const char *BaseCtx::nameOfGroup(GroupId group) const
|
|||||||
return ctx->getGroupName(group).c_str(ctx);
|
return ctx->getGroupName(group).c_str(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BelId BaseCtx::getBelByNameStr(const std::string &str)
|
||||||
|
{
|
||||||
|
Context *ctx = getCtx();
|
||||||
|
return ctx->getBelByName(IdStringList::parse(ctx, str));
|
||||||
|
}
|
||||||
|
|
||||||
WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
|
WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const
|
||||||
{
|
{
|
||||||
if (net_info->driver.cell == nullptr)
|
if (net_info->driver.cell == nullptr)
|
||||||
@ -655,7 +671,7 @@ void BaseCtx::archInfoToAttributes()
|
|||||||
if (ci->attrs.find(id("BEL")) != ci->attrs.end()) {
|
if (ci->attrs.find(id("BEL")) != ci->attrs.end()) {
|
||||||
ci->attrs.erase(ci->attrs.find(id("BEL")));
|
ci->attrs.erase(ci->attrs.find(id("BEL")));
|
||||||
}
|
}
|
||||||
ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(this);
|
ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(getCtx());
|
||||||
ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength;
|
ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength;
|
||||||
}
|
}
|
||||||
if (ci->constr_x != ci->UNCONSTR)
|
if (ci->constr_x != ci->UNCONSTR)
|
||||||
@ -707,7 +723,7 @@ void BaseCtx::attributesToArchInfo()
|
|||||||
if (str != ci->attrs.end())
|
if (str != ci->attrs.end())
|
||||||
strength = (PlaceStrength)str->second.as_int64();
|
strength = (PlaceStrength)str->second.as_int64();
|
||||||
|
|
||||||
BelId b = getCtx()->getBelByName(id(val->second.as_string()));
|
BelId b = getCtx()->getBelByNameStr(val->second.as_string());
|
||||||
getCtx()->bindBel(b, ci, strength);
|
getCtx()->bindBel(b, ci, strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,14 +148,13 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
// An small size optimised array that is statically allocated when the size is N or less; heap allocated otherwise
|
// An small size optimised array that is statically allocated when the size is N or less; heap allocated otherwise
|
||||||
template <typename T, size_t N> class SSOArray
|
template <typename T, size_t N> class SSOArray
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
T data_static[N];
|
T data_static[N];
|
||||||
T *data_heap;
|
T *data_heap;
|
||||||
};
|
};
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
|
|
||||||
private:
|
|
||||||
inline bool is_heap() const { return (m_size > N); }
|
inline bool is_heap() const { return (m_size > N); }
|
||||||
void alloc()
|
void alloc()
|
||||||
{
|
{
|
||||||
@ -224,8 +223,8 @@ struct IdStringList
|
|||||||
SSOArray<IdString, 4> ids;
|
SSOArray<IdString, 4> ids;
|
||||||
|
|
||||||
IdStringList(){};
|
IdStringList(){};
|
||||||
explicit IdStringList(size_t n) : ids(n, IdString()){};
|
IdStringList(size_t n) : ids(n, IdString()){};
|
||||||
explicit IdStringList(IdString id) : ids(1, id){};
|
IdStringList(IdString id) : ids(1, id){};
|
||||||
template <typename Tlist> IdStringList(const Tlist &list) : ids(list){};
|
template <typename Tlist> IdStringList(const Tlist &list) : ids(list){};
|
||||||
|
|
||||||
static IdStringList parse(Context *ctx, const std::string &str);
|
static IdStringList parse(Context *ctx, const std::string &str);
|
||||||
@ -238,6 +237,19 @@ struct IdStringList
|
|||||||
const IdString &operator[](size_t idx) const { return ids[idx]; }
|
const IdString &operator[](size_t idx) const { return ids[idx]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A ring buffer of strings, so we can return a simple const char * pointer for %s formatting - inspired by how logging
|
||||||
|
// in Yosys works Let's just hope noone tries to log more than 100 things in one call....
|
||||||
|
class StrRingBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const size_t N = 100;
|
||||||
|
std::array<std::string, N> buffer;
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string &next();
|
||||||
|
};
|
||||||
|
|
||||||
struct GraphicElement
|
struct GraphicElement
|
||||||
{
|
{
|
||||||
enum type_t
|
enum type_t
|
||||||
@ -760,6 +772,9 @@ struct BaseCtx
|
|||||||
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
|
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
|
||||||
mutable std::vector<const std::string *> *idstring_idx_to_str;
|
mutable std::vector<const std::string *> *idstring_idx_to_str;
|
||||||
|
|
||||||
|
// Temporary string backing store for logging
|
||||||
|
mutable StrRingBuffer log_strs;
|
||||||
|
|
||||||
// Project settings and config switches
|
// Project settings and config switches
|
||||||
std::unordered_map<IdString, Property> settings;
|
std::unordered_map<IdString, Property> settings;
|
||||||
|
|
||||||
@ -875,6 +890,9 @@ struct BaseCtx
|
|||||||
const char *nameOfPip(PipId pip) const;
|
const char *nameOfPip(PipId pip) const;
|
||||||
const char *nameOfGroup(GroupId group) const;
|
const char *nameOfGroup(GroupId group) const;
|
||||||
|
|
||||||
|
// Overrides of arch functions that take a string and handle IdStringList parsing
|
||||||
|
BelId getBelByNameStr(const std::string &str);
|
||||||
|
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
bool allUiReload = true;
|
bool allUiReload = true;
|
||||||
|
@ -158,8 +158,7 @@ bool place_single_cell(Context *ctx, CellInfo *cell, bool require_legality)
|
|||||||
all_placed = true;
|
all_placed = true;
|
||||||
}
|
}
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx),
|
log_info(" placed single cell '%s' at '%s'\n", cell->name.c_str(ctx), ctx->nameOfBel(best_bel));
|
||||||
ctx->getBelName(best_bel).c_str(ctx));
|
|
||||||
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
ctx->bindBel(best_bel, cell, STRENGTH_WEAK);
|
||||||
|
|
||||||
cell = ripup_target;
|
cell = ripup_target;
|
||||||
@ -375,7 +374,7 @@ class ConstraintLegaliseWorker
|
|||||||
if (confl_cell != nullptr) {
|
if (confl_cell != nullptr) {
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info(" '%s' already placed at '%s'\n", ctx->nameOf(confl_cell),
|
log_info(" '%s' already placed at '%s'\n", ctx->nameOf(confl_cell),
|
||||||
ctx->getBelName(confl_cell->bel).c_str(ctx));
|
ctx->nameOfBel(confl_cell->bel));
|
||||||
NPNR_ASSERT(confl_cell->belStrength < STRENGTH_STRONG);
|
NPNR_ASSERT(confl_cell->belStrength < STRENGTH_STRONG);
|
||||||
ctx->unbindBel(target);
|
ctx->unbindBel(target);
|
||||||
rippedCells.insert(confl_cell->name);
|
rippedCells.insert(confl_cell->name);
|
||||||
@ -489,7 +488,7 @@ class ConstraintLegaliseWorker
|
|||||||
for (auto cell : sorted(ctx->cells))
|
for (auto cell : sorted(ctx->cells))
|
||||||
if (get_constraints_distance(ctx, cell.second) != 0)
|
if (get_constraints_distance(ctx, cell.second) != 0)
|
||||||
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
|
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
|
||||||
ctx->getBelName(cell.second->bel).c_str(ctx));
|
ctx->nameOfBel(cell.second->bel));
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -154,7 +154,7 @@ class SAPlacer
|
|||||||
auto loc = cell->attrs.find(ctx->id("BEL"));
|
auto loc = cell->attrs.find(ctx->id("BEL"));
|
||||||
if (loc != cell->attrs.end()) {
|
if (loc != cell->attrs.end()) {
|
||||||
std::string loc_name = loc->second.as_string();
|
std::string loc_name = loc->second.as_string();
|
||||||
BelId bel = ctx->getBelByName(ctx->id(loc_name));
|
BelId bel = ctx->getBelByNameStr(loc_name);
|
||||||
if (bel == BelId()) {
|
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",
|
"this chip (processing BEL attribute on \'%s\')\n",
|
||||||
@ -409,18 +409,18 @@ class SAPlacer
|
|||||||
if (ctx->force) {
|
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",
|
"(%s)\n",
|
||||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
ctx->nameOfBel(bel), cell_text.c_str());
|
||||||
} else {
|
} else {
|
||||||
log_error("post-placement validity check failed for Bel '%s' "
|
log_error("post-placement validity check failed for Bel '%s' "
|
||||||
"(%s)\n",
|
"(%s)\n",
|
||||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
ctx->nameOfBel(bel), cell_text.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto cell : sorted(ctx->cells))
|
for (auto cell : sorted(ctx->cells))
|
||||||
if (get_constraints_distance(ctx, cell.second) != 0)
|
if (get_constraints_distance(ctx, cell.second) != 0)
|
||||||
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
|
log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx),
|
||||||
ctx->getBelName(cell.second->bel).c_str(ctx));
|
ctx->nameOfBel(cell.second->bel));
|
||||||
timing_analysis(ctx);
|
timing_analysis(ctx);
|
||||||
ctx->unlock();
|
ctx->unlock();
|
||||||
return true;
|
return true;
|
||||||
|
@ -305,7 +305,7 @@ class HeAPPlacer
|
|||||||
if (ctx->getBoundBelCell(cell.second->bel) != cell.second)
|
if (ctx->getBoundBelCell(cell.second->bel) != cell.second)
|
||||||
log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx));
|
log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx));
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->getBelName(cell.second->bel).c_str(ctx));
|
log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->unlock();
|
ctx->unlock();
|
||||||
@ -379,7 +379,7 @@ class HeAPPlacer
|
|||||||
auto loc = cell->attrs.find(ctx->id("BEL"));
|
auto loc = cell->attrs.find(ctx->id("BEL"));
|
||||||
if (loc != cell->attrs.end()) {
|
if (loc != cell->attrs.end()) {
|
||||||
std::string loc_name = loc->second.as_string();
|
std::string loc_name = loc->second.as_string();
|
||||||
BelId bel = ctx->getBelByName(ctx->id(loc_name));
|
BelId bel = ctx->getBelByNameStr(loc_name);
|
||||||
if (bel == BelId()) {
|
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",
|
"this chip (processing BEL attribute on \'%s\')\n",
|
||||||
|
@ -427,7 +427,7 @@ class TimingOptimiser
|
|||||||
if (pn->users.at(i).cell == port->cell && pn->users.at(i).port == port->port)
|
if (pn->users.at(i).cell == port->cell && pn->users.at(i).port == port->port)
|
||||||
crit = net_crit.at(pn->name).criticality.at(i);
|
crit = net_crit.at(pn->name).criticality.at(i);
|
||||||
log_info(" %s.%s at %s crit %0.02f\n", port->cell->name.c_str(ctx), port->port.c_str(ctx),
|
log_info(" %s.%s at %s crit %0.02f\n", port->cell->name.c_str(ctx), port->port.c_str(ctx),
|
||||||
ctx->getBelName(port->cell->bel).c_str(ctx), crit);
|
ctx->nameOfBel(port->cell->bel), crit);
|
||||||
}
|
}
|
||||||
if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end())
|
if (std::find(path_cells.begin(), path_cells.end(), port->cell->name) != path_cells.end())
|
||||||
continue;
|
continue;
|
||||||
@ -472,10 +472,9 @@ class TimingOptimiser
|
|||||||
|
|
||||||
if (ctx->debug) {
|
if (ctx->debug) {
|
||||||
for (auto cell : path_cells) {
|
for (auto cell : path_cells) {
|
||||||
log_info("Candidate neighbours for %s (%s):\n", cell.c_str(ctx),
|
log_info("Candidate neighbours for %s (%s):\n", cell.c_str(ctx), ctx->nameOfBel(ctx->cells[cell]->bel));
|
||||||
ctx->getBelName(ctx->cells[cell]->bel).c_str(ctx));
|
|
||||||
for (auto neigh : cell_neighbour_bels.at(cell)) {
|
for (auto neigh : cell_neighbour_bels.at(cell)) {
|
||||||
log_info(" %s\n", ctx->getBelName(neigh).c_str(ctx));
|
log_info(" %s\n", ctx->nameOfBel(neigh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,7 +596,7 @@ class TimingOptimiser
|
|||||||
CellInfo *cell = ctx->cells.at(rt_entry.first).get();
|
CellInfo *cell = ctx->cells.at(rt_entry.first).get();
|
||||||
cell_swap_bel(cell, rt_entry.second);
|
cell_swap_bel(cell, rt_entry.second);
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info(" %s at %s\n", rt_entry.first.c_str(ctx), ctx->getBelName(rt_entry.second).c_str(ctx));
|
log_info(" %s at %s\n", rt_entry.first.c_str(ctx), ctx->nameOfBel(rt_entry.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
15
ecp5/arch.cc
15
ecp5/arch.cc
@ -128,6 +128,11 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
bucket.name = bel_type;
|
bucket.name = bel_type;
|
||||||
buckets.push_back(bucket);
|
buckets.push_back(bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < chip_info->width; i++)
|
||||||
|
x_ids.push_back(id(stringf("X%d", i)));
|
||||||
|
for (int i = 0; i < chip_info->height; i++)
|
||||||
|
y_ids.push_back(id(stringf("Y%d", i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@ -208,16 +213,18 @@ IdString Arch::archArgsToId(ArchArgs args) const
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
BelId Arch::getBelByName(IdString name) const
|
BelId Arch::getBelByName(IdStringList name) const
|
||||||
{
|
{
|
||||||
|
// TODO: take advantage of IdStringList for fast parsing
|
||||||
BelId ret;
|
BelId ret;
|
||||||
|
#if 0
|
||||||
auto it = bel_by_name.find(name);
|
auto it = bel_by_name.find(name);
|
||||||
if (it != bel_by_name.end())
|
if (it != bel_by_name.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
#endif
|
||||||
Location loc;
|
Location loc;
|
||||||
std::string basename;
|
std::string basename;
|
||||||
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(getCtx()));
|
||||||
ret.location = loc;
|
ret.location = loc;
|
||||||
const LocationTypePOD *loci = locInfo(ret);
|
const LocationTypePOD *loci = locInfo(ret);
|
||||||
for (int i = 0; i < int(loci->bel_data.size()); i++) {
|
for (int i = 0; i < int(loci->bel_data.size()); i++) {
|
||||||
@ -226,8 +233,10 @@ BelId Arch::getBelByName(IdString name) const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if (ret.index >= 0)
|
if (ret.index >= 0)
|
||||||
bel_by_name[name] = ret;
|
bel_by_name[name] = ret;
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
ecp5/arch.h
13
ecp5/arch.h
@ -450,6 +450,9 @@ struct Arch : BaseCtx
|
|||||||
std::unordered_map<PipId, NetInfo *> pip_to_net;
|
std::unordered_map<PipId, NetInfo *> pip_to_net;
|
||||||
std::unordered_map<WireId, int> wire_fanout;
|
std::unordered_map<WireId, int> wire_fanout;
|
||||||
|
|
||||||
|
// fast access to X and Y IdStrings for building object names
|
||||||
|
std::vector<IdString> x_ids, y_ids;
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
|
|
||||||
@ -475,19 +478,19 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
BelId getBelByName(IdString name) const;
|
BelId getBelByName(IdStringList name) const;
|
||||||
|
|
||||||
template <typename Id> const LocationTypePOD *locInfo(Id &id) const
|
template <typename Id> const LocationTypePOD *locInfo(Id &id) const
|
||||||
{
|
{
|
||||||
return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]);
|
return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBelName(BelId bel) const
|
IdStringList getBelName(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
std::stringstream name;
|
std::array<IdString, 3> ids{x_ids.at(bel.location.x), y_ids.at(bel.location.y),
|
||||||
name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get();
|
id(locInfo(bel)->bel_data[bel.index].name.get())};
|
||||||
return id(name.str());
|
return IdStringList(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||||
|
@ -30,7 +30,7 @@ namespace PythonConversion {
|
|||||||
|
|
||||||
template <> struct string_converter<BelId>
|
template <> struct string_converter<BelId>
|
||||||
{
|
{
|
||||||
BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); }
|
BelId from_str(Context *ctx, std::string name) { return ctx->getBelByNameStr(name); }
|
||||||
|
|
||||||
std::string to_str(Context *ctx, BelId id)
|
std::string to_str(Context *ctx, BelId id)
|
||||||
{
|
{
|
||||||
|
@ -176,8 +176,8 @@ class Ecp5GlobalRouter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (upstream.size() > 30000) {
|
if (upstream.size() > 30000) {
|
||||||
log_error("failed to route HPBX%02d00 to %s.%s\n", global_index,
|
log_error("failed to route HPBX%02d00 to %s.%s\n", global_index, ctx->nameOfBel(user.cell->bel),
|
||||||
ctx->getBelName(user.cell->bel).c_str(ctx), user.port.c_str(ctx));
|
user.port.c_str(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set all the pips we found along the way
|
// Set all the pips we found along the way
|
||||||
@ -300,7 +300,7 @@ class Ecp5GlobalRouter
|
|||||||
if (drv.cell == nullptr) {
|
if (drv.cell == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (drv.cell->attrs.count(ctx->id("BEL"))) {
|
} else if (drv.cell->attrs.count(ctx->id("BEL"))) {
|
||||||
drv_bel = ctx->getBelByName(ctx->id(drv.cell->attrs.at(ctx->id("BEL")).as_string()));
|
drv_bel = ctx->getBelByNameStr(drv.cell->attrs.at(ctx->id("BEL")).as_string());
|
||||||
} else {
|
} else {
|
||||||
// Check if driver is a singleton
|
// Check if driver is a singleton
|
||||||
BelId last_bel;
|
BelId last_bel;
|
||||||
|
46
ecp5/pack.cc
46
ecp5/pack.cc
@ -522,7 +522,7 @@ class Ecp5Packer
|
|||||||
trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
|
trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
|
||||||
} else {
|
} else {
|
||||||
log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
|
log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
|
||||||
ctx->getBelName(pinBel).c_str(ctx));
|
ctx->nameOfBel(pinBel));
|
||||||
}
|
}
|
||||||
trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
|
trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
|
||||||
}
|
}
|
||||||
@ -1657,7 +1657,7 @@ class Ecp5Packer
|
|||||||
CellInfo *dcu = clki->driver.cell;
|
CellInfo *dcu = clki->driver.cell;
|
||||||
if (!dcu->attrs.count(ctx->id("BEL")))
|
if (!dcu->attrs.count(ctx->id("BEL")))
|
||||||
log_error("DCU must be constrained to a Bel!\n");
|
log_error("DCU must be constrained to a Bel!\n");
|
||||||
BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")).as_string()));
|
BelId bel = ctx->getBelByNameStr(dcu->attrs.at(ctx->id("BEL")).as_string());
|
||||||
if (bel == BelId())
|
if (bel == BelId())
|
||||||
log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str());
|
log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str());
|
||||||
Loc loc = ctx->getBelLocation(bel);
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
@ -1704,7 +1704,7 @@ class Ecp5Packer
|
|||||||
for (auto cell : sorted(ctx->cells)) {
|
for (auto cell : sorted(ctx->cells)) {
|
||||||
CellInfo *ci = cell.second;
|
CellInfo *ci = cell.second;
|
||||||
if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL")))
|
if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL")))
|
||||||
available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL")).as_string())));
|
available_plls.erase(ctx->getBelByNameStr(ci->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
}
|
}
|
||||||
// Place PLL connected to fixed drivers such as IO close to their source
|
// Place PLL connected to fixed drivers such as IO close to their source
|
||||||
for (auto cell : sorted(ctx->cells)) {
|
for (auto cell : sorted(ctx->cells)) {
|
||||||
@ -1716,7 +1716,7 @@ class Ecp5Packer
|
|||||||
const CellInfo *drivercell = drivernet->driver.cell;
|
const CellInfo *drivercell = drivernet->driver.cell;
|
||||||
if (!drivercell->attrs.count(ctx->id("BEL")))
|
if (!drivercell->attrs.count(ctx->id("BEL")))
|
||||||
continue;
|
continue;
|
||||||
BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")).as_string()));
|
BelId drvbel = ctx->getBelByNameStr(drivercell->attrs.at(ctx->id("BEL")).as_string());
|
||||||
Loc drvloc = ctx->getBelLocation(drvbel);
|
Loc drvloc = ctx->getBelLocation(drvbel);
|
||||||
BelId closest_pll;
|
BelId closest_pll;
|
||||||
int closest_distance = std::numeric_limits<int>::max();
|
int closest_distance = std::numeric_limits<int>::max();
|
||||||
@ -1848,8 +1848,8 @@ class Ecp5Packer
|
|||||||
WireId next;
|
WireId next;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (upstream.empty() || upstream.size() > 30000)
|
if (upstream.empty() || upstream.size() > 30000)
|
||||||
log_error("failed to route bank %d ECLK%d to %s.%s\n", bank, found_eclk,
|
log_error("failed to route bank %d ECLK%d to %s.%s\n", bank, found_eclk, ctx->nameOfBel(usr_bel),
|
||||||
ctx->getBelName(usr_bel).c_str(ctx), usr_port.name.c_str(ctx));
|
usr_port.name.c_str(ctx));
|
||||||
next = upstream.front();
|
next = upstream.front();
|
||||||
upstream.pop();
|
upstream.pop();
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
@ -1913,17 +1913,17 @@ class Ecp5Packer
|
|||||||
log_error("DQSBUFM can only be used with a pin-constrained PIO connected to its DQSI input"
|
log_error("DQSBUFM can only be used with a pin-constrained PIO connected to its DQSI input"
|
||||||
"(while processing '%s').\n",
|
"(while processing '%s').\n",
|
||||||
ci->name.c_str(ctx));
|
ci->name.c_str(ctx));
|
||||||
BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string()));
|
BelId pio_bel = ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string());
|
||||||
NPNR_ASSERT(pio_bel != BelId());
|
NPNR_ASSERT(pio_bel != BelId());
|
||||||
Loc pio_loc = ctx->getBelLocation(pio_bel);
|
Loc pio_loc = ctx->getBelLocation(pio_bel);
|
||||||
if (pio_loc.z != 0)
|
if (pio_loc.z != 0)
|
||||||
log_error("PIO '%s' does not appear to be a DQS site (expecting an 'A' pin).\n",
|
log_error("PIO '%s' does not appear to be a DQS site (expecting an 'A' pin).\n",
|
||||||
ctx->getBelName(pio_bel).c_str(ctx));
|
ctx->nameOfBel(pio_bel));
|
||||||
pio_loc.z = 8;
|
pio_loc.z = 8;
|
||||||
BelId dqsbuf = ctx->getBelByLocation(pio_loc);
|
BelId dqsbuf = ctx->getBelByLocation(pio_loc);
|
||||||
if (dqsbuf == BelId() || ctx->getBelType(dqsbuf) != id_DQSBUFM)
|
if (dqsbuf == BelId() || ctx->getBelType(dqsbuf) != id_DQSBUFM)
|
||||||
log_error("PIO '%s' does not appear to be a DQS site (didn't find a DQSBUFM).\n",
|
log_error("PIO '%s' does not appear to be a DQS site (didn't find a DQSBUFM).\n",
|
||||||
ctx->getBelName(pio_bel).c_str(ctx));
|
ctx->nameOfBel(pio_bel));
|
||||||
ci->attrs[ctx->id("BEL")] = ctx->getBelName(dqsbuf).str(ctx);
|
ci->attrs[ctx->id("BEL")] = ctx->getBelName(dqsbuf).str(ctx);
|
||||||
bool got_dqsg = ctx->getPIODQSGroup(pio_bel, dqsbuf_dqsg[ci->name].first, dqsbuf_dqsg[ci->name].second);
|
bool got_dqsg = ctx->getPIODQSGroup(pio_bel, dqsbuf_dqsg[ci->name].first, dqsbuf_dqsg[ci->name].second);
|
||||||
NPNR_ASSERT(got_dqsg);
|
NPNR_ASSERT(got_dqsg);
|
||||||
@ -2078,15 +2078,14 @@ class Ecp5Packer
|
|||||||
log_error("IOLOGIC functionality (DDR, DELAY, DQS, etc) can only be used with pin-constrained PIO "
|
log_error("IOLOGIC functionality (DDR, DELAY, DQS, etc) can only be used with pin-constrained PIO "
|
||||||
"(while processing '%s').\n",
|
"(while processing '%s').\n",
|
||||||
curr->name.c_str(ctx));
|
curr->name.c_str(ctx));
|
||||||
BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string()));
|
BelId bel = ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string());
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return bel;
|
return bel;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto create_pio_iologic = [&](CellInfo *pio, CellInfo *curr) {
|
auto create_pio_iologic = [&](CellInfo *pio, CellInfo *curr) {
|
||||||
BelId bel = get_pio_bel(pio, curr);
|
BelId bel = get_pio_bel(pio, curr);
|
||||||
log_info("IOLOGIC component %s connected to PIO Bel %s\n", curr->name.c_str(ctx),
|
log_info("IOLOGIC component %s connected to PIO Bel %s\n", curr->name.c_str(ctx), ctx->nameOfBel(bel));
|
||||||
ctx->getBelName(bel).c_str(ctx));
|
|
||||||
Loc loc = ctx->getBelLocation(bel);
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
bool s = false;
|
bool s = false;
|
||||||
if (loc.y == 0 || loc.y == (ctx->chip_info->height - 1))
|
if (loc.y == 0 || loc.y == (ctx->chip_info->height - 1))
|
||||||
@ -2292,8 +2291,7 @@ class Ecp5Packer
|
|||||||
replace_port(ci, ctx->id("D2"), iol, id_TXDATA2);
|
replace_port(ci, ctx->id("D2"), iol, id_TXDATA2);
|
||||||
replace_port(ci, ctx->id("D3"), iol, id_TXDATA3);
|
replace_port(ci, ctx->id("D3"), iol, id_TXDATA3);
|
||||||
if (ci->type == ctx->id("ODDR71B")) {
|
if (ci->type == ctx->id("ODDR71B")) {
|
||||||
Loc loc =
|
Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
ctx->getBelLocation(ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())));
|
|
||||||
if (loc.z % 2 == 1)
|
if (loc.z % 2 == 1)
|
||||||
log_error("ODDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx));
|
log_error("ODDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx));
|
||||||
replace_port(ci, ctx->id("D4"), iol, id_TXDATA4);
|
replace_port(ci, ctx->id("D4"), iol, id_TXDATA4);
|
||||||
@ -2326,8 +2324,7 @@ class Ecp5Packer
|
|||||||
replace_port(ci, ctx->id("Q2"), iol, id_RXDATA2);
|
replace_port(ci, ctx->id("Q2"), iol, id_RXDATA2);
|
||||||
replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3);
|
replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3);
|
||||||
if (ci->type == ctx->id("IDDR71B")) {
|
if (ci->type == ctx->id("IDDR71B")) {
|
||||||
Loc loc =
|
Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
ctx->getBelLocation(ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())));
|
|
||||||
if (loc.z % 2 == 1)
|
if (loc.z % 2 == 1)
|
||||||
log_error("IDDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx));
|
log_error("IDDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx));
|
||||||
replace_port(ci, ctx->id("Q4"), iol, id_RXDATA4);
|
replace_port(ci, ctx->id("Q4"), iol, id_RXDATA4);
|
||||||
@ -2579,7 +2576,7 @@ class Ecp5Packer
|
|||||||
if (!user.cell->attrs.count(ctx->id("BEL")))
|
if (!user.cell->attrs.count(ctx->id("BEL")))
|
||||||
continue;
|
continue;
|
||||||
Loc user_loc = ctx->getBelLocation(
|
Loc user_loc = ctx->getBelLocation(
|
||||||
ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string())));
|
ctx->getBelByNameStr(user.cell->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
|
if (ctx->getBelType(bel) != id_ECLKBRIDGECS)
|
||||||
continue;
|
continue;
|
||||||
@ -2594,8 +2591,8 @@ class Ecp5Packer
|
|||||||
CellInfo *drv = input->driver.cell;
|
CellInfo *drv = input->driver.cell;
|
||||||
if (!drv->attrs.count(ctx->id("BEL")))
|
if (!drv->attrs.count(ctx->id("BEL")))
|
||||||
continue;
|
continue;
|
||||||
Loc drv_loc = ctx->getBelLocation(
|
Loc drv_loc =
|
||||||
ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string())));
|
ctx->getBelLocation(ctx->getBelByNameStr(drv->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
BelId closest;
|
BelId closest;
|
||||||
int closest_x = -1; // aim for same side of chip
|
int closest_x = -1; // aim for same side of chip
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
@ -2639,7 +2636,7 @@ class Ecp5Packer
|
|||||||
if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) {
|
if (ci->type == id_IOLOGIC || ci->type == id_DQSBUFM) {
|
||||||
if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr)
|
if (!ci->ports.count(id_ECLK) || ci->ports.at(id_ECLK).net == nullptr)
|
||||||
continue;
|
continue;
|
||||||
BelId bel = ctx->getBelByName(ctx->id(str_or_default(ci->attrs, ctx->id("BEL"))));
|
BelId bel = ctx->getBelByNameStr(str_or_default(ci->attrs, ctx->id("BEL")));
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
Loc pioLoc = ctx->getBelLocation(bel);
|
Loc pioLoc = ctx->getBelLocation(bel);
|
||||||
if (ci->type == id_DQSBUFM)
|
if (ci->type == id_DQSBUFM)
|
||||||
@ -2683,8 +2680,7 @@ class Ecp5Packer
|
|||||||
const NetInfo *eclko = net_or_nullptr(ci, id_ECLKO);
|
const NetInfo *eclko = net_or_nullptr(ci, id_ECLKO);
|
||||||
if (eclki != nullptr && eclki->driver.cell != nullptr) {
|
if (eclki != nullptr && eclki->driver.cell != nullptr) {
|
||||||
if (eclki->driver.cell->type == id_ECLKBRIDGECS) {
|
if (eclki->driver.cell->type == id_ECLKBRIDGECS) {
|
||||||
BelId bel =
|
BelId bel = ctx->getBelByNameStr(eclki->driver.cell->attrs.at(ctx->id("BEL")).as_string());
|
||||||
ctx->getBelByName(ctx->id(eclki->driver.cell->attrs.at(ctx->id("BEL")).as_string()));
|
|
||||||
Loc loc = ctx->getBelLocation(bel);
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
ci->attrs[ctx->id("BEL")] =
|
ci->attrs[ctx->id("BEL")] =
|
||||||
ctx->getBelName(ctx->getBelByLocation(Loc(loc.x, loc.y, 15))).str(ctx);
|
ctx->getBelName(ctx->getBelByLocation(Loc(loc.x, loc.y, 15))).str(ctx);
|
||||||
@ -2697,7 +2693,7 @@ class Ecp5Packer
|
|||||||
for (auto user : eclko->users) {
|
for (auto user : eclko->users) {
|
||||||
if (user.cell->type == id_TRELLIS_ECLKBUF) {
|
if (user.cell->type == id_TRELLIS_ECLKBUF) {
|
||||||
Loc eckbuf_loc = ctx->getBelLocation(
|
Loc eckbuf_loc = ctx->getBelLocation(
|
||||||
ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string())));
|
ctx->getBelByNameStr(user.cell->attrs.at(ctx->id("BEL")).as_string()));
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(bel) != id_ECLKSYNCB)
|
if (ctx->getBelType(bel) != id_ECLKSYNCB)
|
||||||
continue;
|
continue;
|
||||||
@ -2726,7 +2722,7 @@ class Ecp5Packer
|
|||||||
const CellInfo *uc = usr.cell;
|
const CellInfo *uc = usr.cell;
|
||||||
if (uc->type != id_DQSBUFM || !uc->attrs.count(ctx->id("BEL")))
|
if (uc->type != id_DQSBUFM || !uc->attrs.count(ctx->id("BEL")))
|
||||||
continue;
|
continue;
|
||||||
BelId dqsb_bel = ctx->getBelByName(ctx->id(uc->attrs.at(ctx->id("BEL")).as_string()));
|
BelId dqsb_bel = ctx->getBelByNameStr(uc->attrs.at(ctx->id("BEL")).as_string());
|
||||||
Loc dqsb_loc = ctx->getBelLocation(dqsb_bel);
|
Loc dqsb_loc = ctx->getBelLocation(dqsb_bel);
|
||||||
if (dqsb_loc.x > 15)
|
if (dqsb_loc.x > 15)
|
||||||
right_bank_users = true;
|
right_bank_users = true;
|
||||||
@ -2809,7 +2805,7 @@ class Ecp5Packer
|
|||||||
CellInfo *drv = clki->driver.cell;
|
CellInfo *drv = clki->driver.cell;
|
||||||
if (drv->type != id_ECLKSYNCB || !drv->attrs.count(ctx->id("BEL")))
|
if (drv->type != id_ECLKSYNCB || !drv->attrs.count(ctx->id("BEL")))
|
||||||
continue;
|
continue;
|
||||||
BelId bel = ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string()));
|
BelId bel = ctx->getBelByNameStr(drv->attrs.at(ctx->id("BEL")).as_string());
|
||||||
// Find a CLKDIVF that is routeable from the ECLKSYNC
|
// Find a CLKDIVF that is routeable from the ECLKSYNC
|
||||||
std::queue<WireId> visit;
|
std::queue<WireId> visit;
|
||||||
visit.push(ctx->getBelPinWire(bel, id_ECLKO));
|
visit.push(ctx->getBelPinWire(bel, id_ECLKO));
|
||||||
|
Loading…
Reference in New Issue
Block a user