/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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.h" #include "kernel/celltypes.h" #ifdef YOSYS_ENABLE_READLINE # include # include #endif #ifdef YOSYS_ENABLE_EDITLINE # include #endif #ifdef YOSYS_ENABLE_PLUGINS # include #endif #if defined(_WIN32) # include # include #elif defined(__APPLE__) # include # include # include # include #else # include # include # include # include # if !defined(YOSYS_DISABLE_SPAWN) # include # endif #endif #if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) # include #endif #ifdef __FreeBSD__ # include #endif #ifdef WITH_PYTHON #if PY_MAJOR_VERSION >= 3 # define INIT_MODULE PyInit_libyosys extern "C" PyObject* INIT_MODULE(); #else # define INIT_MODULE initlibyosys extern "C" void INIT_MODULE(); #endif #endif #include #include YOSYS_NAMESPACE_BEGIN int autoidx = 1; int yosys_xtrace = 0; RTLIL::Design *yosys_design = NULL; CellTypes yosys_celltypes; #ifdef YOSYS_ENABLE_TCL Tcl_Interp *yosys_tcl_interp = NULL; #endif std::set yosys_input_files, yosys_output_files; bool memhasher_active = false; uint32_t memhasher_rng = 123456; std::vector memhasher_store; std::string yosys_share_dirname; std::string yosys_abc_executable; void init_share_dirname(); void init_abc_executable_name(); void memhasher_on() { #if defined(__linux__) || defined(__FreeBSD__) memhasher_rng += time(NULL) << 16 ^ getpid(); #endif memhasher_store.resize(0x10000); memhasher_active = true; } void memhasher_off() { for (auto p : memhasher_store) if (p) free(p); memhasher_store.clear(); memhasher_active = false; } void memhasher_do() { memhasher_rng ^= memhasher_rng << 13; memhasher_rng ^= memhasher_rng >> 17; memhasher_rng ^= memhasher_rng << 5; int size, index = (memhasher_rng >> 4) & 0xffff; switch (memhasher_rng & 7) { case 0: size = 16; break; case 1: size = 256; break; case 2: size = 1024; break; case 3: size = 4096; break; default: size = 0; } if (index < 16) size *= 16; memhasher_store[index] = realloc(memhasher_store[index], size); } void yosys_banner() { log("\n"); log(" /----------------------------------------------------------------------------\\\n"); log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); log(" | Copyright (C) 2012 - 2020 Claire Wolf |\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"); log(" %s\n", yosys_version_str); log("\n"); } int ceil_log2(int x) { #if defined(__GNUC__) return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0; #else if (x <= 0) return 0; for (int i = 0; i < 32; i++) if (((x-1) >> i) == 0) return i; log_abort(); #endif } std::string stringf(const char *fmt, ...) { std::string string; va_list ap; va_start(ap, fmt); string = vstringf(fmt, ap); va_end(ap); return string; } std::string vstringf(const char *fmt, va_list ap) { std::string string; char *str = NULL; #if defined(_WIN32 )|| defined(__CYGWIN__) int sz = 64, rc; while (1) { va_list apc; va_copy(apc, ap); str = (char*)realloc(str, sz); rc = vsnprintf(str, sz, fmt, apc); va_end(apc); if (rc >= 0 && rc < sz) break; sz *= 2; } #else if (vasprintf(&str, fmt, ap) < 0) str = NULL; #endif if (str != NULL) { string = str; free(str); } return string; } int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); // f.readsome() sometimes returns 0 on a non-empty stream.. if (rc == 0) { int c = f.get(); if (c != EOF) { *s = c; rc = 1; } } return rc; } std::string next_token(std::string &text, const char *sep, bool long_strings) { size_t pos_begin = text.find_first_not_of(sep); if (pos_begin == std::string::npos) pos_begin = text.size(); if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { string sep_string = sep; for (size_t i = pos_begin+1; i < text.
Welcome to ``cryptography``
===========================

``cryptography`` is a Python library which exposes cryptographic recipes and
primitives. Our goal is for it to be your "cryptographic standard library". If
you are interested in learning more about the field of cryptography, we
recommend `Crypto 101, by Laurens Van Houtven`_.

Installation
------------
You can install ``cryptography`` with ``pip``:

.. code-block:: console

    $ pip install cryptography

See :doc:`Installation <installation>` for more information.

Why a new crypto library for Python?
------------------------------------

If you've done cryptographic work in Python before, you've probably seen some
other libraries in Python, such as *M2Crypto*, *PyCrypto*, or *PyOpenSSL*. In
building ``cryptography`` we wanted to address a few issues we observed in the
existing libraries:

* Lack of PyPy and Python 3 support.
* Lack of maintenance.
* Use of poor implementations of algorithms (i.e. ones with known side-channel
  attacks).
* Lack of high level, "Cryptography for humans", APIs.
* Absence of algorithms such as
  :class:`AES-GCM <cryptography.hazmat.primitives.ciphers.modes.GCM>` and
  :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`.
* Poor introspectability, and thus poor testability.
* Extremely error prone APIs, and bad defaults.


.. _cryptography-layout:

Layout
------

``cryptography`` is broadly divided into two levels. One with safe
cryptographic recipes, "cryptography for humans" if you will. These are safe
and easy to use and don't require developers to make many decisions.

The other level is low-level cryptographic primitives. These are often
dangerous and can be used incorrectly. They require making decisions and having
an in-depth knowledge of the cryptographic concepts at work. Because of the
potential danger in working at this level, this is referred to as the
"hazardous materials" or "hazmat" layer. These live in the
``cryptography.hazmat`` package, and their documentation will always contain an
admonition at the top.

We recommend using the recipes layer whenever possible, and falling back to the
hazmat layer only when necessary.

The recipes layer
~~~~~~~~~~~~~~~~~

.. toctree::
    :maxdepth: 2

    fernet
    x509/index
    random-numbers
    exceptions
    faq
    glossary

The hazardous materials layer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. toctree::
    :maxdepth: 2

    hazmat/primitives/index
    hazmat/backends/index
    hazmat/bindings/index

The ``cryptography`` open source project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. toctree::
    :maxdepth: 2

    installation
    development/index
    security
    limitations
    api-stability
    doing-a-release
    changelog
    community


.. note::

    ``cryptography`` has not been subjected to an external audit of its code or
    documentation. If you're interested in discussing an audit please
    :doc:`get in touch </community>`.

.. _`Crypto 101, by Laurens Van Houtven`: https://www.crypto101.io/
2, "~/") == 0) filename = filename.replace(0, 1, getenv("HOME")); #endif } #ifdef YOSYS_ENABLE_TCL static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) { std::vector args; for (int i = 1; i < argc; i++) args.push_back(argv[i]); if (args.size() >= 1 && args[0] == "-import") { for (auto &it : pass_register) { std::string tcl_command_name = it.first; if (tcl_command_name == "proc") tcl_command_name = "procs"; else if (tcl_command_name == "rename") tcl_command_name = "renames"; Tcl_CmdInfo info; if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) { log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str()); } else { std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str()); Tcl_Eval(interp, tcl_script.c_str()); } } return TCL_OK; } if (args.size() == 1) { Pass::call(yosys_get_design(), args[0]); return TCL_OK; } Pass::call(yosys_get_design(), args); return TCL_OK; } extern Tcl_Interp *yosys_get_tcl_interp() { if (yosys_tcl_interp == NULL) { yosys_tcl_interp = Tcl_CreateInterp(); Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL); } return yosys_tcl_interp; } struct TclPass : public Pass { TclPass() : Pass("tcl", "execute a TCL script file") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" tcl [args]\n"); log("\n"); log("This command executes the tcl commands in the specified file.\n"); log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); log("\n"); log("The tcl command 'yosys -import' can be used to import all yosys\n"); log("commands directly as tcl commands to the tcl shell. Yosys commands\n"); log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n"); log("in order to avoid a name collision with the built in commands.\n"); log("\n"); log("If any arguments are specified, these arguments are provided to the script via\n"); log("the standard $argc and $argv variables.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *) override { if (args.size() < 2) log_cmd_error("Missing script file.\n"); std::vector script_args; for (auto it = args.begin() + 2; it != args.end(); ++it) script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size())); Tcl_Interp *interp = yosys_get_tcl_interp(); Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0); Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0); Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0); if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); } } TclPass; #endif #if defined(__linux__) || defined(__CYGWIN__) std::string proc_self_dirname() { char path[PATH_MAX]; ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); if (buflen < 0) { log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno)); } while (buflen > 0 && path[buflen-1] != '/') buflen--; return std::string(path, buflen); } #elif defined(__FreeBSD__) std::string proc_self_dirname() { int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; size_t buflen; char *buffer; std::string path; if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0) log_error("sysctl failed: %s\n", strerror(errno)); buffer = (char*)malloc(buflen); if (buffer == NULL) log_error("malloc failed: %s\n", strerror(errno)); if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0) log_error("sysctl failed: %s\n", strerror(errno)); while (buflen > 0 && buffer[buflen-1] != '/') buflen--; path.assign(buffer, buflen); free(buffer); return path; } #elif defined(__APPLE__) std::string proc_self_dirname() { char *path = NULL; uint32_t buflen = 0; while (_NSGetExecutablePath(path, &buflen) != 0) path = (char *) realloc((void *) path, buflen); while (buflen > 0 && path[buflen-1] != '/') buflen--; return std::string(path, buflen); } #elif defined(_WIN32) std::string proc_self_dirname() { int i = 0; # ifdef __MINGW32__ char longpath[MAX_PATH + 1]; char shortpath[MAX_PATH + 1]; # else WCHAR longpath[MAX_PATH + 1]; TCHAR shortpath[MAX_PATH + 1]; # endif if (!GetModuleFileName(0, longpath, MAX_PATH+1)) log_error("GetModuleFileName() failed.\n"); if (!GetShortPathName(longpath, shortpath, MAX_PATH+1)) log_error("GetShortPathName() failed.\n"); while (shortpath[i] != 0) i++; while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') shortpath[--i] = 0; std::string path; for (i = 0; shortpath[i]; i++) path += char(shortpath[i]); return path; } #elif defined(EMSCRIPTEN) || defined(__wasm) std::string proc_self_dirname() { return "/"; } #else #error "Don't know how to determine process executable base path!" #endif #if defined(EMSCRIPTEN) || defined(__wasm) void init_share_dirname() { yosys_share_dirname = "/share/"; } #else void init_share_dirname() { std::string proc_self_path = proc_self_dirname(); # if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR) std::string proc_share_path = proc_self_path + "share\\"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; } proc_share_path = proc_self_path + "..\\share\\"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; } # else std::string proc_share_path = proc_self_path + "share/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; } proc_share_path = proc_self_path + "../share/" + proc_program_prefix()+ "yosys/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; } # ifdef YOSYS_DATDIR proc_share_path = YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; } # endif # endif } #endif void init_abc_executable_name() { #ifdef ABCEXTERNAL std::string exe_file; if (std::getenv("ABC")) { yosys_abc_executable = std::getenv("ABC"); } else { yosys_abc_executable = ABCEXTERNAL; } #else yosys_abc_executable = proc_self_dirname() + proc_program_prefix()+ "yosys-abc"; #endif #ifdef _WIN32 #ifndef ABCEXTERNAL if (!check_file_exists(yosys_abc_executable + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe")) yosys_abc_executable = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc"; #endif #endif } std::string proc_share_dirname() { if (yosys_share_dirname.empty()) log_error("init_share_dirname: unable to determine share/ directory!\n"); return yosys_share_dirname; } std::string proc_program_prefix() { std::string program_prefix; #ifdef YOSYS_PROGRAM_PREFIX program_prefix = YOSYS_PROGRAM_PREFIX; #endif return program_prefix; } bool fgetline(FILE *f, std::string &buffer) { buffer = ""; char block[4096]; while (1) { if (fgets(block, 4096, f) == NULL) return false; buffer += block; if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) { while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) buffer.resize(buffer.size()-1); return true; } } } static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to) { int pos = 0; std::string label; while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t')) pos++; if (pos < GetSize(command) && command[pos] == '#') return; while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') label += command[pos++]; if (GetSize(label) > 1 && label.back() == ':') { label = label.substr(0, GetSize(label)-1); command = command.substr(pos); if (label == run_from) from_to_active = true; else if (label == run_to || (run_from == run_to && !run_from.empty())) from_to_active = false; } } void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design) { if (design == nullptr) design = yosys_design; if (command == "auto") { std::string filename_trim = filename; if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0) filename_trim.erase(filename_trim.size()-3); if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0) command = "verilog"; else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0) command = "verilog -sv"; else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0) command = "vhdl"; else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0) command = "blif"; else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0) command = "blif"; else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".json") == 0) command = "json"; else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".il") == 0) command = "rtlil"; else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".ys") == 0) command = "script"; else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".tcl") == 0) command = "tcl"; else if (filename == "-") command = "script"; else log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str()); } if (command == "script") { std::string run_from, run_to; bool from_to_active = true; if (from_to_label != NULL) { size_t pos = from_to_label->find(':'); if (pos == std::string::npos) { run_from = *from_to_label; run_to = *from_to_label; } else { run_from = from_to_label->substr(0, pos); run_to = from_to_label->substr(pos+1); } from_to_active = run_from.empty(); } log("\n-- Executing script file `%s' --\n", filename.c_str()); FILE *f = stdin; if (filename != "-") { f = fopen(filename.c_str(), "r"); yosys_input_files.insert(filename); } if (f == NULL) log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); FILE *backup_script_file = Frontend::current_script_file; Frontend::current_script_file = f; try { std::string command; while (fgetline(f, command)) { while (!command.empty() && command[command.size()-1] == '\\') { std::string next_line; if (!fgetline(f, next_line)) break; command.resize(command.size()-1); command += next_line; } handle_label(command, from_to_active, run_from, run_to); if (from_to_active) { Pass::call(design, command); design->check(); } } if (!command.empty()) { handle_label(command, from_to_active, run_from, run_to); if (from_to_active) { Pass::call(design, command); design->check(); } } } catch (...) { Frontend::current_script_file = backup_script_file; throw; } Frontend::current_script_file = backup_script_file; if (filename != "-") fclose(f); if (backend_command != NULL && *backend_command == "auto") *backend_command = ""; return; } if (filename == "-") { log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str()); } else { log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str()); } if (command == "tcl") Pass::call(design, vector({command, filename})); else Frontend::frontend_call(design, NULL, filename, command); design->check(); } void run_frontend(std::string filename, std::string command, RTLIL::Design *design) { run_frontend(filename, command, nullptr, nullptr, design); } void run_pass(std::string command, RTLIL::Design *design) { if (design == nullptr) design = yosys_design; log("\n-- Running command `%s' --\n", command.c_str()); Pass::call(design, command); } void run_backend(std::string filename, std::string command, RTLIL::Design *design) { if (design == nullptr) design = yosys_design; if (command == "auto") { if (filename.size() > 2 && filename.compare(filename.size()-2, std::string::npos, ".v") == 0) command = "verilog"; else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".sv") == 0) command = "verilog -sv"; else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0) command = "rtlil"; else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".cc") == 0) command = "cxxrtl"; else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0) command = "aiger"; else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".blif") == 0) command = "blif"; else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".edif") == 0) command = "edif"; else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".json") == 0) command = "json"; else if (filename == "-") command = "rtlil"; else if (filename.empty()) return; else log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str()); } if (filename.empty()) filename = "-"; if (filename == "-") { log("\n-- Writing to stdout using backend `%s' --\n", command.c_str()); } else { log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str()); } Backend::backend_call(design, NULL, filename, command); } #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) static char *readline_cmd_generator(const char *text, int state) { static std::map::iterator it; static int len; if (!state) { it = pass_register.begin(); len = strlen(text); } for (; it != pass_register.end(); it++) { if (it->first.compare(0, len, text) == 0) return strdup((it++)->first.c_str()); } return NULL; } static char *readline_obj_generator(const char *text, int state) { static std::vector obj_names; static size_t idx; if (!state) { idx = 0; obj_names.clear(); RTLIL::Design *design = yosys_get_design(); int len = strlen(text); if (design->selected_active_module.empty()) { for (auto mod : design->modules()) if (RTLIL::unescape_id(mod->name).compare(0, len, text) == 0) obj_names.push_back(strdup(log_id(mod->name))); } else if (design->module(design->selected_active_module) != nullptr) { RTLIL::Module *module = design->module(design->selected_active_module); for (auto w : module->wires()) if (RTLIL::unescape_id(w->name).compare(0, len, text) == 0) obj_names.push_back(strdup(log_id(w->name))); for (auto &it : module->memories) if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(log_id(it.first))); for (auto cell : module->cells()) if (RTLIL::unescape_id(cell->name).compare(0, len, text) == 0) obj_names.push_back(strdup(log_id(cell->name))); for (auto &it : module->processes) if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(log_id(it.first))); } std::sort(obj_names.begin(), obj_names.end()); } if (idx < obj_names.size()) return strdup(obj_names[idx++]); idx = 0; obj_names.clear(); return NULL; } static char **readline_completion(const char *text, int start, int) { if (start == 0) return rl_completion_matches(text, readline_cmd_generator); if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6)) return rl_completion_matches(text, readline_obj_generator); return NULL; } #endif void shell(RTLIL::Design *design) { static int recursion_counter = 0; recursion_counter++; log_cmd_error_throw = true; #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) rl_readline_name = (char*)"yosys"; rl_attempted_completion_function = readline_completion; rl_basic_word_break_characters = (char*)" \t\n"; #endif char *command = NULL; #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) while ((command = readline(create_prompt(design, recursion_counter))) != NULL) { #else char command_buffer[4096]; while (1) { fputs(create_prompt(design, recursion_counter), stdout); fflush(stdout); if ((command = fgets(command_buffer, 4096, stdin)) == NULL) break; #endif if (command[strspn(command, " \t\r\n")] == 0) continue; #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) add_history(command); #endif char *p = command + strspn(command, " \t\r\n"); if (!strncmp(p, "exit", 4)) { p += 4; p += strspn(p, " \t\r\n"); if (*p == 0) break; } try { log_assert(design->selection_stack.size() == 1); Pass::call(design, command); } catch (log_cmd_error_exception) { while (design->selection_stack.size() > 1) design->selection_stack.pop_back(); log_reset_stack(); } design->check(); } if (command == NULL) printf("exit\n"); recursion_counter--; log_cmd_error_throw = false; } struct ShellPass : public Pass { ShellPass() : Pass("shell", "enter interactive command mode") { } void help() override { log("\n"); log(" shell\n"); log("\n"); log("This command enters the interactive command mode. This can be useful\n"); log("in a script to interrupt the script at a certain point and allow for\n"); log("interactive inspection or manual synthesis of the design at this point.\n"); log("\n"); log("The command prompt of the interactive shell indicates the current\n"); log("selection (see 'help select'):\n"); log("\n"); log(" yosys>\n"); log(" the entire design is selected\n"); log("\n"); log(" yosys*>\n"); log(" only part of the design is selected\n"); log("\n"); log(" yosys [modname]>\n"); log(" the entire module 'modname' is selected using 'select -module modname'\n"); log("\n"); log(" yosys [modname]*>\n"); log(" only part of current module 'modname' is selected\n"); log("\n"); log("When in interactive shell, some errors (e.g. invalid command arguments)\n"); log("do not terminate yosys but return to the command prompt.\n"); log("\n"); log("This command is the default action if nothing else has been specified\n"); log("on the command line.\n"); log("\n"); log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { extra_args(args, 1, design, false); shell(design); } } ShellPass; #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) struct HistoryPass : public Pass { HistoryPass() : Pass("history", "show last interactive commands") { } void help() override { log("\n"); log(" history\n"); log("\n"); log("This command prints all commands in the shell history buffer. This are\n"); log("all commands executed in an interactive session, but not the commands\n"); log("from executed scripts.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { extra_args(args, 1, design, false); #ifdef YOSYS_ENABLE_READLINE for(HIST_ENTRY **list = history_list(); *list != NULL; list++) log("%s\n", (*list)->line); #else for (int i = where_history(); history_get(i); i++) log("%s\n", history_get(i)->line); #endif } } HistoryPass; #endif struct ScriptCmdPass : public Pass { ScriptCmdPass() : Pass("script", "execute commands from file or wire") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" script [:]\n"); log(" script -scriptwire [selection]\n"); log("\n"); log("This command executes the yosys commands in the specified file (default\n"); log("behaviour), or commands embedded in the constant text value connected to the\n"); log("selected wires.\n"); log("\n"); log("In the default (file) case, the 2nd argument can be used to only execute the\n"); log("section of the file between the specified labels. An empty from label is\n"); log("synonymous with the beginning of the file and an empty to label is synonymous\n"); log("with the end of the file.\n"); log("\n"); log("If only one label is specified (without ':') then only the block\n"); log("marked with that label (until the next label) is executed.\n"); log("\n"); log("In \"-scriptwire\" mode, the commands on the selected wire(s) will be executed\n"); log("in the scope of (and thus, relative to) the wires' owning module(s). This\n"); log("'-module' mode can be exited by using the 'cd' command.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool scriptwire = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-scriptwire") { scriptwire = true; continue; } break; } if (scriptwire) { extra_args(args, argidx, design); for (auto mod : design->selected_modules()) for (auto &c : mod->connections()) { if (!c.first.is_wire()) continue; auto w = c.first.as_wire(); if (!mod->selected(w)) continue; if (!c.second.is_fully_const()) log_error("RHS of selected wire %s.%s is not constant.\n", log_id(mod), log_id(w)); auto v = c.second.as_const(); Pass::call_on_module(design, mod, v.decode_string()); } } else if (args.size() < 2) log_cmd_error("Missing script file.\n"); else if (args.size() == 2) run_frontend(args[1], "script", design); else if (args.size() == 3) run_frontend(args[1], "script", NULL, &args[2], design); else extra_args(args, 2, design, false); } } ScriptCmdPass; YOSYS_NAMESPACE_END