From ec42b42bd93d08839a0f6315b807042990f093e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Oct 2024 11:26:15 +0200 Subject: [PATCH 001/121] cellmatch: Size the `lut` attribute --- passes/techmap/cellmatch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/cellmatch.cc b/passes/techmap/cellmatch.cc index a21a4fbadc2..23559997247 100644 --- a/passes/techmap/cellmatch.cc +++ b/passes/techmap/cellmatch.cc @@ -223,7 +223,7 @@ struct CellmatchPass : Pass { for (auto bit : outputs) { log_assert(bit.is_wire()); bit.wire->attributes[ID(p_class)] = p_class(inputs.size(), luts[no]); - bit.wire->attributes[ID(lut)] = luts[no++]; + bit.wire->attributes[ID(lut)] = Const(luts[no++], 1 << inputs.size()); } } From 3d6b8b8e1a350ae1ec688d41b8d8eae0109e5119 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Wed, 9 Oct 2024 12:44:52 +0300 Subject: [PATCH 002/121] wheels: fix missing yosys-abc/share directory * `misc/__init__.py`: * checks if there's a `yosys-abc` in the same directory - if yes, sets the variable `sys._pyosys_abc` * checks if there's a `share` in the same directory - if yes, sets the variable `sys._pyosys_share_dirname` * `yosys.cc::init_share_dirname`: check for `sys._pyosys_share_dirname`, use it at the highest priority if Python is enabled * `yosys.cc::init_abc_executable_name`: check for `sys._pyosys_abc`, use it at at the highest priority if Python is enabled * `Makefile`: add new target, `share`, to only create the extra targets * `setup.py`: compile libyosys.so, yosys-abc and share, and copy them all as part of the pyosys build * `test/arch/ecp5/add_sub.py`: ported `add_sub.ys` to Python to act as a test for the share directory and abc with Python wheels, used in CI --- .github/workflows/wheels.yml | 2 +- Makefile | 6 +++++ kernel/yosys.cc | 52 ++++++++++++++++++++++++------------ misc/__init__.py | 14 ++++++++++ setup.py | 34 +++++++++++++++++++---- tests/arch/ecp5/add_sub.py | 20 ++++++++++++++ 6 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 tests/arch/ecp5/add_sub.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d59f8e1ec61..d66239a1601 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -110,7 +110,7 @@ jobs: MACOSX_DEPLOYMENT_TARGET=11 makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh - CIBW_TEST_COMMAND: python3 -c "from pyosys import libyosys as ys;d=ys.Design();ys.run_pass('help', d)" + CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py - uses: actions/upload-artifact@v4 with: name: python-wheels-${{ matrix.os.runner }} diff --git a/Makefile b/Makefile index f81e1fea200..0be664b9a1f 100644 --- a/Makefile +++ b/Makefile @@ -737,6 +737,12 @@ compile-only: $(OBJS) $(GENFILES) $(EXTRA_TARGETS) @echo " Compile successful." @echo "" +.PHONY: share +share: $(EXTRA_TARGETS) + @echo "" + @echo " Share directory created." + @echo "" + $(PROGRAM_PREFIX)yosys$(EXE): $(OBJS) $(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(LIBS) $(LIBS_VERIFIC) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 510151479b6..374b07d06b6 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -554,17 +554,17 @@ void yosys_setup() #include "kernel/constids.inc" #undef X - #ifdef WITH_PYTHON - // With Python 3.12, calling PyImport_AppendInittab on an already - // initialized platform fails (such as when libyosys is imported - // from a Python interpreter) - if (!Py_IsInitialized()) { - PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); - Py_Initialize(); - PyRun_SimpleString("import sys"); - signal(SIGINT, SIG_DFL); - } - #endif +#ifdef WITH_PYTHON + // With Python 3.12, calling PyImport_AppendInittab on an already + // initialized platform fails (such as when libyosys is imported + // from a Python interpreter) + if (!Py_IsInitialized()) { + PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); + Py_Initialize(); + PyRun_SimpleString("import sys"); + signal(SIGINT, SIG_DFL); + } +#endif Pass::init_register(); yosys_design = new RTLIL::Design; @@ -1013,6 +1013,16 @@ void init_share_dirname() #else void init_share_dirname() { +# ifdef WITH_PYTHON + PyObject *sys_obj = PyImport_ImportModule("sys"); + + if (PyObject_HasAttrString(sys_obj, "_pyosys_share_dirname")) { + PyObject *share_path_obj = PyObject_GetAttrString(sys_obj, "_pyosys_share_dirname"); + const char *share_path = PyUnicode_AsUTF8(share_path_obj); + yosys_share_dirname = std::string(share_path); + return; + } +# endif 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\\"; @@ -1058,12 +1068,20 @@ void init_abc_executable_name() } #else yosys_abc_executable = proc_self_dirname() + proc_program_prefix()+ "yosys-abc"; -#endif -#ifdef _WIN32 -#ifndef ABCEXTERNAL +# ifdef _WIN32 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 + +# ifdef WITH_PYTHON + PyObject *sys_obj = PyImport_ImportModule("sys"); + + if (PyObject_HasAttrString(sys_obj, "_pyosys_abc")) { + PyObject *abc_path_obj = PyObject_GetAttrString(sys_obj, "_pyosys_abc"); + const char *abc_path = PyUnicode_AsUTF8(abc_path_obj); + yosys_abc_executable = std::string(abc_path); + } +# endif #endif } @@ -1132,7 +1150,7 @@ bool run_frontend(std::string filename, std::string command, RTLIL::Design *desi if (command == "auto") { std::string filename_trim = filename; - + auto has_extension = [](const std::string& filename, const std::string& extension) { if (filename.size() >= extension.size()) { return filename.compare(filename.size() - extension.size(), extension.size(), extension) == 0; @@ -1143,7 +1161,7 @@ bool run_frontend(std::string filename, std::string command, RTLIL::Design *desi if (has_extension(filename_trim, ".gz")) { filename_trim.erase(filename_trim.size() - 3); } - + if (has_extension(filename_trim, ".v")) { command = " -vlog2k"; } else if (has_extension(filename_trim, ".sv")) { diff --git a/misc/__init__.py b/misc/__init__.py index 330fd6d8634..d74e3f5bd9b 100644 --- a/misc/__init__.py +++ b/misc/__init__.py @@ -1,5 +1,19 @@ import os import sys + sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) +__dir__ = os.path.abspath(os.path.dirname(__file__)) +sys._pyosys_dir = os.path.abspath(__dir__) + +bin_ext = ".exe" if os.name == "nt" else "" + +_share_candidate = os.path.join(__dir__, "share") +if os.path.isdir(_share_candidate): + sys._pyosys_share_dirname = _share_candidate + os.path.sep + +_abc_candidate = os.path.join(__dir__, f"yosys-abc{bin_ext}") +if os.path.isfile(_abc_candidate): + sys._pyosys_abc = _abc_candidate + __all__ = ["libyosys"] diff --git a/setup.py b/setup.py index 22196597109..b3a6a92802d 100644 --- a/setup.py +++ b/setup.py @@ -44,27 +44,51 @@ def __init__( "ENABLE_PYTHON_CONFIG_EMBED=0", # Would need to be installed separately by the user "ENABLE_TCL=0", - # Would need to be installed separately by the user "ENABLE_READLINE=0", + "ENABLE_EDITLINE=0", + # Always compile and include ABC in wheel + "ABCEXTERNAL=", # Show compile commands "PRETTY=0", ] def custom_build(self, bext: build_ext): bext.spawn( - ["make", f"-j{os.cpu_count() or 1}", self.name] + [ + "make", + f"-j{os.cpu_count() or 1}", + self.name, + "yosys-abc", + "share", + ] + shlex.split(os.getenv("makeFlags", "")) + self.args ) build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name))) pyosys_path = os.path.join(build_path, "pyosys") - target = os.path.join(pyosys_path, os.path.basename(self.name)) os.makedirs(pyosys_path, exist_ok=True) - shutil.copyfile(self.name, target) - # I don't know how debug info is getting here. + # libyosys.so + target = os.path.join(pyosys_path, os.path.basename(self.name)) + shutil.copy(self.name, target) bext.spawn(["strip", "-S", target]) + # yosys-abc + yosys_abc_target = os.path.join(pyosys_path, "yosys-abc") + shutil.copy("yosys-abc", yosys_abc_target) + bext.spawn(["strip", "-S", "yosys-abc"]) + + # share directory + share_target = os.path.join(pyosys_path, "share") + try: + shutil.rmtree(share_target) + except FileNotFoundError: + pass + + shutil.copytree("share", share_target) + + # I don't know how debug info is getting here. + class custom_build_ext(build_ext): def build_extension(self, ext) -> None: diff --git a/tests/arch/ecp5/add_sub.py b/tests/arch/ecp5/add_sub.py new file mode 100644 index 00000000000..0232ac1dba1 --- /dev/null +++ b/tests/arch/ecp5/add_sub.py @@ -0,0 +1,20 @@ +import os +from pyosys import libyosys as ys + +__dir__ = os.path.dirname(os.path.abspath(__file__)) +add_sub = os.path.join(__dir__, "..", "common", "add_sub.v") + +base = ys.Design() +ys.run_pass(f"read_verilog {add_sub}", base) +ys.run_pass("hierarchy -top top", base) +ys.run_pass("proc", base) +ys.run_pass("equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5", base) + +postopt = ys.Design() +ys.run_pass("design -load postopt", postopt) +ys.run_pass("cd top", postopt) +ys.run_pass("select -assert-min 25 t:LUT4", postopt) +ys.run_pass("select -assert-max 26 t:LUT4", postopt) +ys.run_pass("select -assert-count 10 t:PFUMX", postopt) +ys.run_pass("select -assert-count 6 t:L6MUX21", postopt) +ys.run_pass("select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D", postopt) From 575415ade2d8877b26944cf08ac3f6dd2ad3d035 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Oct 2024 15:07:56 +0200 Subject: [PATCH 003/121] driver: switch to cxxopts, replace -B --- .gitmodules | 3 + kernel/driver.cc | 538 +++++++++++++++++++---------------------------- libs/cxxopts | 1 + 3 files changed, 219 insertions(+), 323 deletions(-) create mode 160000 libs/cxxopts diff --git a/.gitmodules b/.gitmodules index d88d4b1e5e9..de3bb2e7491 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "abc"] path = abc url = https://github.com/YosysHQ/abc +[submodule "libs/cxxopts"] + path = libs/cxxopts + url = git@github.com:jarro2783/cxxopts.git diff --git a/kernel/driver.cc b/kernel/driver.cc index 53608c260e4..0c0dc9023d0 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -19,6 +19,8 @@ #include "kernel/yosys.h" #include "libs/sha1/sha1.h" +#include "libs/cxxopts/include/cxxopts.hpp" +#include #ifdef YOSYS_ENABLE_READLINE # include @@ -55,55 +57,6 @@ USING_YOSYS_NAMESPACE -char *optarg; -int optind = 1, optcur = 1, optopt = 0; -int getopt(int argc, char **argv, const char *optstring) -{ - if (optind >= argc) - return -1; - - if (argv[optind][0] != '-' || argv[optind][1] == 0) { - optopt = 1; - optarg = argv[optind++]; - return optopt; - } - - bool takes_arg = false; - optopt = argv[optind][optcur]; - - if (optopt == '-') { - ++optind; - return -1; - } - - for (int i = 0; optstring[i]; i++) - if (optopt == optstring[i] && optstring[i + 1] == ':') - takes_arg = true; - - if (!takes_arg) { - if (argv[optind][++optcur] == 0) - optind++, optcur = 1; - return optopt; - } - - if (argv[optind][++optcur]) { - optarg = argv[optind++] + optcur; - optcur = 1; - return optopt; - } - - 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; -} - #ifdef EMSCRIPTEN # include # include @@ -235,6 +188,7 @@ int main(int argc, char **argv) std::vector passes_commands; std::vector frontend_files; std::vector plugin_filenames; + std::vector special_args; std::string output_filename = ""; std::string scriptfile = ""; std::string depsfile = ""; @@ -251,305 +205,243 @@ int main(int argc, char **argv) bool mode_v = false; bool mode_q = false; - if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help"))) - { - printf("\n"); - printf("Usage: %s [options] [ [..]]\n", argv[0]); - printf("\n"); - printf(" -Q\n"); - printf(" suppress printing of banner (copyright, disclaimer, version)\n"); - printf("\n"); - printf(" -T\n"); - printf(" suppress printing of footer (log hash, version, timing statistics)\n"); - printf("\n"); - printf(" -q\n"); - printf(" quiet operation. only write warnings and error messages to console\n"); - printf(" use this option twice to also quiet warning messages\n"); - printf("\n"); - printf(" -v \n"); - printf(" print log headers up to level to the console. (this\n"); - printf(" implies -q for everything except the 'End of script.' message.)\n"); - printf("\n"); - printf(" -t\n"); - printf(" annotate all log messages with a time stamp\n"); - printf("\n"); - printf(" -d\n"); - printf(" print more detailed timing stats at exit\n"); - printf("\n"); - printf(" -l logfile\n"); - printf(" write log messages to the specified file\n"); - printf("\n"); - printf(" -L logfile\n"); - printf(" like -l but open log file in line buffered mode\n"); - printf("\n"); - printf(" -o outfile\n"); - printf(" write the design to the specified file on exit\n"); - printf("\n"); - printf(" -b backend\n"); - printf(" use this backend for the output file specified on the command line\n"); - printf("\n"); - printf(" -f frontend\n"); - printf(" use the specified frontend for the input files on the command line\n"); - printf("\n"); - printf(" -H\n"); - printf(" print the command list\n"); - printf("\n"); - printf(" -h command\n"); - printf(" print the help message for the specified command\n"); - printf("\n"); - printf(" -s scriptfile\n"); - printf(" execute the commands in the script file\n"); + cxxopts::Options options(argv[0], "Yosys Open SYnthesis Suite"); + options.set_width(SIZE_MAX); + + options.add_options("operation") + ("b,backend", "use for the output file specified on the command line", + cxxopts::value(), "") + ("f,frontend", "use for the input files on the command line", + cxxopts::value(), "") + ("s,scriptfile", "execute the commands in ", + cxxopts::value(), "") #ifdef YOSYS_ENABLE_TCL - printf("\n"); - printf(" -c tcl_scriptfile\n"); - printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n"); - printf("\n"); - printf(" -C\n"); - printf(" enters TCL interactive shell mode\n"); -#endif + ("c,tcl-scriptfile", "execute the commands in the TCL (see 'help tcl' for details)", + cxxopts::value(),"") + ("C,tcl-interactive", "enters TCL interactive shell mode") +#endif // YOSYS_ENABLE_TCL #ifdef WITH_PYTHON - printf("\n"); - printf(" -y python_scriptfile\n"); - printf(" execute a python script with libyosys available as a built-in module\n"); -#endif - printf("\n"); - printf(" -p command\n"); - printf(" execute the commands (to chain commands, separate them with semicolon + whitespace: 'cmd1; cmd2')\n"); - printf("\n"); - printf(" -m module_file\n"); - printf(" load the specified module (aka plugin)\n"); - printf("\n"); - printf(" -X\n"); - printf(" enable tracing of core data structure changes. for debugging\n"); - printf("\n"); - printf(" -M\n"); - printf(" will slightly randomize allocated pointer addresses. for debugging\n"); - printf("\n"); - printf(" -A\n"); - printf(" will call abort() at the end of the script. for debugging\n"); - printf("\n"); - printf(" -r \n"); - printf(" elaborate command line arguments using the specified top module\n"); - printf("\n"); - printf(" -D [=]\n"); - printf(" set the specified Verilog define (via \"read -define\")\n"); - printf("\n"); - printf(" -P [:]\n"); - printf(" dump the design when printing the specified log header to a file.\n"); - printf(" yosys_dump_.il is used as filename if none is specified.\n"); - printf(" Use 'ALL' as to dump at every header.\n"); - printf("\n"); - printf(" -W regex\n"); - printf(" print a warning for all log messages matching the regex.\n"); - printf("\n"); - printf(" -w regex\n"); - printf(" if a warning message matches the regex, it is printed as regular\n"); - printf(" message instead.\n"); - printf("\n"); - printf(" -e regex\n"); - printf(" if a warning message matches the regex, it is printed as error\n"); - printf(" message instead and the tool terminates with a nonzero return code.\n"); - printf("\n"); - printf(" -E \n"); - printf(" write a Makefile dependencies file with in- and output file names\n"); - printf("\n"); - printf(" -x \n"); - printf(" do not print warnings for the specified experimental feature\n"); - printf("\n"); - printf(" -g\n"); - printf(" globally enable debug log messages\n"); - printf("\n"); - printf(" -V\n"); - printf(" print version information and exit\n"); - printf("\n"); - printf("The option -S is a shortcut for calling the \"synth\" command, a default\n"); - printf("script for transforming the Verilog input to a gate-level netlist. For example:\n"); - printf("\n"); - printf(" yosys -o output.blif -S input.v\n"); - printf("\n"); - printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n"); - printf("commands in a script file instead of specifying input and output files on the\n"); - printf("command line.\n"); - printf("\n"); - printf("When no commands, script files or input files are specified on the command\n"); - printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n"); - printf("command to get information on the individual commands.\n"); - printf("\n"); + ("y,py-scriptfile", "execute the Python