Merge pull request #640 from litghost/inversion_logic

Initial inverter logic for FPGA interchange
This commit is contained in:
gatecat 2021-03-23 16:59:35 +00:00 committed by GitHub
commit 2300d81c3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 131 additions and 8 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -95,18 +95,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;
}
}
@ -313,6 +311,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)
@ -366,6 +366,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,
@ -570,6 +572,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);
@ -583,6 +591,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);

View File

@ -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);
}

View File

@ -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