686 lines
20 KiB
C++
686 lines
20 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"
|
|
|
|
USING_YOSYS_NAMESPACE
|
|
PRIVATE_NAMESPACE_BEGIN
|
|
|
|
struct dff_map_info_t {
|
|
RTLIL::SigSpec sig_d, sig_clk, sig_arst;
|
|
bool clk_polarity, arst_polarity;
|
|
RTLIL::Const arst_value;
|
|
std::vector<RTLIL::IdString> cells;
|
|
};
|
|
|
|
struct dff_map_bit_info_t {
|
|
RTLIL::SigBit bit_d, bit_clk, bit_arst;
|
|
bool clk_polarity, arst_polarity;
|
|
RTLIL::State arst_value;
|
|
RTLIL::Cell *cell;
|
|
};
|
|
|
|
bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
|
|
{
|
|
if (wire->name[0] == '$' || dff_dq_map.count(wire->name))
|
|
return false;
|
|
if (wire->port_input)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
|
|
{
|
|
if (cell->name[0] == '$' || dff_cells.count(cell->name))
|
|
return false;
|
|
if (cell->type[0] == '\\' && !design->modules_.count(cell->type))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
|
|
{
|
|
log_assert(wire1->name == wire2->name);
|
|
if (wire1->width != wire2->width)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void find_dff_wires(std::set<RTLIL::IdString> &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->hasPort("\\Q"))
|
|
dffsignals.add(sigmap(it.second->getPort("\\Q")));
|
|
}
|
|
|
|
for (auto &it : module->wires_) {
|
|
if (dffsignals.check_any(it.second))
|
|
dff_wires.insert(it.first);
|
|
}
|
|
}
|
|
|
|
void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
|
|
{
|
|
std::map<RTLIL::SigBit, dff_map_bit_info_t> bit_info;
|
|
SigMap sigmap(module);
|
|
|
|
for (auto &it : module->cells_)
|
|
{
|
|
if (!design->selected(module, it.second))
|
|
continue;
|
|
|
|
dff_map_bit_info_t info;
|
|
info.bit_d = RTLIL::State::Sm;
|
|
info.bit_clk = RTLIL::State::Sm;
|
|
info.bit_arst = RTLIL::State::Sm;
|
|
info.clk_polarity = false;
|
|
info.arst_polarity = false;
|
|
info.arst_value = RTLIL::State::Sm;
|
|
info.cell = it.second;
|
|
|
|
if (info.cell->type == "$dff") {
|
|
info.bit_clk = sigmap(info.cell->getPort("\\CLK")).as_bit();
|
|
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
|
|
std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
|
|
std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
|
|
for (size_t i = 0; i < sig_d.size(); i++) {
|
|
info.bit_d = sig_d.at(i);
|
|
bit_info[sig_q.at(i)] = info;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (info.cell->type == "$adff") {
|
|
info.bit_clk = sigmap(info.cell->getPort("\\CLK")).as_bit();
|
|
info.bit_arst = sigmap(info.cell->getPort("\\ARST")).as_bit();
|
|
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
|
|
info.arst_polarity = info.cell->parameters.at("\\ARST_POLARITY").as_bool();
|
|
std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
|
|
std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
|
|
std::vector<RTLIL::State> arst_value = info.cell->parameters.at("\\ARST_VALUE").bits;
|
|
for (size_t i = 0; i < sig_d.size(); i++) {
|
|
info.bit_d = sig_d.at(i);
|
|
info.arst_value = arst_value.at(i);
|
|
bit_info[sig_q.at(i)] = info;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") {
|
|
info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit();
|
|
info.clk_polarity = info.cell->type == "$_DFF_P_";
|
|
info.bit_d = sigmap(info.cell->getPort("\\D")).as_bit();
|
|
bit_info[sigmap(info.cell->getPort("\\Q")).as_bit()] = info;
|
|
continue;
|
|
}
|
|
|
|
if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") {
|
|
info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit();
|
|
info.bit_arst = sigmap(info.cell->getPort("\\R")).as_bit();
|
|
info.clk_polarity = info.cell->type[6] == 'P';
|
|
info.arst_polarity = info.cell->type[7] == 'P';
|
|
info.arst_value = info.cell->type[0] == '1' ? RTLIL::State::S1 : RTLIL::State::S0;
|
|
info.bit_d = sigmap(info.cell->getPort("\\D")).as_bit();
|
|
bit_info[sigmap(info.cell->getPort("\\Q")).as_bit()] = info;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
std::map<RTLIL::IdString, dff_map_info_t> empty_dq_map;
|
|
for (auto &it : module->wires_)
|
|
{
|
|
if (!consider_wire(it.second, empty_dq_map))
|
|
continue;
|
|
|
|
std::vector<RTLIL::SigBit> bits_q = sigmap(it.second).to_sigbit_vector();
|
|
std::vector<RTLIL::SigBit> bits_d;
|
|
std::vector<RTLIL::State> arst_value;
|
|
std::set<RTLIL::Cell*> cells;
|
|
|
|
if (bits_q.empty() || !bit_info.count(bits_q.front()))
|
|
continue;
|
|
|
|
dff_map_bit_info_t ref_info = bit_info.at(bits_q.front());
|
|
for (auto &bit : bits_q) {
|
|
if (!bit_info.count(bit))
|
|
break;
|
|
dff_map_bit_info_t info = bit_info.at(bit);
|
|
if (info.bit_clk != ref_info.bit_clk)
|
|
break;
|
|
if (info.bit_arst != ref_info.bit_arst)
|
|
break;
|
|
if (info.clk_polarity != ref_info.clk_polarity)
|
|
break;
|
|
if (info.arst_polarity != ref_info.arst_polarity)
|
|
break;
|
|
bits_d.push_back(info.bit_d);
|
|
arst_value.push_back(info.arst_value);
|
|
cells.insert(info.cell);
|
|
}
|
|
|
|
if (bits_d.size() != bits_q.size())
|
|
continue;
|
|
|
|
dff_map_info_t info;
|
|
info.sig_d = bits_d;
|
|
info.sig_clk = ref_info.bit_clk;
|
|
info.sig_arst = ref_info.bit_arst;
|
|
info.clk_polarity = ref_info.clk_polarity;
|
|
info.arst_polarity = ref_info.arst_polarity;
|
|
info.arst_value = arst_value;
|
|
for (auto it : cells)
|
|
info.cells.push_back(it->name);
|
|
map[it.first] = info;
|
|
}
|
|
}
|
|
|
|
RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
|
|
{
|
|
if (module->count_id(name))
|
|
log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", log_id(name));
|
|
return module->addWire(name, width);
|
|
}
|
|
|
|
struct ExposePass : public Pass {
|
|
ExposePass() : Pass("expose", "convert internal signals to module ports") { }
|
|
void help() YS_OVERRIDE
|
|
{
|
|
// |---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(" -cut\n");
|
|
log(" when exposing a wire, create an input/output pair and cut the internal\n");
|
|
log(" signal path at that wire.\n");
|
|
log("\n");
|
|
log(" -input\n");
|
|
log(" when exposing a wire, create an input port and disconnect the internal\n");
|
|
log(" driver.\n");
|
|
log("\n");
|
|
log(" -shared\n");
|
|
log(" only expose those signals that are shared among the selected modules.\n");
|
|
log(" this is useful for preparing modules for equivalence 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");
|
|
log(" -evert-dff\n");
|
|
log(" turn flip-flops to sets of inputs and outputs.\n");
|
|
log("\n");
|
|
log(" -sep <separator>\n");
|
|
log(" when creating new wire/port names, the original object name is suffixed\n");
|
|
log(" with this separator (default: '.') and the port name or a type\n");
|
|
log(" designator for the exposed signal.\n");
|
|
log("\n");
|
|
}
|
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
|
{
|
|
bool flag_shared = false;
|
|
bool flag_evert = false;
|
|
bool flag_dff = false;
|
|
bool flag_cut = false;
|
|
bool flag_input = false;
|
|
bool flag_evert_dff = false;
|
|
std::string sep = ".";
|
|
|
|
log_header(design, "Executing EXPOSE pass (exposing internal signals as outputs).\n");
|
|
|
|
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;
|
|
}
|
|
if (args[argidx] == "-cut" && !flag_input) {
|
|
flag_cut = true;
|
|
continue;
|
|
}
|
|
if (args[argidx] == "-input" && !flag_cut) {
|
|
flag_input = true;
|
|
continue;
|
|
}
|
|
if (args[argidx] == "-evert-dff") {
|
|
flag_evert_dff = true;
|
|
continue;
|
|
}
|
|
if (args[argidx] == "-sep" && argidx+1 < args.size()) {
|
|
sep = args[++argidx];
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
extra_args(args, argidx, design);
|
|
|
|
CellTypes ct(design);
|
|
|
|
std::map<RTLIL::Module*, std::map<RTLIL::IdString, dff_map_info_t>> dff_dq_maps;
|
|
std::map<RTLIL::Module*, std::set<RTLIL::IdString>> dff_cells;
|
|
|
|
if (flag_evert_dff)
|
|
{
|
|
RTLIL::Module *first_module = NULL;
|
|
std::set<RTLIL::IdString> shared_dff_wires;
|
|
|
|
for (auto &mod_it : design->modules_)
|
|
{
|
|
if (!design->selected(mod_it.second))
|
|
continue;
|
|
|
|
create_dff_dq_map(dff_dq_maps[mod_it.second], design, mod_it.second);
|
|
|
|
if (!flag_shared)
|
|
continue;
|
|
|
|
if (first_module == NULL) {
|
|
for (auto &it : dff_dq_maps[mod_it.second])
|
|
shared_dff_wires.insert(it.first);
|
|
first_module = mod_it.second;
|
|
} else {
|
|
std::set<RTLIL::IdString> new_shared_dff_wires;
|
|
for (auto &it : shared_dff_wires) {
|
|
if (!dff_dq_maps[mod_it.second].count(it))
|
|
continue;
|
|
if (!compare_wires(first_module->wires_.at(it), mod_it.second->wires_.at(it)))
|
|
continue;
|
|
new_shared_dff_wires.insert(it);
|
|
}
|
|
shared_dff_wires.swap(new_shared_dff_wires);
|
|
}
|
|
}
|
|
|
|
if (flag_shared)
|
|
for (auto &map_it : dff_dq_maps)
|
|
{
|
|
std::map<RTLIL::IdString, dff_map_info_t> new_map;
|
|
for (auto &it : map_it.second)
|
|
if (shared_dff_wires.count(it.first))
|
|
new_map[it.first] = it.second;
|
|
map_it.second.swap(new_map);
|
|
}
|
|
|
|
for (auto &it1 : dff_dq_maps)
|
|
for (auto &it2 : it1.second)
|
|
for (auto &it3 : it2.second.cells)
|
|
dff_cells[it1.first].insert(it3);
|
|
}
|
|
|
|
std::set<RTLIL::IdString> shared_wires, shared_cells;
|
|
std::set<RTLIL::IdString> 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<RTLIL::IdString> 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, dff_dq_maps[module]))
|
|
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, dff_cells[module], it.second))
|
|
shared_cells.insert(it.first);
|
|
|
|
first_module = module;
|
|
}
|
|
else
|
|
{
|
|
std::vector<RTLIL::IdString> 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, dff_dq_maps[module]))
|
|
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, dff_cells[module], 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<RTLIL::IdString> dff_wires;
|
|
if (flag_dff && !flag_shared)
|
|
find_dff_wires(dff_wires, module);
|
|
|
|
SigMap sigmap(module);
|
|
|
|
SigMap out_to_in_map;
|
|
|
|
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, dff_dq_maps[module]))
|
|
continue;
|
|
if (flag_dff && !dff_wires.count(it.first))
|
|
continue;
|
|
}
|
|
|
|
if (flag_input)
|
|
{
|
|
if (!it.second->port_input) {
|
|
it.second->port_input = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
|
|
RTLIL::Wire *w = module->addWire(NEW_ID, GetSize(it.second));
|
|
out_to_in_map.add(it.second, w);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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_cut) {
|
|
RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
|
|
in_wire->port_input = true;
|
|
out_to_in_map.add(sigmap(it.second), in_wire);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag_input)
|
|
{
|
|
for (auto &it : module->cells_) {
|
|
if (!ct.cell_known(it.second->type))
|
|
continue;
|
|
for (auto &conn : it.second->connections_)
|
|
if (ct.cell_output(it.second->type, conn.first))
|
|
conn.second = out_to_in_map(sigmap(conn.second));
|
|
}
|
|
|
|
for (auto &conn : module->connections_)
|
|
conn.first = out_to_in_map(conn.first);
|
|
}
|
|
|
|
if (flag_cut)
|
|
{
|
|
for (auto &it : module->cells_) {
|
|
if (!ct.cell_known(it.second->type))
|
|
continue;
|
|
for (auto &conn : it.second->connections_)
|
|
if (ct.cell_input(it.second->type, conn.first))
|
|
conn.second = out_to_in_map(sigmap(conn.second));
|
|
}
|
|
|
|
for (auto &conn : module->connections_)
|
|
conn.second = out_to_in_map(sigmap(conn.second));
|
|
}
|
|
|
|
std::set<RTLIL::SigBit> set_q_bits;
|
|
|
|
for (auto &dq : dff_dq_maps[module])
|
|
{
|
|
if (!module->wires_.count(dq.first))
|
|
continue;
|
|
|
|
RTLIL::Wire *wire = module->wires_.at(dq.first);
|
|
std::set<RTLIL::SigBit> wire_bits_set = sigmap(wire).to_sigbit_set();
|
|
std::vector<RTLIL::SigBit> wire_bits_vec = sigmap(wire).to_sigbit_vector();
|
|
|
|
dff_map_info_t &info = dq.second;
|
|
|
|
RTLIL::Wire *wire_dummy_q = add_new_wire(module, NEW_ID, 0);
|
|
|
|
for (auto &cell_name : info.cells) {
|
|
RTLIL::Cell *cell = module->cells_.at(cell_name);
|
|
std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->getPort("\\Q")).to_sigbit_vector();
|
|
for (auto &bit : cell_q_bits)
|
|
if (wire_bits_set.count(bit))
|
|
bit = RTLIL::SigBit(wire_dummy_q, wire_dummy_q->width++);
|
|
cell->setPort("\\Q", cell_q_bits);
|
|
}
|
|
|
|
RTLIL::Wire *wire_q = add_new_wire(module, wire->name.str() + sep + "q", wire->width);
|
|
wire_q->port_input = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_q->name));
|
|
|
|
RTLIL::SigSig connect_q;
|
|
for (size_t i = 0; i < wire_bits_vec.size(); i++) {
|
|
if (set_q_bits.count(wire_bits_vec[i]))
|
|
continue;
|
|
connect_q.first.append(wire_bits_vec[i]);
|
|
connect_q.second.append(RTLIL::SigBit(wire_q, i));
|
|
set_q_bits.insert(wire_bits_vec[i]);
|
|
}
|
|
module->connect(connect_q);
|
|
|
|
RTLIL::Wire *wire_d = add_new_wire(module, wire->name.str() + sep + "d", wire->width);
|
|
wire_d->port_output = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_d->name));
|
|
module->connect(RTLIL::SigSig(wire_d, info.sig_d));
|
|
|
|
RTLIL::Wire *wire_c = add_new_wire(module, wire->name.str() + sep + "c");
|
|
wire_c->port_output = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_c->name));
|
|
if (info.clk_polarity) {
|
|
module->connect(RTLIL::SigSig(wire_c, info.sig_clk));
|
|
} else {
|
|
RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
|
|
c->parameters["\\A_SIGNED"] = 0;
|
|
c->parameters["\\A_WIDTH"] = 1;
|
|
c->parameters["\\Y_WIDTH"] = 1;
|
|
c->setPort("\\A", info.sig_clk);
|
|
c->setPort("\\Y", wire_c);
|
|
}
|
|
|
|
if (info.sig_arst != RTLIL::State::Sm)
|
|
{
|
|
RTLIL::Wire *wire_r = add_new_wire(module, wire->name.str() + sep + "r");
|
|
wire_r->port_output = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_r->name));
|
|
if (info.arst_polarity) {
|
|
module->connect(RTLIL::SigSig(wire_r, info.sig_arst));
|
|
} else {
|
|
RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
|
|
c->parameters["\\A_SIGNED"] = 0;
|
|
c->parameters["\\A_WIDTH"] = 1;
|
|
c->parameters["\\Y_WIDTH"] = 1;
|
|
c->setPort("\\A", info.sig_arst);
|
|
c->setPort("\\Y", wire_r);
|
|
}
|
|
|
|
RTLIL::Wire *wire_v = add_new_wire(module, wire->name.str() + sep + "v", wire->width);
|
|
wire_v->port_output = true;
|
|
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_v->name));
|
|
module->connect(RTLIL::SigSig(wire_v, info.arst_value));
|
|
}
|
|
}
|
|
|
|
if (flag_evert)
|
|
{
|
|
std::vector<RTLIL::Cell*> 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, dff_cells[module], it.second))
|
|
continue;
|
|
}
|
|
|
|
RTLIL::Cell *cell = it.second;
|
|
|
|
if (design->modules_.count(cell->type))
|
|
{
|
|
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 = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(p->name), p->width);
|
|
if (p->port_input)
|
|
w->port_output = true;
|
|
if (p->port_output)
|
|
w->port_input = true;
|
|
|
|
log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
|
|
|
|
RTLIL::SigSpec sig;
|
|
if (cell->hasPort(p->name))
|
|
sig = cell->getPort(p->name);
|
|
sig.extend_u0(w->width);
|
|
if (w->port_input)
|
|
module->connect(RTLIL::SigSig(sig, w));
|
|
else
|
|
module->connect(RTLIL::SigSig(w, sig));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (auto &it : cell->connections())
|
|
{
|
|
RTLIL::Wire *w = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(it.first), it.second.size());
|
|
if (ct.cell_input(cell->type, it.first))
|
|
w->port_output = true;
|
|
if (ct.cell_output(cell->type, it.first))
|
|
w->port_input = true;
|
|
|
|
log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
|
|
|
|
if (w->port_input)
|
|
module->connect(RTLIL::SigSig(it.second, w));
|
|
else
|
|
module->connect(RTLIL::SigSig(w, it.second));
|
|
}
|
|
}
|
|
|
|
delete_cells.push_back(cell);
|
|
}
|
|
|
|
for (auto cell : delete_cells) {
|
|
log("Removing cell: %s/%s (%s)\n", log_id(module), log_id(cell), log_id(cell->type));
|
|
module->remove(cell);
|
|
}
|
|
}
|
|
|
|
module->fixup_ports();
|
|
}
|
|
}
|
|
} ExposePass;
|
|
|
|
PRIVATE_NAMESPACE_END
|