diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7d257714460..51d02091308 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3280,13 +3280,13 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string return sig; } -RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($set_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::SET, sig_s); cell->setPort(ID::CLR, sig_c); cell->setPort(ID::Y, sig); @@ -3294,37 +3294,50 @@ RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &ta return sig; } -RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($set_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + +RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($get_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } -RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($overwrite_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::SET, sig_s); cell->setPort(ID::CLR, sig_c); cell->set_src_attribute(src); return cell; } -RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src) +RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) { - RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); Cell *cell = addCell(name, ID($original_tag)); - cell->parameters[ID::WIDTH] = sig_e.size(); + cell->parameters[ID::WIDTH] = sig_a.size(); cell->parameters[ID::TAG] = tag; - cell->setPort(ID::A, sig_e); + cell->setPort(ID::A, sig_a); cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 012865a75c6..c50d75e9087 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1465,10 +1465,11 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); - RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); - RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); - RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); + RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = ""); #ifdef WITH_PYTHON diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 24fdf9714c8..9fd356ef65d 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -28,7 +28,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct DftTagOptions { - bool tag_public; + bool tag_public = false; + bool overwrite_only = false; }; struct DftTagWorker { @@ -80,6 +81,78 @@ struct DftTagWorker { tag_sets(tmp_tag_set); } + void resolve_overwrites() + { + std::vector overwrite_cells; + std::vector original_cells; + + bool design_changed = false; + + for (auto cell : module->cells()) { + if (cell->type == ID($overwrite_tag)) + overwrite_cells.push_back(cell); + + if (cell->type == ID($original_tag)) + original_cells.push_back(cell); + } + + for (auto cell : overwrite_cells) { + log_debug("Applying $overwrite_tag %s for signal %s\n", log_id(cell->name), log_signal(cell->getPort(ID::A))); + SigSpec orig_signal = cell->getPort(ID::A); + SigSpec interposed_signal = divert_users(orig_signal); + auto *set_tag_cell = module->addSetTag(NEW_ID, cell->getParam(ID::TAG).decode_string(), orig_signal, cell->getPort(ID::SET), cell->getPort(ID::CLR), interposed_signal); + modwalker.add_cell(set_tag_cell); // Make sure the next $overwrite_tag sees the new connections + design_changed = true; + } + + for (auto cell : overwrite_cells) { + module->remove(cell); + } + for (auto cell : original_cells) { + cell->type = ID($get_tag); + } + + if (design_changed) + modwalker.setup(module); + } + + SigSpec divert_users(SigSpec signal) + { + SigSpec signal_mapped = sigmap(signal); + signal_mapped.sort_and_unify(); + if (GetSize(signal_mapped) < GetSize(signal)) + log_warning("Detected $overwrite_tag on signal %s which contains repeated bits, this can result in unexpected behavior.\n", log_signal(signal)); + SigSpec new_wire = module->addWire(NEW_ID, GetSize(signal)); + for (int i = 0; i < GetSize(new_wire); ++i) + divert_users(signal[i], new_wire[i]); + return new_wire; + } + + void divert_users(SigBit driver_bit, SigBit interposed_bit) + { + dict, SigSpec> updated_ports; + // TODO also check module outputs + auto found = modwalker.signal_consumers.find(driver_bit); + if (found == modwalker.signal_consumers.end()) + return; + for (auto &consumer : found->second) { + if (consumer.cell->type.in(ID($original_tag))) + continue; + if (sigmap(consumer.cell->getPort(consumer.port)[consumer.offset]) != driver_bit) + continue; + std::pair key = {consumer.cell, consumer.port}; + auto found_port = updated_ports.find(key); + if (found_port == updated_ports.end()) { + updated_ports.emplace(key, consumer.cell->getPort(consumer.port)); + } + updated_ports[key][consumer.offset] = interposed_bit; + } + for (auto &update : updated_ports) { + update.first.first->setPort(update.first.second, update.second); + modwalker.add_cell(update.first.first); // Make sure the next $overwrite_tag sees the new connections + } + } + const pool &tag_pool(tag_set set) { return tag_sets[set.index]; } tag_set singleton(IdString tag) @@ -730,9 +803,7 @@ struct DftTagWorker { if (cell->type == ID($set_tag)) set_tag_cells.push_back(cell); - if (cell->type.in(ID($overwrite_tag), ID($original_tag))) - log_error("$overwrite_tag and $original_tag are not supported yet\n"); - // TODO these have to be rewritten as early as possible, so it should be a separate pass invocation + log_assert(!cell->type.in(ID($overwrite_tag), ID($original_tag))); } for (auto cell : set_tag_cells) { @@ -889,6 +960,8 @@ struct DftTagPass : public Pass { log("\n"); log("This pass... TODO\n"); log("\n"); + log(" -overwrite-only\n"); + log(" Only process $overwrite_tag and $original_tag cells.\n"); log(" -tag-public\n"); log(" For each public wire that may carry tagged data, create a new public\n"); log(" wire (named :) that carries the tag bits. Note\n"); @@ -909,6 +982,10 @@ struct DftTagPass : public Pass { options.tag_public = true; continue; } + if (args[argidx] == "-overwrite-only") { + options.overwrite_only = true; + continue; + } break; } @@ -917,6 +994,12 @@ struct DftTagPass : public Pass { for (auto module : design->selected_modules()) { DftTagWorker worker(module, options); + log_debug("Resolve overwrite_tag and original_tag.\n"); + worker.resolve_overwrites(); + + if (options.overwrite_only) + continue; + log_debug("Propagate tagged signals.\n"); worker.propagate_tags(); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 4da67cf630f..a219e470813 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -76,6 +76,9 @@ struct keep_cache_t if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) return true; + if (cell->type.in(ID($overwrite_tag))) + return true; + if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule))) return true;