Skip to content

Commit

Permalink
dft_tag: Implement $overwrite_tag and $original_tag
Browse files Browse the repository at this point in the history
This does not correctly handle an `$overwrite_tag` on a module output,
but since we currently require the user to flatten the design for
cross-module dft, this cannot be observed from within the design, only
by manually inspecting the signals in the design.
  • Loading branch information
jix committed Sep 13, 2023
1 parent 78ff40d commit 62b4df4
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 23 deletions.
43 changes: 28 additions & 15 deletions kernel/rtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3280,51 +3280,64 @@ 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);
cell->set_src_attribute(src);
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;
Expand Down
9 changes: 5 additions & 4 deletions kernel/rtlil.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
91 changes: 87 additions & 4 deletions passes/cmds/dft_tag.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -80,6 +81,78 @@ struct DftTagWorker {
tag_sets(tmp_tag_set);
}

void resolve_overwrites()
{
std::vector<Cell *> overwrite_cells;
std::vector<Cell *> 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<std::pair<Cell *, IdString>, 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<Cell *, IdString> 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<IdString> &tag_pool(tag_set set) { return tag_sets[set.index]; }

tag_set singleton(IdString tag)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 <wirename>:<tagname>) that carries the tag bits. Note\n");
Expand All @@ -909,6 +982,10 @@ struct DftTagPass : public Pass {
options.tag_public = true;
continue;
}
if (args[argidx] == "-overwrite-only") {
options.overwrite_only = true;
continue;
}
break;
}

Expand All @@ -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();

Expand Down
3 changes: 3 additions & 0 deletions passes/opt/opt_clean.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 62b4df4

Please sign in to comment.