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; }
|
||||
|
||||
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.
|
||||
template void Arch::ArchConstraints::bindBel(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;
|
||||
}
|
||||
|
||||
// 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 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 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 SitePipUphillRange getPipsUphill(const SiteWire &site_wire) const NPNR_ALWAYS_INLINE;
|
||||
SiteWireRange getWires() const;
|
||||
@ -341,6 +347,7 @@ struct SiteArch
|
||||
void archcheck();
|
||||
|
||||
bool is_pip_synthetic(const SitePip &pip) const NPNR_ALWAYS_INLINE;
|
||||
SyntheticType pip_synthetic_type(const SitePip &pip) const NPNR_ALWAYS_INLINE;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
switch (state) {
|
||||
@ -250,6 +264,37 @@ inline SitePipDownhillIterator SitePipDownhillRange::begin() const
|
||||
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
|
||||
|
||||
#endif /* SITE_ARCH_H */
|
||||
|
@ -92,18 +92,16 @@ bool check_initial_wires(const Context *ctx, SiteInformation *site_info)
|
||||
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)) {
|
||||
// FIXME: Not all synthetic pips are for constant networks.
|
||||
// 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).
|
||||
SyntheticType type = ctx->pip_synthetic_type(pip);
|
||||
if (type == SYNTH_GND) {
|
||||
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);
|
||||
return net->net->name != gnd_net_name && net->net->name != vcc_net_name;
|
||||
return net->net->name != vcc_net_name;
|
||||
} else {
|
||||
// All non-synthetic site ports are valid
|
||||
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_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)
|
||||
@ -363,6 +363,8 @@ struct PossibleSolutions
|
||||
SiteNetInfo *net = nullptr;
|
||||
std::vector<SitePip>::const_iterator pips_begin;
|
||||
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,
|
||||
@ -567,6 +569,12 @@ bool route_site(SiteArch *ctx, SiteRoutingCache *site_routing_cache, RouteNodeSt
|
||||
|
||||
for (const auto *expansion : expansions) {
|
||||
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);
|
||||
auto begin = expansion->solution_begin(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.pips_begin = begin;
|
||||
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) {
|
||||
NPNR_ASSERT(ctx->getPipDstWire(*iter) == wire);
|
||||
|
@ -31,14 +31,27 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
|
||||
clear();
|
||||
|
||||
solution_sinks.reserve(solutions.size());
|
||||
inverted.reserve(solutions.size());
|
||||
can_invert.reserve(solutions.size());
|
||||
|
||||
for (size_t route : solutions) {
|
||||
bool sol_inverted = false;
|
||||
bool sol_can_invert = false;
|
||||
|
||||
SiteWire wire = node_storage->get_node(route)->wire;
|
||||
solution_sinks.push_back(wire);
|
||||
|
||||
solution_offsets.push_back(solution_storage.size());
|
||||
Node cursor = node_storage->get_node(route);
|
||||
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);
|
||||
Node parent = cursor.parent();
|
||||
NPNR_ASSERT(ctx->getPipDstWire(cursor->pip) == cursor->wire);
|
||||
@ -46,6 +59,9 @@ void SiteRoutingSolution::store_solution(const SiteArch *ctx, const RouteNodeSto
|
||||
cursor = parent;
|
||||
}
|
||||
|
||||
inverted.push_back(sol_inverted);
|
||||
can_invert.push_back(sol_can_invert);
|
||||
|
||||
NPNR_ASSERT(cursor->wire == driver);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@ struct SiteRoutingSolution
|
||||
solution_offsets.clear();
|
||||
solution_storage.clear();
|
||||
solution_sinks.clear();
|
||||
inverted.clear();
|
||||
can_invert.clear();
|
||||
}
|
||||
|
||||
size_t num_solutions() const { return solution_sinks.size(); }
|
||||
@ -58,9 +60,15 @@ struct SiteRoutingSolution
|
||||
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<SitePip> solution_storage;
|
||||
std::vector<SiteWire> solution_sinks;
|
||||
std::vector<uint8_t> inverted;
|
||||
std::vector<uint8_t> can_invert;
|
||||
};
|
||||
|
||||
struct SiteRoutingKey
|
||||
|
Loading…
Reference in New Issue
Block a user