mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 09:05:32 +00:00
Merge branch 'master' into krys/docs
This commit is contained in:
commit
1455941ab9
152 changed files with 3892 additions and 1578 deletions
|
@ -102,11 +102,13 @@ struct CellTypes
|
|||
setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool<RTLIL::IdString>(), true);
|
||||
setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);
|
||||
setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y});
|
||||
setup_type(ID($get_tag), {ID::A}, {ID::Y});
|
||||
setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool<RTLIL::IdString>());
|
||||
setup_type(ID($original_tag), {ID::A}, {ID::Y});
|
||||
setup_type(ID($future_ff), {ID::A}, {ID::Y});
|
||||
setup_type(ID($scopeinfo), {}, {});
|
||||
}
|
||||
|
||||
void setup_internals_eval()
|
||||
|
|
|
@ -88,6 +88,7 @@ X(equiv_merged)
|
|||
X(equiv_region)
|
||||
X(extract_order)
|
||||
X(F)
|
||||
X(FLAVOR)
|
||||
X(FORMAT)
|
||||
X(force_downto)
|
||||
X(force_upto)
|
||||
|
|
|
@ -92,8 +92,15 @@ int getopt(int argc, char **argv, const char *optstring)
|
|||
return optopt;
|
||||
}
|
||||
|
||||
optarg = argv[++optind];
|
||||
if (++optind >= argc) {
|
||||
fprintf(stderr, "%s: option '-%c' expects an argument\n", argv[0], optopt);
|
||||
optopt = '?';
|
||||
return optopt;
|
||||
}
|
||||
|
||||
optarg = argv[optind];
|
||||
optind++, optcur = 1;
|
||||
|
||||
return optopt;
|
||||
}
|
||||
|
||||
|
@ -243,14 +250,6 @@ int main(int argc, char **argv)
|
|||
bool mode_v = false;
|
||||
bool mode_q = false;
|
||||
|
||||
#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
|
||||
if (getenv("HOME") != NULL) {
|
||||
yosys_history_file = stringf("%s/.yosys_history", getenv("HOME"));
|
||||
read_history(yosys_history_file.c_str());
|
||||
yosys_history_offset = where_history();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")))
|
||||
{
|
||||
printf("\n");
|
||||
|
@ -538,6 +537,36 @@ int main(int argc, char **argv)
|
|||
if (print_banner)
|
||||
yosys_banner();
|
||||
|
||||
#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE)
|
||||
std::string state_dir;
|
||||
#if defined(_WIN32)
|
||||
if (getenv("HOMEDRIVE") != NULL && getenv("HOMEPATH") != NULL) {
|
||||
state_dir = stringf("%s%s/.local/state", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
|
||||
} else {
|
||||
log_debug("$HOMEDRIVE and/or $HOMEPATH is empty. No history file will be created.\n");
|
||||
}
|
||||
#else
|
||||
if (getenv("XDG_STATE_HOME") == NULL || getenv("XDG_STATE_HOME")[0] == '\0') {
|
||||
if (getenv("HOME") != NULL) {
|
||||
state_dir = stringf("%s/.local/state", getenv("HOME"));
|
||||
} else {
|
||||
log_debug("$HOME is empty. No history file will be created.\n");
|
||||
}
|
||||
} else {
|
||||
state_dir = stringf("%s", getenv("XDG_STATE_HOME"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!state_dir.empty()) {
|
||||
std::string yosys_dir = state_dir + "/yosys";
|
||||
create_directory(yosys_dir);
|
||||
|
||||
yosys_history_file = yosys_dir + "/history";
|
||||
read_history(yosys_history_file.c_str());
|
||||
yosys_history_offset = where_history();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (print_stats)
|
||||
log_hasher = new SHA1;
|
||||
|
||||
|
@ -569,6 +598,8 @@ int main(int argc, char **argv)
|
|||
for (auto &fn : plugin_filenames)
|
||||
load_plugin(fn, {});
|
||||
|
||||
log_suppressed();
|
||||
|
||||
if (!vlog_defines.empty()) {
|
||||
std::string vdef_cmd = "read -define";
|
||||
for (auto vdef : vlog_defines)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace hashlib {
|
||||
|
||||
const int hashtable_size_trigger = 2;
|
||||
|
|
|
@ -108,9 +108,8 @@ Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_he
|
|||
|
||||
void Pass::run_register()
|
||||
{
|
||||
if (pass_register.count(pass_name))
|
||||
if (pass_register.count(pass_name) && !replace_existing_pass())
|
||||
log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str());
|
||||
|
||||
pass_register[pass_name] = this;
|
||||
}
|
||||
|
||||
|
@ -447,13 +446,12 @@ Frontend::Frontend(std::string name, std::string short_help) :
|
|||
|
||||
void Frontend::run_register()
|
||||
{
|
||||
if (pass_register.count(pass_name))
|
||||
if (pass_register.count(pass_name) && !replace_existing_pass())
|
||||
log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str());
|
||||
pass_register[pass_name] = this;
|
||||
|
||||
if (frontend_register.count(frontend_name))
|
||||
if (frontend_register.count(frontend_name) && !replace_existing_pass())
|
||||
log_error("Unable to register frontend '%s', frontend already exists!\n", frontend_name.c_str());
|
||||
|
||||
frontend_register[frontend_name] = this;
|
||||
}
|
||||
|
||||
|
@ -993,4 +991,44 @@ struct MinisatSatSolver : public SatSolver {
|
|||
}
|
||||
} MinisatSatSolver;
|
||||
|
||||
struct LicensePass : public Pass {
|
||||
LicensePass() : Pass("license", "print license terms") { }
|
||||
void help() override
|
||||
{
|
||||
log("\n");
|
||||
log(" license\n");
|
||||
log("\n");
|
||||
log("This command produces the following notice.\n");
|
||||
notice();
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design*) override
|
||||
{
|
||||
notice();
|
||||
}
|
||||
void notice()
|
||||
{
|
||||
log("\n");
|
||||
log(" /----------------------------------------------------------------------------\\\n");
|
||||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | |\n");
|
||||
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
|
||||
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
|
||||
log(" | copyright notice and this permission notice appear in all copies. |\n");
|
||||
log(" | |\n");
|
||||
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
|
||||
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
|
||||
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
|
||||
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
|
||||
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
|
||||
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
|
||||
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
|
||||
log(" | |\n");
|
||||
log(" \\----------------------------------------------------------------------------/\n");
|
||||
log("\n");
|
||||
}
|
||||
} LicensePass;
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -70,6 +70,7 @@ struct Pass
|
|||
|
||||
virtual void on_register();
|
||||
virtual void on_shutdown();
|
||||
virtual bool replace_existing_pass() const { return false; }
|
||||
};
|
||||
|
||||
struct ScriptPass : Pass
|
||||
|
|
|
@ -1068,6 +1068,12 @@ namespace {
|
|||
error(__LINE__);
|
||||
}
|
||||
|
||||
std::string param_string(const RTLIL::IdString &name)
|
||||
{
|
||||
param(name);
|
||||
return cell->parameters.at(name).decode_string();
|
||||
}
|
||||
|
||||
void port(const RTLIL::IdString& name, int width)
|
||||
{
|
||||
auto it = cell->connections_.find(name);
|
||||
|
@ -1747,6 +1753,31 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($check)) {
|
||||
std::string flavor = param_string(ID(FLAVOR));
|
||||
if (!(flavor == "assert" || flavor == "assume" || flavor == "live" || flavor == "fair" || flavor == "cover"))
|
||||
error(__LINE__);
|
||||
param(ID(FORMAT));
|
||||
param_bool(ID::TRG_ENABLE);
|
||||
param(ID::TRG_POLARITY);
|
||||
param(ID::PRIORITY);
|
||||
port(ID::A, 1);
|
||||
port(ID::EN, 1);
|
||||
port(ID::TRG, param(ID::TRG_WIDTH));
|
||||
port(ID::ARGS, param(ID::ARGS_WIDTH));
|
||||
check_expected();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($scopeinfo)) {
|
||||
param(ID::TYPE);
|
||||
check_expected();
|
||||
std::string scope_type = cell->getParam(ID::TYPE).decode_string();
|
||||
if (scope_type != "module" && scope_type != "struct")
|
||||
error(__LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||
if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; }
|
||||
if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; }
|
||||
|
@ -2157,17 +2188,10 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
|||
}
|
||||
|
||||
void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
|
||||
log_assert(GetSize(lhs) == GetSize(rhs));
|
||||
lhs.unpack();
|
||||
rhs.unpack();
|
||||
for (int i = 0; i < GetSize(lhs); i++) {
|
||||
RTLIL::SigBit &lhs_bit = lhs.bits_[i];
|
||||
RTLIL::SigBit &rhs_bit = rhs.bits_[i];
|
||||
if ((lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire)) || (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))) {
|
||||
lhs_bit = State::Sx;
|
||||
rhs_bit = State::Sx;
|
||||
}
|
||||
}
|
||||
// If a deleted wire occurs on the lhs or rhs we just remove that part
|
||||
// of the assignment
|
||||
lhs.remove2(*wires_p, &rhs);
|
||||
rhs.remove2(*wires_p, &lhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3693,6 +3717,9 @@ RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
|
|||
|
||||
RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
|
||||
{
|
||||
log_assert(offset >= 0);
|
||||
log_assert(length >= 0);
|
||||
log_assert(offset + length <= width);
|
||||
RTLIL::SigChunk ret;
|
||||
if (wire) {
|
||||
ret.wire = wire;
|
||||
|
@ -4238,6 +4265,34 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
|
|||
check();
|
||||
}
|
||||
|
||||
void RTLIL::SigSpec::remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *other)
|
||||
{
|
||||
if (other)
|
||||
cover("kernel.rtlil.sigspec.remove_other");
|
||||
else
|
||||
cover("kernel.rtlil.sigspec.remove");
|
||||
|
||||
unpack();
|
||||
|
||||
if (other != NULL) {
|
||||
log_assert(width_ == other->width_);
|
||||
other->unpack();
|
||||
}
|
||||
|
||||
for (int i = GetSize(bits_) - 1; i >= 0; i--) {
|
||||
if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) {
|
||||
bits_.erase(bits_.begin() + i);
|
||||
width_--;
|
||||
if (other != NULL) {
|
||||
other->bits_.erase(other->bits_.begin() + i);
|
||||
other->width_--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const
|
||||
{
|
||||
if (other)
|
||||
|
@ -4377,6 +4432,9 @@ void RTLIL::SigSpec::remove(int offset, int length)
|
|||
|
||||
RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
|
||||
{
|
||||
log_assert(offset >= 0);
|
||||
log_assert(length >= 0);
|
||||
log_assert(offset + length <= width_);
|
||||
unpack();
|
||||
cover("kernel.rtlil.sigspec.extract_pos");
|
||||
return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
|
||||
|
|
|
@ -712,7 +712,7 @@ struct RTLIL::Const
|
|||
inline unsigned int hash() const {
|
||||
unsigned int h = mkhash_init;
|
||||
for (auto b : bits)
|
||||
mkhash(h, b);
|
||||
h = mkhash(h, b);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
@ -924,6 +924,7 @@ public:
|
|||
void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
|
||||
void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
|
||||
void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
|
||||
void remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *other);
|
||||
|
||||
void remove(int offset, int length = 1);
|
||||
void remove_const();
|
||||
|
|
|
@ -1379,6 +1379,11 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($scopeinfo))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unsupported internal cell types: $pow $fsm $mem*
|
||||
// .. and all sequential cells with asynchronous inputs
|
||||
return false;
|
||||
|
|
129
kernel/scopeinfo.cc
Normal file
129
kernel/scopeinfo.cc
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2024 Jannis Harder <jix@yosyshq.com> <me@jix.one>
|
||||
*
|
||||
* 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/scopeinfo.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
template <typename I, typename Filter> void ModuleHdlnameIndex::index_items(I begin, I end, Filter filter)
|
||||
{
|
||||
for (; begin != end; ++begin) {
|
||||
auto const &item = *begin;
|
||||
|
||||
if (!filter(item))
|
||||
continue;
|
||||
std::vector<IdString> path = parse_hdlname(item);
|
||||
if (!path.empty())
|
||||
lookup.emplace(item, tree.insert(path, item));
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleHdlnameIndex::index()
|
||||
{
|
||||
index_wires();
|
||||
index_cells();
|
||||
}
|
||||
|
||||
void ModuleHdlnameIndex::index_wires()
|
||||
{
|
||||
auto wires = module->wires();
|
||||
index_items(wires.begin(), wires.end(), [](Wire *) { return true; });
|
||||
}
|
||||
|
||||
void ModuleHdlnameIndex::index_cells()
|
||||
{
|
||||
auto cells = module->cells();
|
||||
index_items(cells.begin(), cells.end(), [](Cell *) { return true; });
|
||||
}
|
||||
|
||||
void ModuleHdlnameIndex::index_scopeinfo_cells()
|
||||
{
|
||||
auto cells = module->cells();
|
||||
index_items(cells.begin(), cells.end(), [](Cell *cell) { return cell->type == ID($scopeinfo); });
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleHdlnameIndex::scope_sources(Cursor cursor)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
for (; !cursor.is_root(); cursor = cursor.parent()) {
|
||||
if (!cursor.has_entry()) {
|
||||
result.push_back("");
|
||||
result.push_back("");
|
||||
continue;
|
||||
}
|
||||
Cell *cell = cursor.entry().cell();
|
||||
if (cell == nullptr || cell->type != ID($scopeinfo)) {
|
||||
result.push_back("");
|
||||
result.push_back("");
|
||||
continue;
|
||||
}
|
||||
result.push_back(scopeinfo_get_attribute(cell, ScopeinfoAttrs::Module, ID::src).decode_string());
|
||||
result.push_back(scopeinfo_get_attribute(cell, ScopeinfoAttrs::Cell, ID::src).decode_string());
|
||||
}
|
||||
|
||||
result.push_back(module->get_src_attribute());
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char *attr_prefix(ScopeinfoAttrs attrs)
|
||||
{
|
||||
switch (attrs) {
|
||||
case ScopeinfoAttrs::Cell:
|
||||
return "\\cell_";
|
||||
case ScopeinfoAttrs::Module:
|
||||
return "\\module_";
|
||||
default:
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id)
|
||||
{
|
||||
log_assert(scopeinfo->type == ID($scopeinfo));
|
||||
return scopeinfo->has_attribute(attr_prefix(attrs) + RTLIL::unescape_id(id));
|
||||
}
|
||||
|
||||
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id)
|
||||
{
|
||||
log_assert(scopeinfo->type == ID($scopeinfo));
|
||||
auto found = scopeinfo->attributes.find(attr_prefix(attrs) + RTLIL::unescape_id(id));
|
||||
if (found == scopeinfo->attributes.end())
|
||||
return RTLIL::Const();
|
||||
return found->second;
|
||||
}
|
||||
|
||||
dict<RTLIL::IdString, RTLIL::Const> scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs)
|
||||
{
|
||||
dict<RTLIL::IdString, RTLIL::Const> attributes;
|
||||
|
||||
const char *prefix = attr_prefix(attrs);
|
||||
int prefix_len = strlen(prefix);
|
||||
|
||||
for (auto const &entry : scopeinfo->attributes)
|
||||
if (entry.first.begins_with(prefix))
|
||||
attributes.emplace(RTLIL::escape_id(entry.first.c_str() + prefix_len), entry.second);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
432
kernel/scopeinfo.h
Normal file
432
kernel/scopeinfo.h
Normal file
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2024 Jannis Harder <jix@yosyshq.com> <me@jix.one>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCOPEINFO_H
|
||||
#define SCOPEINFO_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/celltypes.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
template<typename T>
|
||||
class IdTree
|
||||
{
|
||||
public:
|
||||
struct Cursor;
|
||||
|
||||
protected:
|
||||
IdTree *parent = nullptr;
|
||||
IdString scope_name;
|
||||
int depth = 0;
|
||||
|
||||
pool<IdString> names;
|
||||
dict<IdString, T> entries;
|
||||
public: // XXX
|
||||
dict<IdString, std::unique_ptr<IdTree>> subtrees;
|
||||
|
||||
template<typename P, typename T_ref>
|
||||
static Cursor do_insert(IdTree *tree, P begin, P end, T_ref &&value)
|
||||
{
|
||||
log_assert(begin != end && "path must be non-empty");
|
||||
while (true) {
|
||||
IdString name = *begin;
|
||||
++begin;
|
||||
log_assert(!name.empty());
|
||||
tree->names.insert(name);
|
||||
if (begin == end) {
|
||||
tree->entries.emplace(name, std::forward<T_ref>(value));
|
||||
return Cursor(tree, name);
|
||||
}
|
||||
auto &unique = tree->subtrees[name];
|
||||
if (!unique) {
|
||||
unique.reset(new IdTree);
|
||||
unique->scope_name = name;
|
||||
unique->parent = tree;
|
||||
unique->depth = tree->depth + 1;
|
||||
}
|
||||
tree = unique.get();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
IdTree() = default;
|
||||
IdTree(const IdTree &) = delete;
|
||||
IdTree(IdTree &&) = delete;
|
||||
|
||||
// A cursor remains valid as long as the (sub-)IdTree it points at is alive
|
||||
struct Cursor
|
||||
{
|
||||
friend class IdTree;
|
||||
protected:
|
||||
public:
|
||||
IdTree *target;
|
||||
IdString scope_name;
|
||||
|
||||
Cursor() : target(nullptr) {}
|
||||
Cursor(IdTree *target, IdString scope_name) : target(target), scope_name(scope_name) {
|
||||
if (scope_name.empty())
|
||||
log_assert(target->parent == nullptr);
|
||||
}
|
||||
|
||||
Cursor do_first_child() {
|
||||
IdTree *tree = nullptr;
|
||||
if (scope_name.empty()) {
|
||||
tree = target;
|
||||
} else {
|
||||
auto found = target->subtrees.find(scope_name);
|
||||
if (found != target->subtrees.end()) {
|
||||
tree = found->second.get();
|
||||
} else {
|
||||
return Cursor();
|
||||
}
|
||||
}
|
||||
if (tree->names.empty()) {
|
||||
return Cursor();
|
||||
}
|
||||
return Cursor(tree, *tree->names.begin());
|
||||
}
|
||||
|
||||
Cursor do_next_sibling() {
|
||||
if (scope_name.empty())
|
||||
return Cursor();
|
||||
auto found = target->names.find(scope_name);
|
||||
if (found == target->names.end())
|
||||
return Cursor();
|
||||
++found;
|
||||
if (found == target->names.end())
|
||||
return Cursor();
|
||||
return Cursor(target, *found);
|
||||
}
|
||||
|
||||
Cursor do_parent() {
|
||||
if (scope_name.empty())
|
||||
return Cursor();
|
||||
if (target->parent != nullptr)
|
||||
return Cursor(target->parent, target->scope_name);
|
||||
return Cursor(target, IdString());
|
||||
}
|
||||
|
||||
Cursor do_next_preorder() {
|
||||
Cursor current = *this;
|
||||
Cursor next = current.do_first_child();
|
||||
if (next.valid())
|
||||
return next;
|
||||
while (current.valid()) {
|
||||
if (next.valid())
|
||||
return next;
|
||||
next = current.do_next_sibling();
|
||||
if (next.valid())
|
||||
return next;
|
||||
current = current.do_parent();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
Cursor do_child(IdString name) {
|
||||
IdTree *tree = nullptr;
|
||||
if (scope_name.empty()) {
|
||||
tree = target;
|
||||
} else {
|
||||
auto found = target->subtrees.find(scope_name);
|
||||
if (found != target->subtrees.end()) {
|
||||
tree = found->second.get();
|
||||
} else {
|
||||
return Cursor();
|
||||
}
|
||||
}
|
||||
auto found = tree->names.find(name);
|
||||
if (found == tree->names.end()) {
|
||||
return Cursor();
|
||||
}
|
||||
return Cursor(tree, *found);
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator==(const Cursor &other) const {
|
||||
return target == other.target && scope_name == other.scope_name;
|
||||
}
|
||||
bool operator!=(const Cursor &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return target != nullptr;
|
||||
}
|
||||
|
||||
int depth() const {
|
||||
log_assert(valid());
|
||||
return target->depth + !scope_name.empty();
|
||||
}
|
||||
|
||||
bool is_root() const {
|
||||
return target != nullptr && scope_name.empty();
|
||||
}
|
||||
|
||||
bool has_entry() const {
|
||||
log_assert(valid());
|
||||
return !scope_name.empty() && target->entries.count(scope_name);
|
||||
}
|
||||
|
||||
T &entry() {
|
||||
log_assert(!scope_name.empty());
|
||||
return target->entries.at(scope_name);
|
||||
}
|
||||
|
||||
void assign_path_to(std::vector<IdString> &out_path) {
|
||||
log_assert(valid());
|
||||
out_path.clear();
|
||||
if (scope_name.empty())
|
||||
return;
|
||||
out_path.push_back(scope_name);
|
||||
IdTree *current = target;
|
||||
while (current->parent) {
|
||||
out_path.push_back(current->scope_name);
|
||||
current = current->parent;
|
||||
}
|
||||
std::reverse(out_path.begin(), out_path.end());
|
||||
}
|
||||
|
||||
std::vector<IdString> path() {
|
||||
std::vector<IdString> result;
|
||||
assign_path_to(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string path_str() {
|
||||
std::string result;
|
||||
for (const auto &item : path()) {
|
||||
if (!result.empty())
|
||||
result.push_back(' ');
|
||||
result += RTLIL::unescape_id(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Cursor first_child() {
|
||||
log_assert(valid());
|
||||
return do_first_child();
|
||||
}
|
||||
|
||||
Cursor next_preorder() {
|
||||
log_assert(valid());
|
||||
return do_next_preorder();
|
||||
}
|
||||
|
||||
Cursor parent() {
|
||||
log_assert(valid());
|
||||
return do_parent();
|
||||
}
|
||||
|
||||
Cursor child(IdString name) {
|
||||
log_assert(valid());
|
||||
return do_child(name);
|
||||
}
|
||||
|
||||
Cursor common_ancestor(Cursor other) {
|
||||
Cursor current = *this;
|
||||
|
||||
while (current != other) {
|
||||
if (!current.valid() || !other.valid())
|
||||
return Cursor();
|
||||
int delta = current.depth() - other.depth();
|
||||
if (delta >= 0)
|
||||
current = current.do_parent();
|
||||
if (delta <= 0)
|
||||
other = other.do_parent();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P>
|
||||
Cursor insert(P begin, P end, const T &value) {
|
||||
return do_insert(this, begin, end, value);
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
Cursor insert(P begin, P end, T &&value) {
|
||||
return do_insert(this, begin, end, std::move(value));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
Cursor insert(const P &path, const T &value) {
|
||||
return do_insert(this, path.begin(), path.end(), value);
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
Cursor insert(const P &path, T &&value) {
|
||||
return do_insert(this, path.begin(), path.end(), std::move(value));
|
||||
}
|
||||
|
||||
Cursor cursor() {
|
||||
return parent ? Cursor(this->parent, this->scope_name) : Cursor(this, IdString());
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
Cursor cursor(P begin, P end) {
|
||||
Cursor current = cursor();
|
||||
for (; begin != end; ++begin) {
|
||||
current = current.do_child(*begin);
|
||||
if (!current.valid())
|
||||
break;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
Cursor cursor(const P &path) {
|
||||
return cursor(path.begin(), path.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ModuleItem {
|
||||
enum class Type {
|
||||
Wire,
|
||||
Cell,
|
||||
};
|
||||
Type type;
|
||||
void *ptr;
|
||||
|
||||
ModuleItem(Wire *wire) : type(Type::Wire), ptr(wire) {}
|
||||
ModuleItem(Cell *cell) : type(Type::Cell), ptr(cell) {}
|
||||
|
||||
bool is_wire() const { return type == Type::Wire; }
|
||||
bool is_cell() const { return type == Type::Cell; }
|
||||
|
||||
Wire *wire() const { return type == Type::Wire ? static_cast<Wire *>(ptr) : nullptr; }
|
||||
Cell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }
|
||||
|
||||
bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }
|
||||
unsigned int hash() const { return (uintptr_t)ptr; }
|
||||
};
|
||||
|
||||
static inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); }
|
||||
|
||||
template<typename T>
|
||||
static inline void log_dump_val_worker(const typename std::unique_ptr<T> &cursor ) { log("unique %p", cursor.get()); }
|
||||
|
||||
template<typename O>
|
||||
std::vector<IdString> parse_hdlname(const O* object)
|
||||
{
|
||||
std::vector<IdString> path;
|
||||
if (!object->name.isPublic())
|
||||
return path;
|
||||
for (auto const &item : object->get_hdlname_attribute())
|
||||
path.push_back("\\" + item);
|
||||
if (path.empty())
|
||||
path.push_back(object->name);
|
||||
return path;
|
||||
}
|
||||
|
||||
template<typename O>
|
||||
std::pair<std::vector<IdString>, IdString> parse_scopename(const O* object)
|
||||
{
|
||||
std::vector<IdString> path;
|
||||
IdString trailing = object->name;
|
||||
if (object->name.isPublic()) {
|
||||
for (auto const &item : object->get_hdlname_attribute())
|
||||
path.push_back("\\" + item);
|
||||
if (!path.empty()) {
|
||||
trailing = path.back();
|
||||
path.pop_back();
|
||||
}
|
||||
} else {
|
||||
for (auto const &item : split_tokens(object->get_string_attribute(ID(scopename)), " "))
|
||||
path.push_back("\\" + item);
|
||||
|
||||
}
|
||||
return {path, trailing};
|
||||
}
|
||||
|
||||
struct ModuleHdlnameIndex {
|
||||
typedef IdTree<ModuleItem>::Cursor Cursor;
|
||||
|
||||
RTLIL::Module *module;
|
||||
IdTree<ModuleItem> tree;
|
||||
dict<ModuleItem, Cursor> lookup;
|
||||
|
||||
ModuleHdlnameIndex(RTLIL::Module *module) : module(module) {}
|
||||
|
||||
private:
|
||||
template<typename I, typename Filter>
|
||||
void index_items(I begin, I end, Filter filter);
|
||||
|
||||
public:
|
||||
// Index all wires and cells of the module
|
||||
void index();
|
||||
|
||||
// Index all wires of the module
|
||||
void index_wires();
|
||||
|
||||
// Index all cells of the module
|
||||
void index_cells();
|
||||
|
||||
// Index only the $scopeinfo cells of the module.
|
||||
// This is sufficient when using `containing_scope`.
|
||||
void index_scopeinfo_cells();
|
||||
|
||||
|
||||
// Return the cursor for the containing scope of some RTLIL object (Wire/Cell/...)
|
||||
template<typename O>
|
||||
std::pair<Cursor, IdString> containing_scope(O *object) {
|
||||
auto pair = parse_scopename(object);
|
||||
return {tree.cursor(pair.first), pair.second};
|
||||
}
|
||||
|
||||
// Return a vector of source locations starting from the indexed module to
|
||||
// the scope represented by the cursor. The vector alternates module and
|
||||
// module item source locations, using empty strings for missing src
|
||||
// attributes.
|
||||
std::vector<std::string> scope_sources(Cursor cursor);
|
||||
|
||||
// Return a vector of source locations starting from the indexed module to
|
||||
// the passed RTLIL object (Wire/Cell/...). The vector alternates module
|
||||
// and module item source locations, using empty strings for missing src
|
||||
// attributes.
|
||||
template<typename O>
|
||||
std::vector<std::string> sources(O *object) {
|
||||
auto pair = parse_scopename(object);
|
||||
std::vector<std::string> result = scope_sources(tree.cursor(pair.first));
|
||||
result.push_back(object->get_src_attribute());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
enum class ScopeinfoAttrs {
|
||||
Module,
|
||||
Cell,
|
||||
};
|
||||
|
||||
// Check whether the flattened module or flattened cell corresponding to a $scopeinfo cell had a specific attribute.
|
||||
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);
|
||||
|
||||
// Get a specific attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.
|
||||
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);
|
||||
|
||||
// Get all attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.
|
||||
dict<RTLIL::IdString, RTLIL::Const> scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs);
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -55,7 +55,7 @@
|
|||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
|
@ -138,27 +138,11 @@ void yosys_banner()
|
|||
{
|
||||
log("\n");
|
||||
log(" /----------------------------------------------------------------------------\\\n");
|
||||
log(" | |\n");
|
||||
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2020 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | |\n");
|
||||
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
|
||||
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
|
||||
log(" | copyright notice and this permission notice appear in all copies. |\n");
|
||||
log(" | |\n");
|
||||
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
|
||||
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
|
||||
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
|
||||
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
|
||||
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
|
||||
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
|
||||
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
|
||||
log(" | |\n");
|
||||
log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf <claire@yosyshq.com> |\n");
|
||||
log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n");
|
||||
log(" \\----------------------------------------------------------------------------/\n");
|
||||
log("\n");
|
||||
log(" %s\n", yosys_version_str);
|
||||
log("\n");
|
||||
}
|
||||
|
||||
int ceil_log2(int x)
|
||||
|
@ -436,6 +420,25 @@ std::string make_temp_dir(std::string template_str)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool check_directory_exists(const std::string& dirname)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
struct _stat info;
|
||||
if (_stat(dirname.c_str(), &info) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (info.st_mode & _S_IFDIR) != 0;
|
||||
#else
|
||||
struct stat info;
|
||||
if (stat(dirname.c_str(), &info) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (info.st_mode & S_IFDIR) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool check_file_exists(std::string filename, bool)
|
||||
{
|
||||
|
@ -481,6 +484,48 @@ void remove_directory(std::string dirname)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool create_directory(const std::string& dirname)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
int ret = _mkdir(dirname.c_str());
|
||||
#else
|
||||
mode_t mode = 0755;
|
||||
int ret = mkdir(dirname.c_str(), mode);
|
||||
#endif
|
||||
if (ret == 0)
|
||||
return true;
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
// parent didn't exist, try to create it
|
||||
{
|
||||
std::string::size_type pos = dirname.find_last_of('/');
|
||||
if (pos == std::string::npos)
|
||||
#if defined(_WIN32)
|
||||
pos = dirname.find_last_of('\\');
|
||||
if (pos == std::string::npos)
|
||||
#endif
|
||||
return false;
|
||||
if (!create_directory( dirname.substr(0, pos) ))
|
||||
return false;
|
||||
}
|
||||
// now, try to create again
|
||||
#if defined(_WIN32)
|
||||
return 0 == _mkdir(dirname.c_str());
|
||||
#else
|
||||
return 0 == mkdir(dirname.c_str(), mode);
|
||||
#endif
|
||||
|
||||
case EEXIST:
|
||||
// done!
|
||||
return check_directory_exists(dirname);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string escape_filename_spaces(const std::string& filename)
|
||||
{
|
||||
std::string out;
|
||||
|
@ -781,10 +826,10 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
|
|||
|
||||
int yosys_tcl_iterp_init(Tcl_Interp *interp)
|
||||
{
|
||||
if (Tcl_Init(interp)!=TCL_OK)
|
||||
if (Tcl_Init(interp)!=TCL_OK)
|
||||
log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
|
||||
Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
|
||||
return TCL_OK ;
|
||||
return TCL_OK ;
|
||||
}
|
||||
|
||||
void yosys_tcl_activate_repl()
|
||||
|
@ -856,10 +901,14 @@ std::string proc_self_dirname()
|
|||
buflen--;
|
||||
return std::string(path, buflen);
|
||||
}
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
std::string proc_self_dirname()
|
||||
{
|
||||
#ifdef __NetBSD__
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_PATHNAME};
|
||||
#else
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
#endif
|
||||
size_t buflen;
|
||||
char *buffer;
|
||||
std::string path;
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
#include <Python.h>
|
||||
|
@ -341,8 +343,10 @@ std::string get_base_tmpdir();
|
|||
std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
|
||||
bool check_file_exists(std::string filename, bool is_exec = false);
|
||||
bool check_directory_exists(const std::string& dirname);
|
||||
bool is_absolute_path(std::string filename);
|
||||
void remove_directory(std::string dirname);
|
||||
bool create_directory(const std::string& dirname);
|
||||
std::string escape_filename_spaces(const std::string& filename);
|
||||
|
||||
template<typename T> int GetSize(const T &obj) { return obj.size(); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue