mirror of
https://github.com/YosysHQ/yosys
synced 2026-05-26 03:46:22 +00:00
Add check_mem command
Comes with a set of tests which (currently) pass with `read_verilog` but fail with `verific` based on #5878. Add `--check-sv`, an alternative to `--prove-sv` with generator defined yosys commands. Helpful for when you want to run the same set of commands on a bunch of sv files.
This commit is contained in:
parent
27ae62f492
commit
a7c8651b76
7 changed files with 210 additions and 4 deletions
|
|
@ -23,6 +23,7 @@
|
|||
#include "kernel/newcelltypes.h"
|
||||
#include "kernel/utils.h"
|
||||
#include "kernel/log_help.h"
|
||||
#include "kernel/mem.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
|
@ -453,4 +454,81 @@ struct CheckPass : public Pass {
|
|||
}
|
||||
} CheckPass;
|
||||
|
||||
struct CheckMemPass : public Pass {
|
||||
CheckMemPass() : Pass("check_mem", "check for obvious memory problems in the design") { }
|
||||
bool formatted_help() override {
|
||||
auto *help = PrettyHelp::get_current();
|
||||
help->set_group("passes/status");
|
||||
|
||||
auto content_root = help->get_root();
|
||||
|
||||
content_root->usage("check_mem [selection]");
|
||||
content_root->paragraph(
|
||||
"This pass identifies the following problems in the current design: "
|
||||
"addressing invalid memory."
|
||||
);
|
||||
|
||||
content_root->option("-assert", "produce a runtime error if any problems are found in the current design");
|
||||
|
||||
return true;
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
int counter = 0;
|
||||
bool assert_mode = false;
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-assert") {
|
||||
assert_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
log_header(design, "Executing CHECK_MEM pass.\n");
|
||||
|
||||
for (auto *module : design->selected_unboxed_modules_warn()) {
|
||||
for (auto mem : Mem::get_selected_memories(module)) {
|
||||
int min_addr = mem.mem->start_offset;
|
||||
int max_addr = mem.mem->size + min_addr - 1;
|
||||
for (auto &init : mem.inits) {
|
||||
int start = init.addr.as_int();
|
||||
if (start < min_addr) {
|
||||
log_warning("Mem %s.%s starts at %d but initializes address %d.\n", log_id(module), log_id(mem.mem), min_addr, start);
|
||||
counter++;
|
||||
}
|
||||
int end = start + (GetSize(init.data) / mem.width) - 1;
|
||||
if (end > max_addr) {
|
||||
log_warning("Mem %s.%s ends at %d but initializes address %d.\n", log_id(module), log_id(mem.mem), max_addr, end);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
auto check_addr = [min_addr, max_addr, &counter, module, &mem](SigSpec &addr_sig, const char* access) {
|
||||
if (addr_sig.is_fully_const()) {
|
||||
auto addr = addr_sig.as_int();
|
||||
if (addr < min_addr || addr > max_addr) {
|
||||
log_warning("Mem %s.%s contains entries for addresses %d..%d but %s address %d.\n", log_id(module), log_id(mem.mem), min_addr, max_addr, access, addr);
|
||||
counter++;
|
||||
}
|
||||
} else {
|
||||
// TODO test variable addresses? may need sat solver
|
||||
}
|
||||
};
|
||||
|
||||
// TODO test ABITS and WIDTH?
|
||||
for (auto &rd_port : mem.rd_ports)
|
||||
check_addr(rd_port.addr, "reads");
|
||||
for (auto &wr_port : mem.wr_ports)
|
||||
check_addr(wr_port.addr, "writes");
|
||||
}
|
||||
}
|
||||
|
||||
if (assert_mode && counter > 0)
|
||||
log_error("Found %d problems in 'check_mem -assert'.\n", counter);
|
||||
}
|
||||
} CheckMemPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue