From a0cbe1a33438a429844bf4d856b726cd3d0aac5e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 20 May 2026 15:18:48 +1200 Subject: [PATCH] verific: Fix non-contiguous memory flattening May not be the best approach, insofar as it uses empty memory elements for padding out the alignment, but it does avoid costly address arithmetic. Still needs to adjust ascii init val addresses, but should work fine for read/write accesses. --- frontends/verific/verific.cc | 81 ++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6a1c81aa4..f909e8e05 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1630,22 +1630,78 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma import_attributes(memory->attributes, net, nl); int number_of_bits = net->Size(); - int bits_in_word = number_of_bits; + int min_bits_in_word = number_of_bits; + int max_bits_in_addr = 0; + + // get the size of each memory access FOREACH_PORTREF_OF_NET(net, si, pr) { - if (pr->GetInst()->Type() == OPER_READ_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->OutputSize()); - continue; + auto *inst = pr->GetInst(); + int bits_in_word; + if (inst->Type() == OPER_READ_PORT) + bits_in_word = inst->OutputSize(); + else if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT) + bits_in_word = inst->Input2Size(); + else + log_error("%sVerific RamNet %s is connected to unsupported instance type %s (%s).\n", announce_src_location(inst), + net->Name(), inst->View()->Owner()->Name(), inst->Name()); + + if (bits_in_word < min_bits_in_word) { + min_bits_in_word = bits_in_word; + max_bits_in_addr = inst->Input1Size(); } - if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) { - bits_in_word = min(bits_in_word, pr->GetInst()->Input2Size()); - continue; - } - log_error("%sVerific RamNet %s is connected to unsupported instance type %s (%s).\n", announce_src_location(pr->GetInst()), - net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name()); } - memory->width = bits_in_word; - memory->size = number_of_bits / bits_in_word; + int number_of_words = number_of_bits / min_bits_in_word; + // TODO Verific has u64 sizes + int size = 1 << max_bits_in_addr; + int min_idx = 0; + int max_idx = size - 1; + + // attempt to infer min/max address for memory definition + RTLIL::SigSpec min_addr, max_addr; + auto typeRange = net->GetOrigTypeRange(); + while (typeRange) { + RTLIL::SigSpec min_addr_chunk(RTLIL::Const(typeRange->RightRangeBound(), typeRange->NumBits())); + min_addr_chunk.reverse(); + min_addr.append(min_addr_chunk); + + RTLIL::SigSpec max_addr_chunk(RTLIL::Const(typeRange->LeftRangeBound(), typeRange->NumBits())); + max_addr_chunk.reverse(); + max_addr.append(max_addr_chunk); + + typeRange = typeRange->GetNext(); + } + min_addr = min_addr.extract(0, max_bits_in_addr); + max_addr = max_addr.extract(0, max_bits_in_addr); + min_addr.reverse(); + max_addr.reverse(); + + if (min_addr.convertible_to_int()) { + min_idx = min_addr.as_int(); + if (max_addr.convertible_to_int()) { + max_idx = max_addr.as_int(); + } else { + log_debug("Unable to set maximum index\n"); + } + size = max_idx - min_idx + 1; + } else { + log_debug("Unable to set minimum index\n"); + } + + // sanity check we haven't shrunk the memory + log_assert(size >= number_of_words); + + memory->width = min_bits_in_word; + memory->size = size; + memory->start_offset = min_idx; + + // warn on oversize memories + // TODO consider using a minimum ratio? + if (size > number_of_words) { + float ratio = size / (float)number_of_words; + log_warning("RAM for identifier '%s' may be up to %.0f%% oversize due to addressing\n", net->Name(), (ratio-1)*100); + log_debug("Expected memory of size %d words, but got %d for address range %d to %d (inclusive)\n", number_of_words, size, min_idx, max_idx); + } const char *ascii_initdata = net->GetWideInitialValue(); if (ascii_initdata) { @@ -1672,6 +1728,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma if (initval_valid) { RTLIL::Cell *cell = module->addCell(new_verific_id(net), ID($meminit)); cell->parameters[ID::WORDS] = 1; + // TODO non contiguous memory addressing if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) cell->setPort(ID::ADDR, word_idx); else