blob: 40aeddc838d79bf23e01f629d03e3926b24e8f68 [file]
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2020 The Symbiflow Authors
*
* 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 "pcf_parser.hh"
#include "pinmap_parser.hh"
#include "kernel/register.h"
#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
void register_in_tcl_interpreter(const std::string& command) {
Tcl_Interp* interp = yosys_get_tcl_interp();
std::string tcl_script = stringf("proc %s args { return [yosys %s {*}$args] }", command.c_str(), command.c_str());
Tcl_Eval(interp, tcl_script.c_str());
}
struct QuicklogicIob : public Pass {
QuicklogicIob () :
Pass("quicklogic_iob", "Map IO buffers to cells that correspond to their assigned locations") {
register_in_tcl_interpreter(pass_name);
}
void help() YS_OVERRIDE {
log("Help!\n");
}
void execute(std::vector<std::string> a_Args, RTLIL::Design* a_Design) YS_OVERRIDE {
if (a_Args.size() < 3) {
log_cmd_error("Usage: quicklogic_iob <PCF file> <pinmap file>");
}
// Get the top module of the design
m_topModule = a_Design->top_module();
if (m_topModule == nullptr) {
log_cmd_error("No top module detected!\n");
}
// Read and parse the PCF file
log("Loading PCF from '%s'...\n", a_Args[1].c_str());
auto pcfParser = PcfParser();
if (!pcfParser.parse(a_Args[1])) {
log_cmd_error("Failed to parse the PCF file!\n");
}
// Build a map of net names to constraints
std::unordered_map<std::string, const PcfParser::Constraint> constraintMap;
for (auto& constraint : pcfParser.getConstraints()) {
if (constraintMap.count(constraint.netName) != 0) {
log_cmd_error("The net '%s' is constrained twice!", constraint.netName.c_str());
}
constraintMap.emplace(constraint.netName, constraint);
}
// Read and parse pinmap CSV file
log("Loading pinmap CSV from '%s'...\n", a_Args[2].c_str());
auto pinmapParser = PinmapParser();
if (!pinmapParser.parse(a_Args[2])) {
log_cmd_error("Failed to parse the pinmap CSV file!\n");
}
// A map of IO cell types and their port names that should go to a pad
std::unordered_map<std::string, std::string> ioCellTypes;
// TODO
ioCellTypes.insert(std::make_pair("inpad", "P"));
ioCellTypes.insert(std::make_pair("outpad", "P"));
// Check all IO cells
for (auto cell : m_topModule->cells()) {
auto cellType = RTLIL::unescape_id(cell->type);
// No an IO cell
if (ioCellTypes.count(cellType) == 0) {
continue;
}
log(" %-16s %-40s ", cellType.c_str(), cell->name.c_str());
// Get connections to the specified port
std::string port = RTLIL::escape_id(ioCellTypes.at(cellType));
if (cell->connections().count(port) == 0) {
log(" Port '%s' not found!\n", port.c_str());
continue;
}
// Get the sigspec of the connection
auto sigspec = cell->connections().at(port);
// Get the connected wire
if (!sigspec.is_wire()) {
log(" Couldn't determine connection\n");
continue;
}
auto wire = sigspec.as_wire();
// Has to be top level wire
if (!wire->port_input && !wire->port_output) {
log(" No top-level port!\n");
continue;
}
// Check if the wire is constrained
auto wireName = RTLIL::unescape_id(wire->name);
if (constraintMap.count(wireName) == 0) {
log("\n");
continue;
}
// Get the constraint
auto constraint = constraintMap.at(wireName);
log("%s\n", constraint.padName.c_str());
}
// log("%zu connections\n", m_topModule->connections().size());
// for (auto cell : m_topModule->cells()) {
// log("'%s' '%s' %zu\n", cell->name.c_str(), cell->type.c_str(), cell->connections().size());
// for (auto c : cell->connections()) {
// log(" '%s'\n", c.first.c_str());
// }
// }
/* // Get top-level wires
for (auto wire : m_topModule->wires()) {
// Not a top-level
if (!wire->port_input && !wire->port_output) {
continue;
}
log("'%s'\n", wire->name.c_str());
//getConnectedCell(wire, 0);
}*/
}
// ..............................................................
RTLIL::Module* m_topModule = nullptr;
// ..............................................................
RTLIL::Module* getConnectedCell(RTLIL::Wire* wire, size_t bit = 0) {
RTLIL::Module* module = wire->module;
log("'%s' %d\n", wire->name.c_str(), bit);
for (auto connection : m_topModule->connections_) {
log("k");
auto dst_sig = connection.first;
auto src_sig = connection.second;
// Go down
if (dst_sig.is_chunk()) {
auto chunk = dst_sig.as_chunk();
if (chunk.wire) {
log(" '%s'\n", chunk.wire->name.c_str());
}
log("%d\n", chunk.width);
}
if (dst_sig.is_wire()) {
auto w = dst_sig.as_wire();
log(" '%s'\n",w->name.c_str());
}
/* if (dst_sig.is_chunk()) {
auto chunk = dst_sig.as_chunk();
if (chunk.wire) {
if (chunk.wire->name != wire->name) {
continue;
}
if (bit < chunk.offset || bit >= (chunk.offset + chunk.width)) {
continue;
}
auto src_wires = src_sig.to_sigbit_vector();
auto src_wire_sigbit = src_wires.at(bit - chunk.offset);
if (src_wire_sigbit.wire) {
log(" '%s'\n", src_wire_sigbit.wire->name.c_str());
}
}
}*/
}
return nullptr;
}
} QuicklogicIob;
PRIVATE_NAMESPACE_END