mirror of https://github.com/YosysHQ/yosys.git
307 lines
8.0 KiB
C++
307 lines
8.0 KiB
C++
/*
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
*
|
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
|
*
|
|
* 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/register.h"
|
|
#include "kernel/celltypes.h"
|
|
#include "kernel/sigtools.h"
|
|
#include "kernel/rtlil.h"
|
|
#include "kernel/log.h"
|
|
|
|
static bool consider_wire(RTLIL::Wire *wire)
|
|
{
|
|
if (wire->name[0] == '$')
|
|
return false;
|
|
if (wire->port_input)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool consider_cell(RTLIL::Design *design, RTLIL::Cell *cell)
|
|
{
|
|
if (cell->name[0] == '$')
|
|
return false;
|
|
if (design->modules.count(cell->type) == 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
|
|
{
|
|
log_assert(wire1->name == wire2->name);
|
|
if (wire1->width != wire2->width)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
|
|
{
|
|
log_assert(cell1->name == cell2->name);
|
|
if (cell1->type != cell2->type)
|
|
return false;
|
|
if (cell1->parameters != cell2->parameters)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static void find_dff_wires(std::set<std::string> &dff_wires, RTLIL::Module *module)
|
|
{
|
|
CellTypes ct;
|
|
ct.setup_internals_mem();
|
|
ct.setup_stdcells_mem();
|
|
|
|
SigMap sigmap(module);
|
|
SigPool dffsignals;
|
|
|
|
for (auto &it : module->cells) {
|
|
if (ct.cell_known(it.second->type) && it.second->connections.count("\\Q"))
|
|
dffsignals.add(sigmap(it.second->connections.at("\\Q")));
|
|
}
|
|
|
|
for (auto &it : module->wires) {
|
|
if (dffsignals.check_any(it.second))
|
|
dff_wires.insert(it.first);
|
|
}
|
|
}
|
|
|
|
struct ExposePass : public Pass {
|
|
ExposePass() : Pass("expose", "convert internal signals to module ports") { }
|
|
virtual void help()
|
|
{
|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
log("\n");
|
|
log(" expose [options] [selection]\n");
|
|
log("\n");
|
|
log("This command exposes all selected internal signals of a module as additional\n");
|
|
log("outputs.\n");
|
|
log("\n");
|
|
log(" -dff\n");
|
|
log(" only consider wires that are directly driven by register cell.\n");
|
|
log("\n");
|
|
log(" -shared\n");
|
|
log(" only expose those signals that are shared ammong the selected modules.\n");
|
|
log(" this is useful for preparing modules for equivialence checking.\n");
|
|
log("\n");
|
|
log(" -evert\n");
|
|
log(" also turn connections to instances of other modules to additional\n");
|
|
log(" inputs and outputs and remove the module instances.\n");
|
|
log("\n");
|
|
}
|
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
|
{
|
|
bool flag_shared = false;
|
|
bool flag_evert = false;
|
|
bool flag_dff = false;
|
|
|
|
size_t argidx;
|
|
for (argidx = 1; argidx < args.size(); argidx++)
|
|
{
|
|
if (args[argidx] == "-shared") {
|
|
flag_shared = true;
|
|
continue;
|
|
}
|
|
if (args[argidx] == "-evert") {
|
|
flag_evert = true;
|
|
continue;
|
|
}
|
|
if (args[argidx] == "-dff") {
|
|
flag_dff = true;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
extra_args(args, argidx, design);
|
|
|
|
std::set<std::string> shared_wires, shared_cells;
|
|
std::set<std::string> used_names;
|
|
|
|
if (flag_shared)
|
|
{
|
|
RTLIL::Module *first_module = NULL;
|
|
|
|
for (auto &mod_it : design->modules)
|
|
{
|
|
RTLIL::Module *module = mod_it.second;
|
|
|
|
if (!design->selected(module))
|
|
continue;
|
|
|
|
std::set<std::string> dff_wires;
|
|
if (flag_dff)
|
|
find_dff_wires(dff_wires, module);
|
|
|
|
if (first_module == NULL)
|
|
{
|
|
for (auto &it : module->wires)
|
|
if (design->selected(module, it.second) && consider_wire(it.second))
|
|
if (!flag_dff || dff_wires.count(it.first))
|
|
shared_wires.insert(it.first);
|
|
|
|
if (flag_evert)
|
|
for (auto &it : module->cells)
|
|
if (design->selected(module, it.second) && consider_cell(design, it.second))
|
|
shared_cells.insert(it.first);
|
|
|
|
first_module = module;
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::string> delete_shared_wires, delete_shared_cells;
|
|
|
|
for (auto &it : shared_wires)
|
|
{
|
|
RTLIL::Wire *wire;
|
|
|
|
if (module->wires.count(it) == 0)
|
|
goto delete_shared_wire;
|
|
|
|
wire = module->wires.at(it);
|
|
|
|
if (!design->selected(module, wire))
|
|
goto delete_shared_wire;
|
|
if (!consider_wire(wire))
|
|
goto delete_shared_wire;
|
|
if (!compare_wires(first_module->wires.at(it), wire))
|
|
goto delete_shared_wire;
|
|
if (flag_dff && !dff_wires.count(it))
|
|
goto delete_shared_wire;
|
|
|
|
if (0)
|
|
delete_shared_wire:
|
|
delete_shared_wires.push_back(it);
|
|
}
|
|
|
|
if (flag_evert)
|
|
for (auto &it : shared_cells)
|
|
{
|
|
RTLIL::Cell *cell;
|
|
|
|
if (module->cells.count(it) == 0)
|
|
goto delete_shared_cell;
|
|
|
|
cell = module->cells.at(it);
|
|
|
|
if (!design->selected(module, cell))
|
|
goto delete_shared_cell;
|
|
if (!consider_cell(design, cell))
|
|
goto delete_shared_cell;
|
|
if (!compare_cells(first_module->cells.at(it), cell))
|
|
goto delete_shared_cell;
|
|
|
|
if (0)
|
|
delete_shared_cell:
|
|
delete_shared_cells.push_back(it);
|
|
}
|
|
|
|
for (auto &it : delete_shared_wires)
|
|
shared_wires.erase(it);
|
|
for (auto &it : delete_shared_cells)
|
|
shared_cells.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto &mod_it : design->modules)
|
|
{
|
|
RTLIL::Module *module = mod_it.second;
|
|
|
|
if (!design->selected(module))
|
|
continue;
|
|
|
|
std::set<std::string> dff_wires;
|
|
if (flag_dff && !flag_shared)
|
|
find_dff_wires(dff_wires, module);
|
|
|
|
for (auto &it : module->wires)
|
|
{
|
|
if (flag_shared) {
|
|
if (shared_wires.count(it.first) == 0)
|
|
continue;
|
|
} else {
|
|
if (!design->selected(module, it.second) || !consider_wire(it.second))
|
|
continue;
|
|
if (flag_dff && !dff_wires.count(it.first))
|
|
continue;
|
|
}
|
|
|
|
if (!it.second->port_output) {
|
|
it.second->port_output = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
|
|
}
|
|
}
|
|
|
|
if (flag_evert)
|
|
{
|
|
std::vector<std::string> delete_cells;
|
|
|
|
for (auto &it : module->cells)
|
|
{
|
|
if (flag_shared) {
|
|
if (shared_cells.count(it.first) == 0)
|
|
continue;
|
|
} else {
|
|
if (!design->selected(module, it.second) || !consider_cell(design, it.second))
|
|
continue;
|
|
}
|
|
|
|
RTLIL::Cell *cell = it.second;
|
|
RTLIL::Module *mod = design->modules.at(cell->type);
|
|
|
|
for (auto &it : mod->wires)
|
|
{
|
|
RTLIL::Wire *p = it.second;
|
|
if (!p->port_input && !p->port_output)
|
|
continue;
|
|
|
|
RTLIL::Wire *w = new RTLIL::Wire;
|
|
w->name = cell->name + "." + RTLIL::unescape_id(p->name);
|
|
w->width = p->width;
|
|
if (p->port_input)
|
|
w->port_output = true;
|
|
if (p->port_output)
|
|
w->port_input = true;
|
|
module->add(w);
|
|
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
|
|
|
|
RTLIL::SigSpec sig;
|
|
if (cell->connections.count(p->name) != 0)
|
|
sig = cell->connections.at(p->name);
|
|
sig.extend(w->width);
|
|
if (w->port_input)
|
|
module->connections.push_back(RTLIL::SigSig(sig, w));
|
|
else
|
|
module->connections.push_back(RTLIL::SigSig(w, sig));
|
|
}
|
|
|
|
delete_cells.push_back(cell->name);
|
|
}
|
|
|
|
for (auto &it : delete_cells) {
|
|
log("Removing cell: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it));
|
|
delete module->cells.at(it);
|
|
module->cells.erase(it);
|
|
}
|
|
}
|
|
|
|
module->fixup_ports();
|
|
}
|
|
}
|
|
} ExposePass;
|
|
|