Initial version of inverter logic.
For now just implements some inspection capabilities, and the site router (for now) avoids inverted paths. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
ae71206e1f
commit
831b94cdac
@ -1747,6 +1747,37 @@ bool Arch::checkPipAvail(PipId pip) const { return checkPipAvailForNet(pip, null
|
|||||||
|
|
||||||
std::string Arch::get_chipdb_hash() const { return chipdb_hash; }
|
std::string Arch::get_chipdb_hash() const { return chipdb_hash; }
|
||||||
|
|
||||||
|
bool Arch::is_inverting(PipId pip) const
|
||||||
|
{
|
||||||
|
auto &tile_type = loc_info(chip_info, pip);
|
||||||
|
auto &pip_info = tile_type.pip_data[pip.index];
|
||||||
|
if (pip_info.site == -1) {
|
||||||
|
// FIXME: Some routing pips are inverters, but this is missing from
|
||||||
|
// the chipdb.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &bel_data = tile_type.bel_data[pip_info.bel];
|
||||||
|
|
||||||
|
// Is a fixed inverter if the non_inverting_pin is another pin.
|
||||||
|
return bel_data.non_inverting_pin != pip_info.extra_data && bel_data.inverting_pin == pip_info.extra_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Arch::can_invert(PipId pip) const
|
||||||
|
{
|
||||||
|
auto &tile_type = loc_info(chip_info, pip);
|
||||||
|
auto &pip_info = tile_type.pip_data[pip.index];
|
||||||
|
if (pip_info.site == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &bel_data = tile_type.bel_data[pip_info.bel];
|
||||||
|
|
||||||
|
// Can optionally invert if this pip is both the non_inverting_pin and
|
||||||
|
// inverting pin.
|
||||||
|
return bel_data.non_inverting_pin == pip_info.extra_data && bel_data.inverting_pin == pip_info.extra_data;
|
||||||
|
}
|
||||||
|
|
||||||
// Instance constraint templates.
|
// Instance constraint templates.
|
||||||
template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
||||||
template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
|
||||||
|
@ -1028,6 +1028,12 @@ struct Arch : ArchAPI<ArchRanges>
|
|||||||
return wire_data.site != -1;
|
return wire_data.site != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Does this pip always invert its signal?
|
||||||
|
bool is_inverting(PipId pip) const;
|
||||||
|
|
||||||
|
// Can this pip optional invert its signal?
|
||||||
|
bool can_invert(PipId pip) const;
|
||||||
|
|
||||||
void merge_constant_nets();
|
void merge_constant_nets();
|
||||||
void report_invalid_bel(BelId bel, CellInfo *cell) const;
|
void report_invalid_bel(BelId bel, CellInfo *cell) const;
|
||||||
|
|
||||||
|
@ -289,6 +289,12 @@ struct SiteArch
|
|||||||
inline SiteWire getPipSrcWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
inline SiteWire getPipSrcWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
||||||
inline SiteWire getPipDstWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
inline SiteWire getPipDstWire(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
||||||
|
|
||||||
|
// Does this site pip always invert its signal?
|
||||||
|
inline bool isInverting(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
||||||
|
|
||||||
|
// Can this site pip optional invert its signal?
|
||||||
|
inline bool canInvert(const SitePip &site_pip) const NPNR_ALWAYS_INLINE;
|
||||||
|
|
||||||
inline SitePipDownhillRange getPipsDownhill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE;
|
inline SitePipDownhillRange getPipsDownhill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE;
|
||||||
inline SitePipUphillRange getPipsUphill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE;
|
inline SitePipUphillRange getPipsUphill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE;
|
||||||
SiteWireRange getWires() const;
|
SiteWireRange getWires() const;
|
||||||
@ -341,6 +347,7 @@ struct SiteArch
|
|||||||
void archcheck();
|
void archcheck();
|
||||||
|
|
||||||
bool is_pip_synthetic(const SitePip &pip) const NPNR_ALWAYS_INLINE;
|
bool is_pip_synthetic(const SitePip &pip) const NPNR_ALWAYS_INLINE;
|
||||||
|
SyntheticType pip_synthetic_type(const SitePip &pip) const NPNR_ALWAYS_INLINE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SitePipDownhillIterator
|
struct SitePipDownhillIterator
|
||||||
|
@ -202,6 +202,20 @@ inline bool SiteArch::is_pip_synthetic(const SitePip &pip) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline SyntheticType SiteArch::pip_synthetic_type(const SitePip &pip) const
|
||||||
|
{
|
||||||
|
if (pip.type != SitePip::SITE_PORT) {
|
||||||
|
// This isn't a site port, so its valid!
|
||||||
|
return NOT_SYNTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type];
|
||||||
|
auto &pip_data = tile_type.pip_data[pip.pip.index];
|
||||||
|
NPNR_ASSERT(pip_data.site != -1);
|
||||||
|
auto &bel_data = tile_type.bel_data[pip_data.bel];
|
||||||
|
return SyntheticType(bel_data.synthetic);
|
||||||
|
}
|
||||||
|
|
||||||
inline SitePip SitePipDownhillIterator::operator*() const
|
inline SitePip SitePipDownhillIterator::operator*() const
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -250,6 +264,37 @@ inline SitePipDownhillIterator SitePipDownhillRange::begin() const
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool SiteArch::isInverting(const SitePip &site_pip) const
|
||||||
|
{
|
||||||
|
if (site_pip.type != SitePip::SITE_PIP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type];
|
||||||
|
auto &pip_data = tile_type.pip_data[site_pip.pip.index];
|
||||||
|
NPNR_ASSERT(pip_data.site != -1);
|
||||||
|
auto &bel_data = tile_type.bel_data[pip_data.bel];
|
||||||
|
|
||||||
|
// Is a fixed inverter if the non_inverting_pin is another pin.
|
||||||
|
return bel_data.non_inverting_pin != pip_data.extra_data && bel_data.inverting_pin == pip_data.extra_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SiteArch::canInvert(const SitePip &site_pip) const
|
||||||
|
{
|
||||||
|
if (site_pip.type != SitePip::SITE_PIP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &tile_type = ctx->chip_info->tile_types[site_info->tile_type];
|
||||||
|
auto &pip_data = tile_type.pip_data[site_pip.pip.index];
|
||||||
|
NPNR_ASSERT(pip_data.site != -1);
|
||||||
|
auto &bel_data = tile_type.bel_data[pip_data.bel];
|
||||||
|
|
||||||
|
// Can optionally invert if this pip is both the non_inverting_pin and
|
||||||
|
// inverting pin.
|
||||||
|
return bel_data.non_inverting_pin == pip_data.extra_data && bel_data.inverting_pin == pip_data.extra_data;
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif /* SITE_ARCH_H */
|
#endif /* SITE_ARCH_H */
|
||||||
|
@ -92,18 +92,16 @@ bool check_initial_wires(const Context *ctx, SiteInformation *site_info)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_invalid_site_port(const SiteArch *ctx, const SiteNetInfo *net, const SitePip &pip)
|
static bool is_invalid_site_port(const SiteArch *ctx, const SiteNetInfo *net, const SitePip &pip)
|
||||||
{
|
{
|
||||||
if (ctx->is_pip_synthetic(pip)) {
|
SyntheticType type = ctx->pip_synthetic_type(pip);
|
||||||
// FIXME: Not all synthetic pips are for constant networks.
|
if (type == SYNTH_GND) {
|
||||||
// FIXME: Need to mark if synthetic site ports are for the GND or VCC
|
|
||||||
// network, and only allow the right one. Otherwise site router
|
|
||||||
// could route a VCC on a GND only net (or equiv).
|
|
||||||
IdString gnd_net_name(ctx->ctx->chip_info->constants->gnd_net_name);
|
IdString gnd_net_name(ctx->ctx->chip_info->constants->gnd_net_name);
|
||||||
|
return net->net->name != gnd_net_name;
|
||||||
|
} else if (type == SYNTH_VCC) {
|
||||||
IdString vcc_net_name(ctx->ctx->chip_info->constants->vcc_net_name);
|
IdString vcc_net_name(ctx->ctx->chip_info->constants->vcc_net_name);
|
||||||
return net->net->name != gnd_net_name && net->net->name != vcc_net_name;
|
return net->net->name != vcc_net_name;
|
||||||
} else {
|
} else {
|
||||||
// All non-synthetic site ports are valid
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,6 +308,8 @@ struct SiteExpansionLoop
|
|||||||
std::vector<SitePip>::const_iterator solution_begin(size_t idx) const { return solution.solution_begin(idx); }
|
std::vector<SitePip>::const_iterator solution_begin(size_t idx) const { return solution.solution_begin(idx); }
|
||||||
|
|
||||||
std::vector<SitePip>::const_iterator solution_end(size_t idx) const { return solution.solution_end(idx); }
|
std::vector<SitePip>::const_iterator solution_end(size_t idx) const { return solution.solution_end(idx); }
|
||||||
|
bool solution_inverted(size_t idx) const { return solution.solution_inverted(idx); }
|
||||||
|
bool solution_can_invert(size_t idx) const { return solution.solution_can_invert(idx); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void print_current_state(const SiteArch *site_arch)
|
void print_current_state(const SiteArch *site_arch)
|
||||||
@ -363,6 +363,8 @@ struct PossibleSolutions
|
|||||||
SiteNetInfo *net = nullptr;
|
SiteNetInfo *net = nullptr;
|
||||||
std::vector<SitePip>::const_iterator pips_begin;
|
std::vector<SitePip>::const_iterator pips_begin;
|
||||||
std::vector<SitePip>::const_iterator pips_end;
|
std::vector<SitePip>::const_iterator pips_end;
|
||||||
|
bool inverted = false;
|
||||||
|
bool can_invert = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool test_solution(SiteArch *ctx, SiteNetInfo *net, std::vector<SitePip>::const_iterator pips_begin,
|
bool test_solution(SiteArch *ctx, SiteNetInfo *net, std::vector<SitePip>::const_iterator pips_begin,
|
||||||
@ -567,6 +569,12 @@ bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeSt
|
|||||||
|
|
||||||
for (const auto *expansion : expansions) {
|
for (const auto *expansion : expansions) {
|
||||||
for (size_t idx = 0; idx < expansion->num_solutions(); ++idx) {
|
for (size_t idx = 0; idx < expansion->num_solutions(); ++idx) {
|
||||||
|
if (expansion->solution_inverted(idx)) {
|
||||||
|
// FIXME: May prefer an inverted solution if constant net
|
||||||
|
// type.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SiteWire wire = expansion->solution_sink(idx);
|
SiteWire wire = expansion->solution_sink(idx);
|
||||||
auto begin = expansion->solution_begin(idx);
|
auto begin = expansion->solution_begin(idx);
|
||||||
auto end = expansion->solution_end(idx);
|
auto end = expansion->solution_end(idx);
|
||||||
@ -580,6 +588,8 @@ bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeSt
|
|||||||
solution.net = ctx->wire_to_nets.at(wire).net;
|
solution.net = ctx->wire_to_nets.at(wire).net;
|
||||||
solution.pips_begin = begin;
|
solution.pips_begin = begin;
|
||||||
solution.pips_end = end;
|
solution.pips_end = end;
|
||||||
|
solution.inverted = expansion->solution_inverted(idx);
|
||||||
|
solution.can_invert = expansion->solution_can_invert(idx);
|
||||||
|
|
||||||
for (auto iter = begin; iter != end; ++iter) {
|
for (auto iter = begin; iter != end; ++iter) {
|
||||||
NPNR_ASSERT(ctx->getPipDstWire(*iter) == wire);
|
NPNR_ASSERT(ctx->getPipDstWire(*iter) == wire);
|
||||||
|
@ -31,14 +31,27 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
|
|||||||
clear();
|
clear();
|
||||||
|
|
||||||
solution_sinks.reserve(solutions.size());
|
solution_sinks.reserve(solutions.size());
|
||||||
|
inverted.reserve(solutions.size());
|
||||||
|
can_invert.reserve(solutions.size());
|
||||||
|
|
||||||
for (size_t route : solutions) {
|
for (size_t route : solutions) {
|
||||||
|
bool sol_inverted = false;
|
||||||
|
bool sol_can_invert = false;
|
||||||
|
|
||||||
SiteWire wire = node_storage->get_node(route)->wire;
|
SiteWire wire = node_storage->get_node(route)->wire;
|
||||||
solution_sinks.push_back(wire);
|
solution_sinks.push_back(wire);
|
||||||
|
|
||||||
solution_offsets.push_back(solution_storage.size());
|
solution_offsets.push_back(solution_storage.size());
|
||||||
Node cursor = node_storage->get_node(route);
|
Node cursor = node_storage->get_node(route);
|
||||||
while (cursor.has_parent()) {
|
while (cursor.has_parent()) {
|
||||||
|
if (ctx->isInverting(cursor->pip) && !sol_can_invert) {
|
||||||
|
sol_inverted = !sol_inverted;
|
||||||
|
}
|
||||||
|
if (ctx->canInvert(cursor->pip)) {
|
||||||
|
sol_inverted = false;
|
||||||
|
sol_can_invert = true;
|
||||||
|
}
|
||||||
|
|
||||||
solution_storage.push_back(cursor->pip);
|
solution_storage.push_back(cursor->pip);
|
||||||
Node parent = cursor.parent();
|
Node parent = cursor.parent();
|
||||||
NPNR_ASSERT(ctx->getPipDstWire(cursor->pip) == cursor->wire);
|
NPNR_ASSERT(ctx->getPipDstWire(cursor->pip) == cursor->wire);
|
||||||
@ -46,6 +59,9 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
|
|||||||
cursor = parent;
|
cursor = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inverted.push_back(sol_inverted);
|
||||||
|
can_invert.push_back(sol_can_invert);
|
||||||
|
|
||||||
NPNR_ASSERT(cursor->wire == driver);
|
NPNR_ASSERT(cursor->wire == driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ struct SiteRoutingSolution
|
|||||||
solution_offsets.clear();
|
solution_offsets.clear();
|
||||||
solution_storage.clear();
|
solution_storage.clear();
|
||||||
solution_sinks.clear();
|
solution_sinks.clear();
|
||||||
|
inverted.clear();
|
||||||
|
can_invert.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t num_solutions() const { return solution_sinks.size(); }
|
size_t num_solutions() const { return solution_sinks.size(); }
|
||||||
@ -58,9 +60,15 @@ struct SiteRoutingSolution
|
|||||||
return solution_storage.begin() + solution_offsets.at(solution + 1);
|
return solution_storage.begin() + solution_offsets.at(solution + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool solution_inverted(size_t solution) const { return inverted.at(solution) != 0; }
|
||||||
|
|
||||||
|
bool solution_can_invert(size_t solution) const { return can_invert.at(solution) != 0; }
|
||||||
|
|
||||||
std::vector<size_t> solution_offsets;
|
std::vector<size_t> solution_offsets;
|
||||||
std::vector<SitePip> solution_storage;
|
std::vector<SitePip> solution_storage;
|
||||||
std::vector<SiteWire> solution_sinks;
|
std::vector<SiteWire> solution_sinks;
|
||||||
|
std::vector<uint8_t> inverted;
|
||||||
|
std::vector<uint8_t> can_invert;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SiteRoutingKey
|
struct SiteRoutingKey
|
||||||
|
Loading…
Reference in New Issue
Block a user