diff --git a/common/kernel/CMakeLists.txt b/common/kernel/CMakeLists.txt index fe0b1b4b..3341d10a 100644 --- a/common/kernel/CMakeLists.txt +++ b/common/kernel/CMakeLists.txt @@ -11,23 +11,16 @@ target_sources(nextpnr_kernel PUBLIC base_clusterinfo.h basectx.cc basectx.h - bits.cc - bits.h chain_utils.h command.cc command.h - constraints.h - constraints.impl.h context.cc context.h design_utils.cc design_utils.h deterministic_rng.h - dynamic_bitarray.h embed.cc embed.h - exclusive_state_groups.h - exclusive_state_groups.impl.h handle_error.cc hashlib.h idstring.cc diff --git a/common/kernel/bits.cc b/common/kernel/bits.cc deleted file mode 100644 index b20c2e86..00000000 --- a/common/kernel/bits.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (c) 2013 Mike Pedersen - * Copyright (C) 2021 Symbiflow Authors - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "bits.h" - -#include -#include - -#include "log.h" - -NEXTPNR_NAMESPACE_BEGIN - -int Bits::generic_popcount(unsigned int v) -{ - unsigned int c; // c accumulates the total bits set in v - for (c = 0; v; c++) { - v &= v - 1; // clear the least significant bit set - } - - return c; -} - -int Bits::generic_ctz(unsigned int x) -{ - if (x == 0) { - log_error("Cannot call ctz with arg = 0"); - } - - for (size_t i = 0; i < std::numeric_limits::digits; ++i) { - if ((x & (1 << i)) != 0) { - return i; - } - } - - // Unreachable! - log_error("Unreachable!"); -} - -NEXTPNR_NAMESPACE_END diff --git a/common/kernel/bits.h b/common/kernel/bits.h deleted file mode 100644 index 04b25b74..00000000 --- a/common/kernel/bits.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (c) 2013 Mike Pedersen - * Copyright (C) 2021 Symbiflow Authors - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// This is a small library for implementing common bit vector utilities, -// namely: -// -// - popcount : The number of bits set in an unsigned int -// - ctz : The number of trailing zero bits in an unsigned int. -// Must be called with a value that has at least 1 bit set. -// -// These methods will typically use instrinics when available, and have a -// generic fallback in the event that the instrinic is not available. -// -// If clz (count leading zeros) is needed, it can be added when needed. -#ifndef BITS_H -#define BITS_H - -#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) -#include -#pragma intrinsic(_BitScanForward, _BitScanReverse, __popcnt) -#endif - -#include "nextpnr_namespaces.h" - -NEXTPNR_NAMESPACE_BEGIN - -struct Bits -{ - static int generic_popcount(unsigned int x); - static int generic_ctz(unsigned int x); - - static int popcount(unsigned int x) - { -#if defined(__GNUC__) || defined(__clang__) - return __builtin_popcount(x); -#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) - return __popcnt(x); -#else - return generic_popcount(x); -#endif - } - - static int ctz(unsigned int x) - { -#if defined(__GNUC__) || defined(__clang__) - return __builtin_ctz(x); -#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) - unsigned long result; - _BitScanForward(&result, x); - return result; -#else - return generic_ctz(x); -#endif - } -}; - -NEXTPNR_NAMESPACE_END - -#endif /* BITS_H */ diff --git a/common/kernel/constraints.h b/common/kernel/constraints.h deleted file mode 100644 index 65abf12c..00000000 --- a/common/kernel/constraints.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 The SymbiFlow Authors. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CONSTRAINTS_H -#define CONSTRAINTS_H - -#include -#include - -#include "archdefs.h" -#include "exclusive_state_groups.h" -#include "hashlib.h" -#include "idstring.h" -#include "nextpnr_namespaces.h" - -NEXTPNR_NAMESPACE_BEGIN - -struct Context; - -template struct Constraints -{ - using ConstraintStateType = StateType; - using ConstraintCountType = CountType; - - enum ConstraintType - { - CONSTRAINT_TAG_IMPLIES = 0, - CONSTRAINT_TAG_REQUIRES = 1, - }; - - template struct Constraint - { - virtual std::size_t tag() const = 0; - virtual ConstraintType constraint_type() const = 0; - virtual StateType state() const = 0; - virtual StateRange states() const = 0; - }; - - typedef ExclusiveStateGroup TagState; - dict> definitions; - - template void bindBel(TagState *tags, const ConstraintRange constraints); - - template void unbindBel(TagState *tags, const ConstraintRange constraints); - - template - bool isValidBelForCellType(const Context *ctx, uint32_t prototype, const TagState *tags, - const ConstraintRange constraints, IdString object, IdString cell, BelId bel, - bool explain_constraints) const; -}; - -NEXTPNR_NAMESPACE_END - -#endif diff --git a/common/kernel/constraints.impl.h b/common/kernel/constraints.impl.h deleted file mode 100644 index 145aff5b..00000000 --- a/common/kernel/constraints.impl.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 The SymbiFlow Authors. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef CONSTRAINTS_IMPL_H -#define CONSTRAINTS_IMPL_H - -#include "exclusive_state_groups.impl.h" - -NEXTPNR_NAMESPACE_BEGIN - -template -template -void Constraints::bindBel(TagState *tags, const ConstraintRange constraints) -{ - for (const auto &constraint : constraints) { - switch (constraint.constraint_type()) { - case CONSTRAINT_TAG_IMPLIES: - tags[constraint.tag()].add_implies(constraint.state()); - break; - case CONSTRAINT_TAG_REQUIRES: - break; - default: - NPNR_ASSERT(false); - } - } -} - -template -template -void Constraints::unbindBel(TagState *tags, const ConstraintRange constraints) -{ - for (const auto &constraint : constraints) { - switch (constraint.constraint_type()) { - case CONSTRAINT_TAG_IMPLIES: - tags[constraint.tag()].remove_implies(constraint.state()); - break; - case CONSTRAINT_TAG_REQUIRES: - break; - default: - NPNR_ASSERT(false); - } - } -} - -template -template -bool Constraints::isValidBelForCellType(const Context *ctx, uint32_t prototype, - const TagState *tags, - const ConstraintRange constraints, - IdString object, IdString cell, BelId bel, - bool explain_constraints) const -{ - if (explain_constraints) { - auto &state_definition = definitions.at(prototype); - for (const auto &constraint : constraints) { - switch (constraint.constraint_type()) { - case CONSTRAINT_TAG_IMPLIES: - tags[constraint.tag()].explain_implies(ctx, object, cell, state_definition.at(constraint.tag()), bel, - constraint.state()); - break; - case CONSTRAINT_TAG_REQUIRES: - tags[constraint.tag()].explain_requires(ctx, object, cell, state_definition.at(constraint.tag()), bel, - constraint.states()); - break; - default: - NPNR_ASSERT(false); - } - } - } - - for (const auto &constraint : constraints) { - switch (constraint.constraint_type()) { - case CONSTRAINT_TAG_IMPLIES: - if (!tags[constraint.tag()].check_implies(constraint.state())) { - return false; - } - break; - case CONSTRAINT_TAG_REQUIRES: - if (!tags[constraint.tag()].requires_range(constraint.states())) { - return false; - } - break; - default: - NPNR_ASSERT(false); - } - } - - return true; -} - -NEXTPNR_NAMESPACE_END - -#endif diff --git a/common/kernel/dynamic_bitarray.h b/common/kernel/dynamic_bitarray.h deleted file mode 100644 index be41835b..00000000 --- a/common/kernel/dynamic_bitarray.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 Symbiflow Authors - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef DYNAMIC_BITARRAY_H -#define DYNAMIC_BITARRAY_H - -#include -#include -#include - -#include "log.h" -#include "nextpnr_assertions.h" -#include "nextpnr_namespaces.h" - -NEXTPNR_NAMESPACE_BEGIN - -// This class implements a simple dynamic bitarray, backed by some resizable -// random access storage. The default is to use a std::vector. -template > class DynamicBitarray -{ - public: - static_assert(!std::numeric_limits::is_signed, "Storage must be unsigned!"); - - void fill(bool value) - { - std::fill(storage.begin(), storage.end(), value ? std::numeric_limits::max() : 0); - } - - constexpr size_t bits_per_value() const { return std::numeric_limits::digits; } - - bool get(size_t bit) const - { - size_t element_index = bit / bits_per_value(); - size_t bit_offset = bit % bits_per_value(); - - auto element = storage.at(element_index); - return (element & (1 << bit_offset)) != 0; - } - - void set(size_t bit, bool value) - { - size_t element_index = bit / bits_per_value(); - size_t bit_offset = bit % bits_per_value(); - - if (value) { - storage.at(element_index) |= (1 << bit_offset); - } else { - storage.at(element_index) &= ~(1 << bit_offset); - } - } - - void resize(size_t number_bits) - { - size_t required_storage = (number_bits + bits_per_value() - 1) / bits_per_value(); - storage.resize(required_storage); - } - - size_t size() const { return storage.size() * bits_per_value(); } - - void clear() { return storage.clear(); } - - // Convert IntType to a DynamicBitarray of sufficent width - template static DynamicBitarray to_bitarray(const IntType &value) - { - if (std::numeric_limits::is_signed) { - if (value < 0) { - log_error("Expected position value, got %s\n", std::to_string(value).c_str()); - } - } - - DynamicBitarray result; - result.resize(std::numeric_limits::digits); - result.fill(false); - - // Use a 1 of the right type (for shifting) - IntType one(1); - - for (size_t i = 0; i < std::numeric_limits::digits; ++i) { - if ((value & (one << i)) != 0) { - result.set(i, true); - } - } - - return result; - } - - // Convert binary bitstring to a DynamicBitarray of sufficent width - // - // string must be satisfy the following regex: - // - // [01]+ - // - // width can either be specified explicitly, or -1 to use a size wide - // enough to store the given string. - // - // If the width is specified and the width is insufficent it will result - // in an error. - static DynamicBitarray parse_binary_bitstring(int width, const std::string &bits) - { - NPNR_ASSERT(width == -1 || width > 0); - - DynamicBitarray result; - // If no width was supplied, use the width from the input data. - if (width == -1) { - width = bits.size(); - } - - NPNR_ASSERT(width >= 0); - if ((size_t)width < bits.size()) { - log_error("String '%s' is wider than specified width %d\n", bits.c_str(), width); - } - result.resize(width); - result.fill(false); - - for (size_t i = 0; i < bits.size(); ++i) { - // bits[0] is the MSB! - size_t index = width - 1 - i; - if (!(bits[i] == '1' || bits[i] == '0')) { - log_error("String '%s' is not a valid binary bitstring?\n", bits.c_str()); - } - result.set(index, bits[i] == '1'); - } - - return result; - } - - // Convert hex bitstring to a DynamicBitarray of sufficent width - // - // string must be satisfy the following regex: - // - // [0-9a-fA-F]+ - // - // width can either be specified explicitly, or -1 to use a size wide - // enough to store the given string. - // - // If the width is specified and the width is insufficent it will result - // in an error. - static DynamicBitarray parse_hex_bitstring(int width, const std::string &bits) - { - NPNR_ASSERT(width == -1 || width > 0); - - DynamicBitarray result; - // If no width was supplied, use the width from the input data. - if (width == -1) { - // Each character is 4 bits! - width = bits.size() * 4; - } - - NPNR_ASSERT(width >= 0); - int rem = width % 4; - size_t check_width = width; - if (rem != 0) { - check_width += (4 - rem); - } - if (check_width < bits.size() * 4) { - log_error("String '%s' is wider than specified width %d (check_width = %zu)\n", bits.c_str(), width, - check_width); - } - - result.resize(width); - result.fill(false); - - size_t index = 0; - for (auto nibble_iter = bits.rbegin(); nibble_iter != bits.rend(); ++nibble_iter) { - char nibble = *nibble_iter; - - int value; - if (nibble >= '0' && nibble <= '9') { - value = nibble - '0'; - } else if (nibble >= 'a' && nibble <= 'f') { - value = 10 + (nibble - 'a'); - } else if (nibble >= 'A' && nibble <= 'F') { - value = 10 + (nibble - 'A'); - } else { - log_error("Invalid hex string '%s'?\n", bits.c_str()); - } - NPNR_ASSERT(value >= 0); - NPNR_ASSERT(value < 16); - - // Insert nibble into bitarray. - for (size_t i = 0; i < 4; ++i) { - result.set(index++, (value & (1 << i)) != 0); - } - } - - return result; - } - - private: - Storage storage; -}; - -NEXTPNR_NAMESPACE_END - -#endif /* DYNAMIC_BITARRAY_H */ diff --git a/common/kernel/exclusive_state_groups.h b/common/kernel/exclusive_state_groups.h deleted file mode 100644 index 508e94dd..00000000 --- a/common/kernel/exclusive_state_groups.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 The SymbiFlow Authors. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef EXCLUSIVE_STATE_GROUPS_H -#define EXCLUSIVE_STATE_GROUPS_H - -#include -#include -#include -#include -#include - -#include "archdefs.h" -#include "bits.h" -#include "idstring.h" -#include "nextpnr_assertions.h" -#include "nextpnr_namespaces.h" - -NEXTPNR_NAMESPACE_BEGIN - -// Implementation for exclusive state groups, used to implement generic -// constraint system. -template struct ExclusiveStateGroup -{ - ExclusiveStateGroup() : state(kNoSelected) { count.fill(0); } - struct Definition - { - IdString prefix; - IdString default_state; - std::vector states; - }; - - static_assert(StateCount < std::numeric_limits::max(), "StateType cannot store max StateType"); - static_assert(std::numeric_limits::is_signed, "StateType must be signed"); - - std::bitset selected_states; - StateType state; - std::array count; - - static constexpr StateType kNoSelected = -1; - static constexpr StateType kOverConstrained = -2; - - std::pair current_state(const Definition &definition) const - { - if (state <= 0) { - return std::make_pair(state == kNoSelected, definition.default_state); - } else { - NPNR_ASSERT(state <= definition.states.size()); - return std::make_pair(true, definition.states[state]); - } - } - - bool check_implies(int32_t next_state) const - { - // Implies can be satified if either that state is - // selected, or no state is currently selected. - return state == next_state || state == kNoSelected; - } - - bool add_implies(int32_t next_state) - { - NPNR_ASSERT(next_state >= 0 && (size_t)next_state < StateCount); - - // Increment and mark the state as selected. - count[next_state] += 1; - selected_states[next_state] = true; - - if (state == next_state) { - // State was already selected, state group is still satified. - return true; - } else if (selected_states.count() == 1) { - // State was not select selected, state is now selected. - // State group is satified. - state = next_state; - return true; - } else { - // State group is now overconstrained. - state = kOverConstrained; - return false; - } - }; - - void remove_implies(int32_t next_state) - { - NPNR_ASSERT(next_state >= 0 && (size_t)next_state < StateCount); - NPNR_ASSERT(selected_states[next_state]); - - count[next_state] -= 1; - NPNR_ASSERT(count[next_state] >= 0); - - // Check if next_state is now unselected. - if (count[next_state] == 0) { - // next_state is not longer selected - selected_states[next_state] = false; - - // Check whether the state group is now unselected or satified. - auto value = selected_states.to_ulong(); - auto number_selected = Bits::popcount(value); - if (number_selected == 1) { - // Group is no longer overconstrained. - state = Bits::ctz(value); - NPNR_ASSERT(selected_states[state]); - } else if (number_selected == 0) { - // Group is unselected. - state = kNoSelected; - } else { - state = kOverConstrained; - } - } - } - - template bool requires_range(const StateRange &state_range) const - { - if (state < 0) { - return false; - } - - for (const auto required_state : state_range) { - if (state == required_state) { - return true; - } - } - - return false; - } - - void print_debug(const Context *ctx, IdString object, const Definition &definition) const; - void explain_implies(const Context *ctx, IdString object, IdString cell, const Definition &definition, BelId bel, - int32_t next_state) const; - - template - void explain_requires(const Context *ctx, IdString object, IdString cell, const Definition &definition, BelId bel, - const StateRange state_range) const; -}; - -NEXTPNR_NAMESPACE_END - -#endif diff --git a/common/kernel/exclusive_state_groups.impl.h b/common/kernel/exclusive_state_groups.impl.h deleted file mode 100644 index 6934a028..00000000 --- a/common/kernel/exclusive_state_groups.impl.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 The SymbiFlow Authors. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#pragma once - -#include "context.h" -#include "exclusive_state_groups.h" -#include "log.h" - -NEXTPNR_NAMESPACE_BEGIN - -template -void ExclusiveStateGroup::print_debug(const Context *ctx, IdString object, - const Definition &definition) const -{ - if (state == kNoSelected) { - NPNR_ASSERT(selected_states.count() == 0); - log_info("%s.%s is currently unselected\n", object.c_str(ctx), definition.prefix.c_str(ctx)); - } else if (state >= 0) { - log_info("%s.%s = %s, count = %d\n", object.c_str(ctx), definition.prefix.c_str(ctx), - definition.states.at(state).c_str(ctx), count[state]); - } else { - NPNR_ASSERT(state == kOverConstrained); - log_info("%s.%s is currently overconstrained, states selected:\n", object.c_str(ctx), - definition.prefix.c_str(ctx)); - for (size_t i = 0; i < definition.states.size(); ++i) { - if (selected_states[i]) { - log_info(" - %s, count = %d\n", definition.states.at(i).c_str(ctx), count[i]); - } - } - } -} - -template -void ExclusiveStateGroup::explain_implies(const Context *ctx, IdString object, - IdString cell, const Definition &definition, - BelId bel, int32_t next_state) const -{ - if (check_implies(next_state)) { - log_info("Placing cell %s at bel %s does not violate %s.%s\n", cell.c_str(ctx), ctx->nameOfBel(bel), - object.c_str(ctx), definition.prefix.c_str(ctx)); - } else { - log_info("Placing cell %s at bel %s does violates %s.%s, desired state = %s.\n", cell.c_str(ctx), - ctx->nameOfBel(bel), object.c_str(ctx), definition.prefix.c_str(ctx), - definition.states.at(next_state).c_str(ctx)); - print_debug(ctx, object, definition); - } -} - -template -template -void ExclusiveStateGroup::explain_requires(const Context *ctx, IdString object, - IdString cell, - const Definition &definition, BelId bel, - const StateRange state_range) const -{ - if (requires_range(state_range)) { - log_info("Placing cell %s at bel %s does not violate %s.%s\n", cell.c_str(ctx), ctx->nameOfBel(bel), - object.c_str(ctx), definition.prefix.c_str(ctx)); - } else { - log_info("Placing cell %s at bel %s does violate %s.%s, because current state is %s, constraint requires one " - "of:\n", - cell.c_str(ctx), ctx->nameOfBel(bel), object.c_str(ctx), definition.prefix.c_str(ctx), - state != -1 ? definition.states.at(state).c_str(ctx) : "unset"); - - for (const auto required_state : state_range) { - log_info(" - %s\n", definition.states.at(required_state).c_str(ctx)); - } - print_debug(ctx, object, definition); - } -} - -NEXTPNR_NAMESPACE_END