-
Notifications
You must be signed in to change notification settings - Fork 893
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4773 from povik/wrapcell
wrapcell: Add new command
- Loading branch information
Showing
3 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
/* | ||
* yosys -- Yosys Open SYnthesis Suite | ||
* | ||
* Copyright (C) 2024 Martin Povišer <[email protected]> | ||
* | ||
* Permission to use, copy, modify, and/or distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | ||
* copyright notice and this permission notice appear in all copies. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
* | ||
*/ | ||
#include "kernel/yosys.h" | ||
#include "kernel/celltypes.h" | ||
#include "backends/rtlil/rtlil_backend.h" | ||
|
||
USING_YOSYS_NAMESPACE | ||
PRIVATE_NAMESPACE_BEGIN | ||
|
||
std::optional<std::string> format(std::string fmt, const dict<IdString, Const> ¶meters) | ||
{ | ||
std::stringstream result; | ||
|
||
auto it = fmt.begin(); | ||
while (it != fmt.end()) { | ||
if (*it == '{') { | ||
it++; | ||
auto beg = it; | ||
while (it != fmt.end() && *it != '}') it++; | ||
if (it == fmt.end()) { | ||
log("Unclosed curly brackets in format string '%s'\n", fmt.c_str()); | ||
return {}; | ||
} | ||
|
||
auto id = RTLIL::escape_id(std::string(beg, it)); | ||
if (!parameters.count(id)) { | ||
log("Parameter %s referenced in format string '%s' not found\n", log_id(id), fmt.c_str()); | ||
return {}; | ||
} | ||
|
||
RTLIL_BACKEND::dump_const(result, parameters.at(id)); | ||
} else { | ||
result << *it; | ||
} | ||
it++; | ||
} | ||
|
||
return {result.str()}; | ||
} | ||
|
||
struct WrapcellPass : Pass { | ||
WrapcellPass() : Pass("wrapcell", "wrap individual cells into new modules") {} | ||
|
||
void help() override | ||
{ | ||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||
log("\n"); | ||
log(" wrapcell -name <format> [selection]\n"); | ||
log("\n"); | ||
log("This command wraps the selected cells individually into modules. The name for\n"); | ||
log("each wrapper module is derived from the template <format> by substituting\n"); | ||
log("parameter values as specified in curly brackets. If the named module already\n"); | ||
log("exists, it is reused.\n"); | ||
log("\n"); | ||
log(" -setattr <attribute-name>\n"); | ||
log(" set the given boolean attribute on each created wrapper module\n"); | ||
log("\n"); | ||
log(" -formatattr <attribute-name> <format>\n"); | ||
log(" set a string attribute on the created wrapper module by substituting\n"); | ||
log(" parameter values into <format>\n"); | ||
log("\n"); | ||
log("Currently this command only supports wrapping internal cell types.\n"); | ||
log("\n"); | ||
} | ||
|
||
void execute(std::vector<std::string> args, Design *d) override | ||
{ | ||
log_header(d, "Executing WRAPCELL pass. (wrap selected cells)\n"); | ||
|
||
struct AttrRule { | ||
IdString name; | ||
std::string value_fmt; | ||
|
||
AttrRule(IdString name, std::string value_fmt) | ||
: name(name), value_fmt(value_fmt) {} | ||
}; | ||
std::vector<AttrRule> attributes; | ||
std::string name_fmt; | ||
|
||
size_t argidx; | ||
for (argidx = 1; argidx < args.size(); argidx++) { | ||
if (args[argidx] == "-setattr" && argidx+1 < args.size()) { | ||
attributes.emplace_back(RTLIL::escape_id(args[++argidx]), ""); | ||
} else if (args[argidx] == "-formatattr" && argidx+2 < args.size()) { | ||
IdString id = RTLIL::escape_id(args[++argidx]); | ||
attributes.emplace_back(id, args[++argidx]); | ||
} else if (args[argidx] == "-name" && argidx+1 < args.size()) { | ||
name_fmt = args[++argidx]; | ||
} else { | ||
break; | ||
} | ||
} | ||
extra_args(args, argidx, d); | ||
|
||
if (name_fmt.empty()) | ||
log_cmd_error("Argument -name required"); | ||
|
||
CellTypes ct; | ||
ct.setup(); | ||
|
||
for (auto module : d->selected_modules()) { | ||
for (auto cell : module->selected_cells()) { | ||
std::optional<std::string> unescaped_name = format(name_fmt, cell->parameters); | ||
if (!unescaped_name) | ||
log_error("Formatting error when processing cell '%s' in module '%s'\n", | ||
log_id(cell), log_id(module)); | ||
|
||
IdString name = RTLIL::escape_id(unescaped_name.value()); | ||
|
||
if (d->module(name)) { | ||
cell->type = name; | ||
cell->parameters.clear(); | ||
continue; | ||
} | ||
|
||
if (!ct.cell_known(cell->type)) | ||
log_error("Non-internal cell type '%s' on cell '%s' in module '%s' unsupported\n", | ||
log_id(cell->type), log_id(cell), log_id(module)); | ||
|
||
Module *subm = d->addModule(name); | ||
Cell *subcell = subm->addCell("$1", cell->type); | ||
for (auto conn : cell->connections()) { | ||
Wire *w = subm->addWire(conn.first, conn.second.size()); | ||
if (ct.cell_output(cell->type, w->name)) | ||
w->port_output = true; | ||
else | ||
w->port_input = true; | ||
subcell->setPort(conn.first, w); | ||
} | ||
subcell->parameters = cell->parameters; | ||
subm->fixup_ports(); | ||
|
||
for (auto rule : attributes) { | ||
if (rule.value_fmt.empty()) { | ||
subm->set_bool_attribute(rule.name); | ||
} else { | ||
std::optional<std::string> value = format(rule.value_fmt, cell->parameters); | ||
|
||
if (!value) | ||
log_error("Formatting error when processing cell '%s' in module '%s'\n", | ||
log_id(cell), log_id(module)); | ||
|
||
subm->set_string_attribute(rule.name, value.value()); | ||
} | ||
} | ||
|
||
cell->type = name; | ||
cell->parameters.clear(); | ||
} | ||
} | ||
} | ||
} WrapcellPass; | ||
|
||
PRIVATE_NAMESPACE_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
read_verilog <<EOF | ||
module top( | ||
input [1:0] a, | ||
input [2:0] b, | ||
output [2:0] y, | ||
input [2:0] a2, | ||
input [3:0] b2, | ||
output [3:0] y2, | ||
input [1:0] a3, | ||
input [2:0] b3, | ||
output [2:0] y3 | ||
); | ||
assign y = a | (*keep*) b; | ||
assign y2 = a2 | (*keep*) b2; | ||
assign y3 = a3 | (*keep*) b3; | ||
endmodule | ||
EOF | ||
|
||
wreduce | ||
wrapcell -setattr foo -formatattr bar w{Y_WIDTH} -name OR_{A_WIDTH}_{B_WIDTH}_{Y_WIDTH} | ||
select -assert-count 2 top/t:OR_2_3_3 | ||
select -assert-count 1 top/t:OR_3_4_4 | ||
select -assert-none top/t:OR_2_3_3 top/t:OR_3_4_4 %% top/t:* %D | ||
select -assert-mod-count 2 OR_2_3_3 OR_3_4_4 | ||
select -assert-mod-count 2 A:bar=w3 A:bar=w4 |