Compare commits

...

39 Commits

Author SHA1 Message Date
Robert O'Callahan 7bed9e2bc4
Merge 0d3cd5d6c8 into 5d0847f6fb 2025-11-07 00:35:25 -06:00
github-actions[bot] 5d0847f6fb Bump version 2025-11-07 00:24:35 +00:00
KrystalDelusion 24b69cabaa
Merge pull request #5422 from YosysHQ/krys/SVI_support
Catch partial support of SVI
2025-11-07 11:16:07 +13:00
Robert O'Callahan 0d3cd5d6c8 Implement SigSpec::updhash() using a relaxed atomic for thread-safety 2025-10-31 11:53:39 +00:00
Robert O'Callahan 45017e19ec Make SigSpec::unpack() non-const 2025-10-31 11:53:39 +00:00
Robert O'Callahan 9a2fd4c31b Switch the SigSpec packed representation to allow just a single chunk that's inline in the SigSpec.
Single-chunk SigSpecs are very common and this avoids a heap allocation. It also simplifies
some algorithms.
2025-10-31 11:53:39 +00:00
Robert O'Callahan 1af5d4f2db Use chunks iterator for SigSpec::extract() 2025-10-31 11:53:39 +00:00
Robert O'Callahan ab525643a7 Don't reset the hash when unpacking, instead clear the hash whenever bits are modified 2025-10-31 11:53:39 +00:00
Robert O'Callahan a1f7d6c9bf Use size() instead of direct access to width_ in many places 2025-10-31 11:53:39 +00:00
Robert O'Callahan dbb8354996 Remove unnecessary pack() from SigSpec::extend_u0() 2025-10-31 11:53:39 +00:00
Robert O'Callahan d314c47a55 Simplify SigSpec::as_bit() 2025-10-31 11:53:39 +00:00
Robert O'Callahan be530bef73 Instead of using packing and hashing to compute SigSpec ordering and equality, just use the width and chunkwise comparisons
This avoids having to pack and compute hashes, and generally results in a
simpler ordering.
2025-10-31 11:53:39 +00:00
Robert O'Callahan 973e8a3928 Build a temporary SigChunk list in the iterator in the cases where that's needed 2025-10-31 11:53:39 +00:00
Robert O'Callahan 8c9dd3209a Make SigSpec conversion to vector of SigChunk use chunks iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 4672127610 Make SigSpec::parse_rhs use is_chunk to avoid direct access to chunks_ 2025-10-31 11:53:39 +00:00
Robert O'Callahan 11a91af920 Make SigSpec::to_sigbit_pool use chunk iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 8cb7cd7ac1 Make SigSpec::to_sigbit_set use chunk iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 82f86164d3 Use SigSpec::try_as_const in some places 2025-10-31 11:53:39 +00:00
Robert O'Callahan 0d45d9cc6e Make SigSpec::is_one_hot use try_as_const 2025-10-31 11:53:39 +00:00
Robert O'Callahan a0e9e2d364 Fix try_as_const/as_wire/as_chunk 2025-10-31 11:53:39 +00:00
Robert O'Callahan 000c081965 Add try_as_const and use the const iterator a bit more 2025-10-31 11:53:38 +00:00
Robert O'Callahan 04a6dbc562 Make SigSpec::has_marked_bits use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 7bd6b4f287 Make SigSpec::has_const(State) use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 213d665ae1 Make SigSpec::has_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 5c8f9f14ca Make SigSpec::is_fully_undef use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan b2de56cae2 Make SigSpec::is_fully_def use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 8a88acd9b8 Make SigSpec::is_fully_ones use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 58dbf75885 Make SigSpec::is_fully_zero use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 20e64ee17b Make is_fully_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan bf4cfbd72d Make SigSpec::is_wire/is_chunk/is_fully_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan fd7b4f4a8b Make SigSpec::updhash() use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 37e4c2e8f8 Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec 2025-10-31 11:53:38 +00:00
Robert O'Callahan c4f3e61339 Make Module stop accessing internals of SigSpec 2025-10-29 18:32:10 +00:00
Krystine Sherwin c599d6a67e
tests/svinterfaces: re-chmod test script 2025-10-15 09:49:53 +13:00
Krystine Sherwin 10a55119a9
hierarchy.cc: Tidying 2025-10-15 09:42:47 +13:00
Krystine Sherwin 5d2d544109
hierarchy.cc: Don't segfault 2025-10-15 09:38:43 +13:00
Krystine Sherwin 37ba29482e
docs: Amend modports support to all SVI
Also some formatting fixes.
2025-10-15 09:17:52 +13:00
Krystine Sherwin 7bb0a1913e
hierarchy.cc: Raise error on positional interface
Add test to check that it does error.
2025-10-15 09:10:33 +13:00
Krystine Sherwin bbceaa6b5e
docs: Note partial support of modports 2025-10-14 14:59:32 +13:00
12 changed files with 768 additions and 581 deletions

View File

@ -161,7 +161,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE
endif
YOSYS_VER := 0.58+138
YOSYS_VER := 0.58+162
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)

View File

@ -121,7 +121,8 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
for (const auto& chunk : reversed(sig.chunks())) {
auto chunks = sig.chunks();
for (const auto& chunk : reversed(chunks)) {
dump_sigchunk(f, chunk, false);
f << stringf(" ");
}

View File

@ -382,8 +382,9 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
dump_sigchunk(f, sig.as_chunk());
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
if (it != sig.chunks().rbegin())
auto chunks = sig.chunks();
for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) {
if (it != chunks.rbegin())
f << stringf(", ");
dump_sigchunk(f, *it, true);
}

View File

@ -9,7 +9,7 @@ Yosys and there are currently no plans to add support
for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
- The ``tri``, ``triand`` and ``trior`` net types
@ -356,21 +356,29 @@ from SystemVerilog:
files being read into the same design afterwards.
- typedefs are supported (including inside packages)
- type casts are currently not supported
- type casts are currently not supported
- enums are supported (including inside packages)
- but are currently not strongly typed
- but are currently not strongly typed
- packed structs and unions are supported
- arrays of packed structs/unions are currently not supported
- structure literals are currently not supported
- arrays of packed structs/unions are currently not supported
- structure literals are currently not supported
- multidimensional arrays are supported
- array assignment of unpacked arrays is currently not supported
- array literals are currently not supported
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
ports are inputs or outputs are supported.
- array assignment of unpacked arrays is currently not supported
- array literals are currently not supported
- SystemVerilog interfaces (SVIs), including modports for specifying whether
ports are inputs or outputs, are partially supported.
- interfaces must be provided as *named* arguments, not positional arguments.
i.e. ``foo bar(.intf(intf0), .x(x));`` is supported but ``foo bar(intf0,
x);`` is not.
- Assignments within expressions are supported.

File diff suppressed because it is too large Load Diff

View File

@ -1223,9 +1223,10 @@ struct RTLIL::SigSpecConstIterator
typedef RTLIL::SigBit& reference;
const RTLIL::SigSpec *sig_p;
RTLIL::SigBit bit;
int index;
inline const RTLIL::SigBit &operator*() const;
inline const RTLIL::SigBit &operator*();
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
inline void operator++() { index++; }
@ -1234,33 +1235,83 @@ struct RTLIL::SigSpecConstIterator
struct RTLIL::SigSpec
{
private:
int width_;
Hasher::hash_t hash_;
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
enum Representation : char {
CHUNK,
BITS,
};
// An AtomicHash is either clear or a nonzero integer.
struct AtomicHash {
// Create an initially clear value.
AtomicHash() : atomic_(0) {}
AtomicHash(const AtomicHash &rhs) : atomic_(rhs.load()) {}
AtomicHash &operator=(const AtomicHash &rhs) { store(rhs.load()); return *this; }
// Read the hash. Returns nullopt if the hash is clear.
std::optional<Hasher::hash_t> read() const {
Hasher::hash_t value = load();
if (value == 0)
return std::nullopt;
return value;
}
// Set the hash. If the value is already set, then the new value must
// equal the current value.
void set(Hasher::hash_t value) const {
log_assert(value != 0);
Hasher::hash_t old = const_cast<std::atomic<Hasher::hash_t>&>(atomic_)
.exchange(value, std::memory_order_relaxed);
log_assert(old == 0 || old == value);
}
void clear() { store(0); }
private:
int load() const { return atomic_.load(std::memory_order_relaxed); }
void store(Hasher::hash_t value) const {
const_cast<std::atomic<Hasher::hash_t>&>(atomic_).store(value, std::memory_order_relaxed);
}
void pack() const;
void unpack() const;
void updhash() const;
std::atomic<Hasher::hash_t> atomic_;
};
inline bool packed() const {
return bits_.empty();
Representation rep_;
AtomicHash hash_;
union {
RTLIL::SigChunk chunk_;
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
};
void init_empty_bits() {
rep_ = BITS;
new (&bits_) std::vector<RTLIL::SigBit>;
}
inline void inline_unpack() const {
if (!chunks_.empty())
void unpack();
inline void inline_unpack() {
if (rep_ == CHUNK)
unpack();
}
// Only used by Module::remove(const pool<Wire*> &wires)
// but cannot be more specific as it isn't yet declared
friend struct RTLIL::Module;
Hasher::hash_t updhash() const;
void destroy() {
if (rep_ == CHUNK)
chunk_.~SigChunk();
else
bits_.~vector();
}
friend struct Chunks;
public:
SigSpec() : width_(0), hash_(0) {}
SigSpec() { init_empty_bits(); }
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
SigSpec(const SigSpec &value) = default;
SigSpec(SigSpec &&value) = default;
SigSpec(const SigSpec &value) : rep_(value.rep_), hash_(value.hash_) {
if (value.rep_ == CHUNK)
new (&chunk_) RTLIL::SigChunk(value.chunk_);
else
new (&bits_) std::vector<RTLIL::SigBit>(value.bits_);
}
SigSpec(SigSpec &&value) : rep_(value.rep_), hash_(value.hash_) {
if (value.rep_ == CHUNK)
new (&chunk_) RTLIL::SigChunk(std::move(value.chunk_));
else
new (&bits_) std::vector<RTLIL::SigBit>(std::move(value.bits_));
}
SigSpec(const RTLIL::Const &value);
SigSpec(RTLIL::Const &&value);
SigSpec(const RTLIL::SigChunk &chunk);
@ -1276,24 +1327,135 @@ public:
SigSpec(const pool<RTLIL::SigBit> &bits);
SigSpec(const std::set<RTLIL::SigBit> &bits);
explicit SigSpec(bool bit);
~SigSpec() {
destroy();
}
SigSpec &operator=(const SigSpec &rhs) = default;
SigSpec &operator=(SigSpec &&rhs) = default;
SigSpec &operator=(const SigSpec &rhs) {
destroy();
rep_ = rhs.rep_;
hash_ = rhs.hash_;
if (rep_ == CHUNK)
new (&chunk_) RTLIL::SigChunk(rhs.chunk_);
else
new (&bits_) std::vector<RTLIL::SigBit>(rhs.bits_);
return *this;
}
SigSpec &operator=(SigSpec &&rhs) {
destroy();
rep_ = rhs.rep_;
hash_ = rhs.hash_;
if (rep_ == CHUNK)
new (&chunk_) RTLIL::SigChunk(std::move(rhs.chunk_));
else
new (&bits_) std::vector<RTLIL::SigBit>(std::move(rhs.bits_));
return *this;
}
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
struct Chunks {
Chunks(const SigSpec &spec) : spec(spec) {}
struct const_iterator {
using iterator_category = std::forward_iterator_tag;
using value_type = const SigChunk &;
using difference_type = std::ptrdiff_t;
using pointer = const SigChunk *;
using reference = const SigChunk &;
inline int size() const { return width_; }
inline bool empty() const { return width_ == 0; }
const SigSpec &spec;
int bit_index;
SigChunk chunk;
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
const_iterator(const SigSpec &spec) : spec(spec) {
bit_index = 0;
if (spec.rep_ == BITS)
next_chunk_bits();
}
void next_chunk_bits();
const SigChunk &operator*() {
if (spec.rep_ == CHUNK)
return spec.chunk_;
return chunk;
};
const SigChunk *operator->() { return &**this; }
const_iterator &operator++() {
bit_index += (**this).width;
if (spec.rep_ == BITS)
next_chunk_bits();
return *this;
}
bool operator==(const const_iterator &rhs) const { return bit_index == rhs.bit_index; }
bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); }
};
const_iterator begin() const { return const_iterator(spec); }
const_iterator end() const {
const_iterator it(spec);
it.bit_index = spec.size();
return it;
}
// Later we should deprecate these and remove their in-tree calls,
// so we can eventually remove chunk_vector.
std::vector<RTLIL::SigChunk>::const_reverse_iterator rbegin() {
ensure_chunk_vector();
return chunk_vector.rbegin();
}
std::vector<RTLIL::SigChunk>::const_reverse_iterator rend() {
ensure_chunk_vector();
return chunk_vector.rend();
}
int size() {
ensure_chunk_vector();
return chunk_vector.size();
}
int size() const {
int result = 0;
for (const SigChunk &_: *this)
++result;
return result;
}
const SigChunk &at(int index) {
ensure_chunk_vector();
return chunk_vector.at(index);
}
operator const std::vector<RTLIL::SigChunk>&() {
ensure_chunk_vector();
return chunk_vector;
}
private:
void ensure_chunk_vector() {
if (spec.size() > 0 && chunk_vector.empty()) {
for (const RTLIL::SigChunk &c : *this)
chunk_vector.push_back(c);
}
}
const SigSpec &spec;
std::vector<RTLIL::SigChunk> chunk_vector;
};
friend struct Chunks::const_iterator;
inline Chunks chunks() const { return {*this}; }
inline const SigSpec &bits() const { return *this; }
inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); }
inline bool empty() const { return size() == 0; };
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_.clear(); return bits_.at(index); }
inline RTLIL::SigBit operator[](int index) const {
if (rep_ == CHUNK) {
if (index < 0 || index >= chunk_.width)
throw std::out_of_range("SigSpec::operator[]");
if (chunk_.wire)
return RTLIL::SigBit(chunk_.wire, chunk_.offset + index);
return RTLIL::SigBit(chunk_.data[index]);
}
return bits_.at(index);
}
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = size(); return it; }
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = size(); return it; }
void sort();
void sort_and_unify();
@ -1325,10 +1487,14 @@ public:
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) const;
RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }
RTLIL::SigSpec extract_end(int offset) const { return extract(offset, size() - offset); }
RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; };
RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; };
void rewrite_wires(std::function<void(RTLIL::Wire*& wire)> rewrite);
RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; };
RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; };
RTLIL::SigBit front() const { return (*this)[0]; }
RTLIL::SigBit back() const { return (*this)[size() - 1]; }
void append(const RTLIL::SigSpec &signal);
inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); }
@ -1351,7 +1517,7 @@ public:
bool is_wire() const;
bool is_chunk() const;
inline bool is_bit() const { return width_ == 1; }
inline bool is_bit() const { return size() == 1; }
bool known_driver() const;
@ -1388,6 +1554,9 @@ public:
int as_int_saturating(bool is_signed = false) const;
std::string as_string() const;
// Returns std::nullopt if there are any non-constant bits. Returns an empty
// Const if this has zero width.
std::optional<RTLIL::Const> try_as_const() const;
RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const;
RTLIL::SigChunk as_chunk() const;
@ -1405,11 +1574,19 @@ public:
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
operator std::vector<RTLIL::SigChunk>() const;
operator std::vector<RTLIL::SigBit>() const { return to_sigbit_vector(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; }
[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }
[[nodiscard]] Hasher hash_into(Hasher h) const {
Hasher::hash_t val;
if (std::optional<Hasher::hash_t> current = hash_.read())
val = *current;
else
val = updhash();
h.eat(val);
return h;
}
#ifndef NDEBUG
void check(Module *mod = nullptr) const;
@ -2314,13 +2491,15 @@ inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
return (*sig_p)[index];
}
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
return (*sig_p)[index];
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() {
bit = (*sig_p)[index];
return bit;
}
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
*this = SigBit(sig.chunks().front());
log_assert(sig.size() == 1);
auto it = sig.chunks().begin();
*this = SigBit(*it);
}
template<typename T>

View File

@ -277,14 +277,26 @@ inline int ceil_log2(int x)
#endif
}
template <typename T>
auto reversed(T& container) {
struct reverse_view {
reverse_view(T& container) : container(container) {}
auto begin() const { return container.rbegin(); }
auto end() const { return container.rend(); }
T& container;
};
return reverse_view{container};
}
template <typename T>
auto reversed(const T& container) {
struct reverse_view {
const T& cont;
auto begin() const { return cont.rbegin(); }
auto end() const { return cont.rend(); }
};
return reverse_view{container};
struct reverse_view {
reverse_view(const T& container) : container(container) {}
auto begin() const { return container.rbegin(); }
auto end() const { return container.rend(); }
const T& container;
};
return reverse_view{container};
}
YOSYS_NAMESPACE_END

View File

@ -278,11 +278,12 @@ struct ShowWorker
std::vector<std::string> label_pieces;
int bitpos = sig.size()-1;
for (int rep, chunk_idx = ((int) sig.chunks().size()) - 1; chunk_idx >= 0; chunk_idx -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(chunk_idx);
RTLIL::SigSpec::Chunks sig_chunks = sig.chunks();
for (int rep, chunk_idx = ((int) sig_chunks.size()) - 1; chunk_idx >= 0; chunk_idx -= rep) {
const RTLIL::SigChunk &c = sig_chunks.at(chunk_idx);
// Find the number of times this chunk is repeating
for (rep = 1; chunk_idx - rep >= 0 && c == sig.chunks().at(chunk_idx - rep); rep++);
for (rep = 1; chunk_idx - rep >= 0 && c == sig_chunks.at(chunk_idx - rep); rep++);
int cl, cr;
cl = c.offset + c.width - 1;

View File

@ -156,6 +156,21 @@ std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
return basicType;
}
// Try to read an IdString as a numbered connection name ("$123" or similar),
// writing the result to dst. If the string isn't of the right format, ignore
// dst and return false.
bool read_id_num(RTLIL::IdString str, int *dst)
{
log_assert(dst);
const char *c_str = str.c_str();
if (c_str[0] != '$' || !('0' <= c_str[1] && c_str[1] <= '9'))
return false;
*dst = atoi(c_str + 1);
return true;
}
// A helper struct for expanding a module's interface connections in expand_module
struct IFExpander
{
@ -283,15 +298,42 @@ struct IFExpander
RTLIL::IdString conn_name,
const RTLIL::SigSpec &conn_signals)
{
// Check if the connection is present as an interface in the sub-module's port list
const RTLIL::Wire *wire = submodule.wire(conn_name);
if (!wire || !wire->get_bool_attribute(ID::is_interface))
// Does the connection look like an interface
if (
conn_signals.size() != 1 ||
conn_signals[0].wire == nullptr ||
conn_signals[0].wire->get_bool_attribute(ID::is_interface) == false ||
conn_signals[0].wire->name.str().find("$dummywireforinterface") != 0
)
return;
// Check if the connection is present as an interface in the sub-module's port list
int id;
if (read_id_num(conn_name, &id)) {
/* Interface expansion is incompatible with positional arguments
* during expansion, the port list gets each interface signal
* inserted after the interface itself which means that the argument
* positions in the parent module no longer match.
*
* Supporting this would require expanding the interfaces in the
* parent module, renumbering the arguments to match, and then
* iterating over the ports list to find the matching interface
* (refactoring on_interface to accept different conn_names on the
* parent and child).
*/
log_error("Unable to connect `%s' to submodule `%s' with positional interface argument `%s'!\n",
module.name,
submodule.name,
conn_signals[0].wire->name.str().substr(23)
);
} else {
// Lookup connection by name
const RTLIL::Wire *wire = submodule.wire(conn_name);
if (!wire || !wire->get_bool_attribute(ID::is_interface))
return;
}
// If the connection looks like an interface, handle it.
const auto &bits = conn_signals;
if (bits.size() == 1 && bits[0].wire->get_bool_attribute(ID::is_interface))
on_interface(submodule, conn_name, conn_signals);
on_interface(submodule, conn_name, conn_signals);
}
// Iterate over the connections in a cell, tracking any interface
@ -376,21 +418,6 @@ RTLIL::Module *get_module(RTLIL::Design &design,
return nullptr;
}
// Try to read an IdString as a numbered connection name ("$123" or similar),
// writing the result to dst. If the string isn't of the right format, ignore
// dst and return false.
bool read_id_num(RTLIL::IdString str, int *dst)
{
log_assert(dst);
const char *c_str = str.c_str();
if (c_str[0] != '$' || !('0' <= c_str[1] && c_str[1] <= '9'))
return false;
*dst = atoi(c_str + 1);
return true;
}
// Check that the connections on the cell match those that are defined
// on the type: each named connection should match the name of a port
// and each positional connection should have an index smaller than

View File

@ -1428,13 +1428,13 @@ void reintegrate(RTLIL::Module *module, bool dff_mode)
// Copy connections (and rename) from mapped_mod to module
for (auto conn : mapped_mod->connections()) {
if (!conn.first.is_fully_const()) {
auto chunks = conn.first.chunks();
std::vector<RTLIL::SigChunk> chunks = conn.first.chunks();
for (auto &c : chunks)
c.wire = module->wires_.at(remap_name(c.wire->name));
conn.first = std::move(chunks);
}
if (!conn.second.is_fully_const()) {
auto chunks = conn.second.chunks();
std::vector<RTLIL::SigChunk> chunks = conn.second.chunks();
for (auto &c : chunks)
if (c.wire)
c.wire = module->wires_.at(remap_name(c.wire->name));

View File

@ -0,0 +1,33 @@
read_verilog -sv << EOF
interface simple_if;
logic receiver;
logic driver;
endinterface
module driver_mod(simple_if intf, input in);
assign intf.driver = in;
endmodule
module receiver_mod(simple_if intf);
assign intf.receiver = intf.driver;
endmodule
module top(
input logic [1:0] inputs,
output logic [1:0] outputs
);
simple_if intf0();
simple_if intf1();
driver_mod d0(intf0, inputs[0]);
driver_mod d1(intf1, inputs[1]);
receiver_mod r0(intf0);
receiver_mod r1(intf1);
assign outputs = {intf0.receiver, intf1.receiver};
endmodule
EOF
logger -expect error "Unable to connect.* with positional interface" 1
hierarchy -top top

View File

@ -5,3 +5,4 @@
./run_simple.sh load_and_derive
./run_simple.sh resolve_types
./run_simple.sh positional_args