/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Claire Xenia Wolf * Copyright (C) 2018 Ruben Undheim * * 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_common.h" #include "passes/hierarchy/util/generate.h" PRIVATE_NAMESPACE_BEGIN USING_YOSYS_NAMESPACE using namespace Hierarchy; static void generate_cell(const char* p, std::vector& cells) { log("Celltype: %s\n", p); cells.push_back(RTLIL::unescape_id(string(p))); } static void parse_one(const char* p, std::vector& cells, std::vector& ports) { generate_port_decl_t decl; if (p[0] == 'i' && p[1] == 'o') { decl.input = true; decl.output = true; p += 2; } else if (*p == 'i') { decl.input = true; decl.output = false; p++; } else if (*p == 'o') { decl.input = false; decl.output = true; p++; } else { return generate_cell(p, cells); } if (*p == '@') { char *endptr; decl.index = strtol(++p, &endptr, 10); if (decl.index < 1) return generate_cell(p, cells); p = endptr; } else decl.index = 0; if (*(p++) != ':') return generate_cell(p, cells); if (*p == 0) return generate_cell(p, cells); decl.portname = p; log("Port declaration: %s", decl.input ? decl.output ? "inout" : "input" : "output"); if (decl.index >= 1) log(" [at position %d]", decl.index); log(" %s\n", decl.portname); ports.push_back(decl); return; } PRIVATE_NAMESPACE_END YOSYS_NAMESPACE_BEGIN namespace Hierarchy { void Generator::generate(Design* design) { std::set found_celltypes; for (auto mod : design->modules()) for (auto cell : mod->cells()) { if (design->module(cell->type) != nullptr) continue; if (cell->type.begins_with("$") && !cell->type.begins_with("$__")) continue; for (auto &pattern : cells) if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str())) found_celltypes.insert(cell->type); } for (auto &celltype : found_celltypes) { std::set portnames; std::set parameters; std::map portwidths; log("Generate module for cell type %s:\n", celltype); for (auto mod : design->modules()) for (auto cell : mod->cells()) if (cell->type == celltype) { for (auto &conn : cell->connections()) { if (conn.first[0] != '$') portnames.insert(conn.first); portwidths[conn.first] = max(portwidths[conn.first], conn.second.size()); } for (auto ¶ : cell->parameters) parameters.insert(para.first); } for (auto &decl : ports) if (decl.index > 0) portnames.insert(decl.portname); std::set indices; for (int i = 0; i < int(portnames.size()); i++) indices.insert(i+1); for (auto &decl : ports) if (decl.index > 0) { portwidths[decl.portname] = max(portwidths[decl.portname], 1); portwidths[decl.portname] = max(portwidths[decl.portname], portwidths[stringf("$%d", decl.index)]); log(" port %d: %s [%d:0] %s\n", decl.index, decl.input ? decl.output ? "inout" : "input" : "output", portwidths[decl.portname]-1, RTLIL::id2cstr(decl.portname)); if (indices.count(decl.index) > ports.size()) log_error("Port index (%d) exceeds number of found ports (%d).\n", decl.index, int(ports.size())); if (indices.count(decl.index) == 0) log_error("Conflict on port index %d.\n", decl.index); indices.erase(decl.index); portnames.erase(decl.portname); ports[decl.index-1] = decl; } while (portnames.size() > 0) { RTLIL::IdString portname = *portnames.begin(); for (auto &decl : ports) if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) { generate_port_decl_t d = decl; d.portname = portname.str(); d.index = *indices.begin(); log_assert(!indices.empty()); indices.erase(d.index); ports[d.index-1] = d; portwidths[d.portname] = max(portwidths[d.portname], 1); log(" port %d: %s [%d:0] %s\n", d.index, d.input ? d.output ? "inout" : "input" : "output", portwidths[d.portname]-1, RTLIL::id2cstr(d.portname)); goto found_matching_decl; } log_error("Can't match port %s.\n", RTLIL::id2cstr(portname)); found_matching_decl:; portnames.erase(portname); } log_assert(indices.empty()); RTLIL::Module *mod = new RTLIL::Module; mod->name = celltype; mod->attributes[ID::blackbox] = RTLIL::Const(1); design->add(mod); for (auto &decl : ports) { RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname)); wire->port_id = decl.index; wire->port_input = decl.input; wire->port_output = decl.output; } mod->fixup_ports(); for (auto ¶ : parameters) log(" ignoring parameter %s.\n", RTLIL::id2cstr(para)); log(" module %s created.\n", RTLIL::id2cstr(mod->name)); } } void Generator::parse_arg(const char* p) { parse_one(p, cells, ports); } }; YOSYS_NAMESPACE_END