@yowasp/yosys 0.56.963 → 0.57.141-dev.973
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gen/bundle.js +1 -1
- package/gen/resources-yosys.js +10 -10
- package/gen/yosys.core.wasm +0 -0
- package/package.json +2 -2
package/gen/resources-yosys.js
CHANGED
|
@@ -151,7 +151,7 @@ export const filesystem = {
|
|
|
151
151
|
},
|
|
152
152
|
"frontends": {
|
|
153
153
|
"ast": {
|
|
154
|
-
"ast.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * ---\n *\n * The AST frontend library is not a frontend on its own but provides an\n * abstract syntax tree (AST) abstraction for the open source Verilog frontend\n * at frontends/verilog.\n *\n */\n\n#ifndef AST_H\n#define AST_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/fmt.h\"\n#include <stdint.h>\n#include <set>\n\nYOSYS_NAMESPACE_BEGIN\n\nnamespace AST\n{\n\t// all node types, type2str() must be extended\n\t// whenever a new node type is added here\n\tenum AstNodeType\n\t{\n\t\tAST_NONE,\n\t\tAST_DESIGN,\n\t\tAST_MODULE,\n\t\tAST_TASK,\n\t\tAST_FUNCTION,\n\t\tAST_DPI_FUNCTION,\n\n\t\tAST_WIRE,\n\t\tAST_MEMORY,\n\t\tAST_AUTOWIRE,\n\t\tAST_PARAMETER,\n\t\tAST_LOCALPARAM,\n\t\tAST_DEFPARAM,\n\t\tAST_PARASET,\n\t\tAST_ARGUMENT,\n\t\tAST_RANGE,\n\t\tAST_MULTIRANGE,\n\t\tAST_CONSTANT,\n\t\tAST_REALVALUE,\n\t\tAST_CELLTYPE,\n\t\tAST_IDENTIFIER,\n\t\tAST_PREFIX,\n\t\tAST_ASSERT,\n\t\tAST_ASSUME,\n\t\tAST_LIVE,\n\t\tAST_FAIR,\n\t\tAST_COVER,\n\t\tAST_ENUM,\n\t\tAST_ENUM_ITEM,\n\n\t\tAST_FCALL,\n\t\tAST_TO_BITS,\n\t\tAST_TO_SIGNED,\n\t\tAST_TO_UNSIGNED,\n\t\tAST_SELFSZ,\n\t\tAST_CAST_SIZE,\n\t\tAST_CONCAT,\n\t\tAST_REPLICATE,\n\t\tAST_BIT_NOT,\n\t\tAST_BIT_AND,\n\t\tAST_BIT_OR,\n\t\tAST_BIT_XOR,\n\t\tAST_BIT_XNOR,\n\t\tAST_REDUCE_AND,\n\t\tAST_REDUCE_OR,\n\t\tAST_REDUCE_XOR,\n\t\tAST_REDUCE_XNOR,\n\t\tAST_REDUCE_BOOL,\n\t\tAST_SHIFT_LEFT,\n\t\tAST_SHIFT_RIGHT,\n\t\tAST_SHIFT_SLEFT,\n\t\tAST_SHIFT_SRIGHT,\n\t\tAST_SHIFTX,\n\t\tAST_SHIFT,\n\t\tAST_LT,\n\t\tAST_LE,\n\t\tAST_EQ,\n\t\tAST_NE,\n\t\tAST_EQX,\n\t\tAST_NEX,\n\t\tAST_GE,\n\t\tAST_GT,\n\t\tAST_ADD,\n\t\tAST_SUB,\n\t\tAST_MUL,\n\t\tAST_DIV,\n\t\tAST_MOD,\n\t\tAST_POW,\n\t\tAST_POS,\n\t\tAST_NEG,\n\t\tAST_LOGIC_AND,\n\t\tAST_LOGIC_OR,\n\t\tAST_LOGIC_NOT,\n\t\tAST_TERNARY,\n\t\tAST_MEMRD,\n\t\tAST_MEMWR,\n\t\tAST_MEMINIT,\n\n\t\tAST_TCALL,\n\t\tAST_ASSIGN,\n\t\tAST_CELL,\n\t\tAST_PRIMITIVE,\n\t\tAST_CELLARRAY,\n\t\tAST_ALWAYS,\n\t\tAST_INITIAL,\n\t\tAST_BLOCK,\n\t\tAST_ASSIGN_EQ,\n\t\tAST_ASSIGN_LE,\n\t\tAST_CASE,\n\t\tAST_COND,\n\t\tAST_CONDX,\n\t\tAST_CONDZ,\n\t\tAST_DEFAULT,\n\t\tAST_FOR,\n\t\tAST_WHILE,\n\t\tAST_REPEAT,\n\n\t\tAST_GENVAR,\n\t\tAST_GENFOR,\n\t\tAST_GENIF,\n\t\tAST_GENCASE,\n\t\tAST_GENBLOCK,\n\t\tAST_TECALL,\n\n\t\tAST_POSEDGE,\n\t\tAST_NEGEDGE,\n\t\tAST_EDGE,\n\n\t\tAST_INTERFACE,\n\t\tAST_INTERFACEPORT,\n\t\tAST_INTERFACEPORTTYPE,\n\t\tAST_MODPORT,\n\t\tAST_MODPORTMEMBER,\n\t\tAST_PACKAGE,\n\n\t\tAST_WIRETYPE,\n\t\tAST_TYPEDEF,\n\t\tAST_STRUCT,\n\t\tAST_UNION,\n\t\tAST_STRUCT_ITEM,\n\t\tAST_BIND\n\t};\n\n\tstruct AstSrcLocType {\n\t\tunsigned int first_line, last_line;\n\t\tunsigned int first_column, last_column;\n\t\tAstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}\n\t\tAstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}\n\t};\n\n\t// convert an node type to a string (e.g. for debug output)\n\tstd::string type2str(AstNodeType type);\n\n\t// The AST is built using instances of this struct\n\tstruct AstNode\n\t{\n\t\t// for dict<> and pool<>\n\t\tunsigned int hashidx_;\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\t\t// this nodes type\n\t\tAstNodeType type;\n\n\t\t// the list of child nodes for this node\n\t\tstd::vector<AstNode*> children;\n\n\t\t// the list of attributes assigned to this node\n\t\tstd::map<RTLIL::IdString, AstNode*> attributes;\n\t\tbool get_bool_attribute(RTLIL::IdString id);\n\n\t\t// node content - most of it is unused in most node types\n\t\tstd::string str;\n\t\tstd::vector<RTLIL::State> bits;\n\t\tbool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;\n\t\tint port_id, range_left, range_right;\n\t\tuint32_t integer;\n\t\tdouble realvalue;\n\t\t// set for IDs typed to an enumeration, not used\n\t\tbool is_enum;\n\n\t\t// Declared range for array dimension.\n\t\tstruct dimension_t {\n\t\t\tint range_right; // lsb in [msb:lsb]\n\t\t\tint range_width; // msb - lsb + 1\n\t\t\tbool range_swapped; // if the declared msb < lsb, msb and lsb above are swapped\n\t\t};\n\t\t// Packed and unpacked dimensions for arrays.\n\t\t// Unpacked dimensions go first, to follow the order of indexing.\n\t\tstd::vector<dimension_t> dimensions;\n\t\t// Number of unpacked dimensions.\n\t\tint unpacked_dimensions;\n\n\t\t// this is set by simplify and used during RTLIL generation\n\t\tAstNode *id2ast;\n\n\t\t// this is used by simplify to detect if basic analysis has been performed already on the node\n\t\tbool basic_prep;\n\n\t\t// this is used for ID references in RHS expressions that should use the \"new\" value for non-blocking assignments\n\t\tbool lookahead;\n\n\t\t// this is the original sourcecode location that resulted in this AST node\n\t\t// it is automatically set by the constructor using AST::current_filename and\n\t\t// the AST::get_line_num() callback function.\n\t\tstd::string filename;\n\t\tAstSrcLocType location;\n\n\t\t// are we embedded in an lvalue, param?\n\t\t// (see fixup_hierarchy_flags)\n\t\tbool in_lvalue;\n\t\tbool in_param;\n\t\tbool in_lvalue_from_above;\n\t\tbool in_param_from_above;\n\n\t\t// creating and deleting nodes\n\t\tAstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);\n\t\tAstNode *clone() const;\n\t\tvoid cloneInto(AstNode *other) const;\n\t\tvoid delete_children();\n\t\t~AstNode();\n\n\t\tenum mem2reg_flags\n\t\t{\n\t\t\t/* status flags */\n\t\t\tMEM2REG_FL_ALL = 0x00000001,\n\t\t\tMEM2REG_FL_ASYNC = 0x00000002,\n\t\t\tMEM2REG_FL_INIT = 0x00000004,\n\n\t\t\t/* candidate flags */\n\t\t\tMEM2REG_FL_FORCED = 0x00000100,\n\t\t\tMEM2REG_FL_SET_INIT = 0x00000200,\n\t\t\tMEM2REG_FL_SET_ELSE = 0x00000400,\n\t\t\tMEM2REG_FL_SET_ASYNC = 0x00000800,\n\t\t\tMEM2REG_FL_EQ2 = 0x00001000,\n\t\t\tMEM2REG_FL_CMPLX_LHS = 0x00002000,\n\t\t\tMEM2REG_FL_CONST_LHS = 0x00004000,\n\t\t\tMEM2REG_FL_VAR_LHS = 0x00008000,\n\n\t\t\t/* proc flags */\n\t\t\tMEM2REG_FL_EQ1 = 0x01000000,\n\t\t};\n\n\t\t// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.\n\t\t// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()\n\t\tbool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);\n\t\tvoid replace_result_wire_name_in_function(const std::string &from, const std::string &to);\n\t\tAstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);\n\t\tvoid expand_genblock(const std::string &prefix);\n\t\tvoid label_genblks(std::set<std::string>& existing, int &counter);\n\t\tvoid mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,\n\t\t\t\tdict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);\n\t\tbool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);\n\t\tbool mem2reg_check(pool<AstNode*> &mem2reg_set);\n\t\tvoid mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);\n\t\tvoid meminfo(int &mem_width, int &mem_size, int &addr_bits);\n\t\tbool detect_latch(const std::string &var);\n\t\tconst RTLIL::Module* lookup_cell_module();\n\n\t\t// additional functionality for evaluating constant functions\n\t\tstruct varinfo_t {\n\t\t\tRTLIL::Const val;\n\t\t\tint offset;\n\t\t\tbool range_swapped;\n\t\t\tbool is_signed;\n\t\t\tAstNode *arg = nullptr;\n\t\t\tbool explicitly_sized;\n\t\t};\n\t\tbool has_const_only_constructs();\n\t\tbool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);\n\t\tAstNode *eval_const_function(AstNode *fcall, bool must_succeed);\n\t\tbool is_simple_const_expr();\n\n\t\t// helper for parsing format strings\n\t\tFmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0, bool may_fail = false);\n\n\t\tbool is_recursive_function() const;\n\t\tstd::pair<AstNode*, AstNode*> get_tern_choice();\n\n\t\t// create a human-readable text representation of the AST (for debugging)\n\t\tvoid dumpAst(FILE *f, std::string indent) const;\n\t\tvoid dumpVlog(FILE *f, std::string indent) const;\n\n\t\t// Generate RTLIL for a bind construct\n\t\tstd::vector<RTLIL::Binding *> genBindings() const;\n\n\t\t// used by genRTLIL() for detecting expression width and sign\n\t\tvoid detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);\n\t\tvoid detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);\n\n\t\t// create RTLIL code for this AST node\n\t\t// for expressions the resulting signal vector is returned\n\t\t// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module\n\t\tRTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);\n\t\tRTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);\n\n\t\t// compare AST nodes\n\t\tbool operator==(const AstNode &other) const;\n\t\tbool operator!=(const AstNode &other) const;\n\t\tbool contains(const AstNode *other) const;\n\n\t\t// helper functions for creating AST nodes for constants\n\t\tstatic AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);\n\t\tstatic AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);\n\t\tstatic AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);\n\t\tstatic AstNode *mkconst_str(const std::vector<RTLIL::State> &v);\n\t\tstatic AstNode *mkconst_str(const std::string &str);\n\n\t\t// helper function to create an AST node for a temporary register\n\t\tAstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);\n\n\t\t// helper function for creating sign-extended const objects\n\t\tRTLIL::Const bitsAsConst(int width, bool is_signed);\n\t\tRTLIL::Const bitsAsConst(int width = -1);\n\t\tRTLIL::Const bitsAsUnsizedConst(int width);\n\t\tRTLIL::Const asAttrConst() const;\n\t\tRTLIL::Const asParaConst() const;\n\t\tuint64_t asInt(bool is_signed);\n\t\tbool bits_only_01() const;\n\t\tbool asBool() const;\n\n\t\t// helper functions for real valued const eval\n\t\tint isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE\n\t\tdouble asReal(bool is_signed);\n\t\tRTLIL::Const realAsConst(int width);\n\n\t\t// helpers for enum\n\t\tvoid allocateDefaultEnumValues();\n\t\tvoid annotateTypedEnums(AstNode *template_node);\n\n\t\t// helpers for locations\n\t\tstd::string loc_string() const;\n\n\t\t// Helper for looking up identifiers which are prefixed with the current module name\n\t\tstd::string try_pop_module_prefix() const;\n\n\t\t// helper to clone the node with some of its subexpressions replaced with zero (this is used\n\t\t// to evaluate widths of dynamic ranges)\n\t\tAstNode *clone_at_zero();\n\n\t\tvoid set_attribute(RTLIL::IdString key, AstNode *node)\n\t\t{\n\t\t\tattributes[key] = node;\n\t\t\tnode->set_in_param_flag(true);\n\t\t}\n\n\t\t// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag\n\t\t// can be overridden based on the intrinsic properties of this node, i.e. based on its type)\n\t\tvoid set_in_lvalue_flag(bool flag, bool no_descend = false);\n\t\tvoid set_in_param_flag(bool flag, bool no_descend = false);\n\n\t\t// fix up the hierarchy flags (in_lvalue/in_param) of this node and its children\n\t\t//\n\t\t// to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after\n\t\t// parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs\n\t\t// localized fixups after modifying children/attributes of a particular node\n\t\tvoid fixup_hierarchy_flags(bool force_descend = false);\n\n\t\t// helpers for indexing\n\t\tAstNode *make_index_range(AstNode *node, bool unpacked_range = false);\n\t\tAstNode *get_struct_member() const;\n\n\t\t// helper to print errors from simplify/genrtlil code\n\t\t[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));\n\t};\n\n\t// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code\n\tvoid process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,\n\t\t\tbool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire);\n\n\t// parametric modules are supported directly by the AST library\n\t// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions\n\tstruct AstModule : RTLIL::Module {\n\t\tAstNode *ast;\n\t\tbool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;\n\t\t~AstModule() override;\n\t\tRTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;\n\t\tRTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;\n\t\tstd::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);\n\t\tvoid expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;\n\t\tbool reprocess_if_necessary(RTLIL::Design *design) override;\n\t\tRTLIL::Module *clone() const override;\n\t\tvoid loadconfig() const;\n\t};\n\n\t// this must be set by the language frontend before parsing the sources\n\t// the AstNode constructor then uses current_filename and get_line_num()\n\t// to initialize the filename and linenum properties of new nodes\n\textern std::string current_filename;\n\textern void (*set_line_num)(int);\n\textern int (*get_line_num)();\n\n\t// for stats\n\tunsigned long long astnode_count();\n\n\t// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive\n\t// to control the filename and linenum properties of new nodes not generated by a frontend parser)\n\tvoid use_internal_line_num();\n\n\t// call a DPI function\n\tAstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);\n\n\t// Helper functions related to handling SystemVerilog interfaces\n\tstd::pair<std::string,std::string> split_modport_from_type(std::string name_type);\n\tAstNode * find_modport(AstNode *intf, std::string name);\n\tvoid explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);\n\n\t// Helper for setting the src attribute.\n\tvoid set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);\n\n\t// generate standard $paramod... derived module name; parameters should be\n\t// in the order they are declared in the instantiated module\n\tstd::string derived_module_name(std::string stripped_name, const std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> ¶meters);\n\n\t// used to provide simplify() access to the current design for looking up\n\t// modules, ports, wires, etc.\n\tvoid set_simplify_design_context(const RTLIL::Design *design);\n}\n\nnamespace AST_INTERNAL\n{\n\t// internal state variables\n\textern bool flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;\n\textern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire;\n\textern AST::AstNode *current_ast, *current_ast_mod;\n\textern std::map<std::string, AST::AstNode*> current_scope;\n\textern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;\n\textern RTLIL::SigSpec ignoreThisSignalsInInitial;\n\textern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;\n\textern RTLIL::Module *current_module;\n\textern bool current_always_clocked;\n\textern dict<std::string, int> current_memwr_count;\n\textern dict<std::string, pool<int>> current_memwr_visible;\n\tstruct LookaheadRewriter;\n\tstruct ProcessGenerator;\n\n\t// Create and add a new AstModule from new_ast, then use it to replace\n\t// old_module in design, renaming old_module to move it out of the way.\n\t// Return the new module.\n\t//\n\t// If original_ast is not null, it will be used as the AST node for the\n\t// new module. Otherwise, new_ast will be used.\n\tRTLIL::Module *\n\tprocess_and_replace_module(RTLIL::Design *design,\n\t RTLIL::Module *old_module,\n\t AST::AstNode *new_ast,\n\t AST::AstNode *original_ast = nullptr);\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
154
|
+
"ast.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * ---\n *\n * The AST frontend library is not a frontend on its own but provides an\n * abstract syntax tree (AST) abstraction for the open source Verilog frontend\n * at frontends/verilog.\n *\n */\n\n#ifndef AST_H\n#define AST_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/fmt.h\"\n#include \"frontends/verilog/verilog_location.h\"\n#include <stdint.h>\n#include <set>\n\nYOSYS_NAMESPACE_BEGIN\n\nnamespace AST\n{\n\t// all node types, type2str() must be extended\n\t// whenever a new node type is added here\n\tenum AstNodeType\n\t{\n\t\tAST_NONE,\n\t\tAST_DESIGN,\n\t\tAST_MODULE,\n\t\tAST_TASK,\n\t\tAST_FUNCTION,\n\t\tAST_DPI_FUNCTION,\n\n\t\tAST_WIRE,\n\t\tAST_MEMORY,\n\t\tAST_AUTOWIRE,\n\t\tAST_PARAMETER,\n\t\tAST_LOCALPARAM,\n\t\tAST_DEFPARAM,\n\t\tAST_PARASET,\n\t\tAST_ARGUMENT,\n\t\tAST_RANGE,\n\t\tAST_MULTIRANGE,\n\t\tAST_CONSTANT,\n\t\tAST_REALVALUE,\n\t\tAST_CELLTYPE,\n\t\tAST_IDENTIFIER,\n\t\tAST_PREFIX,\n\t\tAST_ASSERT,\n\t\tAST_ASSUME,\n\t\tAST_LIVE,\n\t\tAST_FAIR,\n\t\tAST_COVER,\n\t\tAST_ENUM,\n\t\tAST_ENUM_ITEM,\n\n\t\tAST_FCALL,\n\t\tAST_TO_BITS,\n\t\tAST_TO_SIGNED,\n\t\tAST_TO_UNSIGNED,\n\t\tAST_SELFSZ,\n\t\tAST_CAST_SIZE,\n\t\tAST_CONCAT,\n\t\tAST_REPLICATE,\n\t\tAST_BIT_NOT,\n\t\tAST_BIT_AND,\n\t\tAST_BIT_OR,\n\t\tAST_BIT_XOR,\n\t\tAST_BIT_XNOR,\n\t\tAST_REDUCE_AND,\n\t\tAST_REDUCE_OR,\n\t\tAST_REDUCE_XOR,\n\t\tAST_REDUCE_XNOR,\n\t\tAST_REDUCE_BOOL,\n\t\tAST_SHIFT_LEFT,\n\t\tAST_SHIFT_RIGHT,\n\t\tAST_SHIFT_SLEFT,\n\t\tAST_SHIFT_SRIGHT,\n\t\tAST_SHIFTX,\n\t\tAST_SHIFT,\n\t\tAST_LT,\n\t\tAST_LE,\n\t\tAST_EQ,\n\t\tAST_NE,\n\t\tAST_EQX,\n\t\tAST_NEX,\n\t\tAST_GE,\n\t\tAST_GT,\n\t\tAST_ADD,\n\t\tAST_SUB,\n\t\tAST_MUL,\n\t\tAST_DIV,\n\t\tAST_MOD,\n\t\tAST_POW,\n\t\tAST_POS,\n\t\tAST_NEG,\n\t\tAST_LOGIC_AND,\n\t\tAST_LOGIC_OR,\n\t\tAST_LOGIC_NOT,\n\t\tAST_TERNARY,\n\t\tAST_MEMRD,\n\t\tAST_MEMWR,\n\t\tAST_MEMINIT,\n\n\t\tAST_TCALL,\n\t\tAST_ASSIGN,\n\t\tAST_CELL,\n\t\tAST_PRIMITIVE,\n\t\tAST_CELLARRAY,\n\t\tAST_ALWAYS,\n\t\tAST_INITIAL,\n\t\tAST_BLOCK,\n\t\tAST_ASSIGN_EQ,\n\t\tAST_ASSIGN_LE,\n\t\tAST_CASE,\n\t\tAST_COND,\n\t\tAST_CONDX,\n\t\tAST_CONDZ,\n\t\tAST_DEFAULT,\n\t\tAST_FOR,\n\t\tAST_WHILE,\n\t\tAST_REPEAT,\n\n\t\tAST_GENVAR,\n\t\tAST_GENFOR,\n\t\tAST_GENIF,\n\t\tAST_GENCASE,\n\t\tAST_GENBLOCK,\n\t\tAST_TECALL,\n\n\t\tAST_POSEDGE,\n\t\tAST_NEGEDGE,\n\t\tAST_EDGE,\n\n\t\tAST_INTERFACE,\n\t\tAST_INTERFACEPORT,\n\t\tAST_INTERFACEPORTTYPE,\n\t\tAST_MODPORT,\n\t\tAST_MODPORTMEMBER,\n\t\tAST_PACKAGE,\n\t\tAST_IMPORT,\n\n\t\tAST_WIRETYPE,\n\t\tAST_TYPEDEF,\n\t\tAST_STRUCT,\n\t\tAST_UNION,\n\t\tAST_STRUCT_ITEM,\n\t\tAST_BIND\n\t};\n\n\tusing AstSrcLocType = Location;\n\n\t// convert an node type to a string (e.g. for debug output)\n\tstd::string type2str(AstNodeType type);\n\n\t// The AST is built using instances of this struct\n\tstruct AstNode\n\t{\n\t\t// for dict<> and pool<>\n\t\tunsigned int hashidx_;\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\t\t// this nodes type\n\t\tAstNodeType type;\n\n\t\t// the list of child nodes for this node\n\t\tstd::vector<std::unique_ptr<AstNode>> children;\n\n\t\t// the list of attributes assigned to this node\n\t\tstd::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;\n\t\tbool get_bool_attribute(RTLIL::IdString id);\n\n\t\t// node content - most of it is unused in most node types\n\t\tstd::string str;\n\t\tstd::vector<RTLIL::State> bits;\n\t\tbool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;\n\t\tint port_id, range_left, range_right;\n\t\tuint32_t integer;\n\t\tdouble realvalue;\n\t\t// set for IDs typed to an enumeration, not used\n\t\tbool is_enum;\n\n\t\t// Declared range for array dimension.\n\t\tstruct dimension_t {\n\t\t\tint range_right; // lsb in [msb:lsb]\n\t\t\tint range_width; // msb - lsb + 1\n\t\t\tbool range_swapped; // if the declared msb < lsb, msb and lsb above are swapped\n\t\t};\n\t\t// Packed and unpacked dimensions for arrays.\n\t\t// Unpacked dimensions go first, to follow the order of indexing.\n\t\tstd::vector<dimension_t> dimensions;\n\t\t// Number of unpacked dimensions.\n\t\tint unpacked_dimensions;\n\n\t\t// this is set by simplify and used during RTLIL generation\n\t\tAstNode* id2ast;\n\n\t\t// this is used by simplify to detect if basic analysis has been performed already on the node\n\t\tbool basic_prep;\n\n\t\t// this is used for ID references in RHS expressions that should use the \"new\" value for non-blocking assignments\n\t\tbool lookahead;\n\n\t\t// this is the original sourcecode location that resulted in this AST node\n\t\t// it is automatically set by the constructor using AST::current_filename and\n\t\t// the AST::get_line_num() callback function.\n\t\tAstSrcLocType location;\n\n\t\t// are we embedded in an lvalue, param?\n\t\t// (see fixup_hierarchy_flags)\n\t\tbool in_lvalue;\n\t\tbool in_param;\n\t\tbool in_lvalue_from_above;\n\t\tbool in_param_from_above;\n\n\t\t// creating and deleting nodes\n\t\tAstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);\n\t\tstd::unique_ptr<AstNode> clone() const;\n\t\tvoid cloneInto(AstNode &other) const;\n\t\tvoid delete_children();\n\t\t~AstNode();\n\n\t\tenum mem2reg_flags\n\t\t{\n\t\t\t/* status flags */\n\t\t\tMEM2REG_FL_ALL = 0x00000001,\n\t\t\tMEM2REG_FL_ASYNC = 0x00000002,\n\t\t\tMEM2REG_FL_INIT = 0x00000004,\n\n\t\t\t/* candidate flags */\n\t\t\tMEM2REG_FL_FORCED = 0x00000100,\n\t\t\tMEM2REG_FL_SET_INIT = 0x00000200,\n\t\t\tMEM2REG_FL_SET_ELSE = 0x00000400,\n\t\t\tMEM2REG_FL_SET_ASYNC = 0x00000800,\n\t\t\tMEM2REG_FL_EQ2 = 0x00001000,\n\t\t\tMEM2REG_FL_CMPLX_LHS = 0x00002000,\n\t\t\tMEM2REG_FL_CONST_LHS = 0x00004000,\n\t\t\tMEM2REG_FL_VAR_LHS = 0x00008000,\n\n\t\t\t/* proc flags */\n\t\t\tMEM2REG_FL_EQ1 = 0x01000000,\n\t\t};\n\n\t\t// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.\n\t\t// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()\n\t\tbool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);\n\t\tvoid replace_result_wire_name_in_function(const std::string &from, const std::string &to);\n\t\tstd::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);\n\t\tvoid expand_genblock(const std::string &prefix);\n\t\tvoid label_genblks(std::set<std::string>& existing, int &counter);\n\t\tvoid mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,\n\t\t\t\tdict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);\n\t\tbool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);\n\t\tbool mem2reg_check(pool<AstNode*> &mem2reg_set);\n\t\tvoid mem2reg_remove(pool<AstNode*> &mem2reg_set);\n\t\tvoid meminfo(int &mem_width, int &mem_size, int &addr_bits);\n\t\tbool detect_latch(const std::string &var);\n\t\tconst RTLIL::Module* lookup_cell_module();\n\n\t\t// additional functionality for evaluating constant functions\n\t\tstruct varinfo_t {\n\t\t\tRTLIL::Const val;\n\t\t\tint offset;\n\t\t\tbool range_swapped;\n\t\t\tbool is_signed;\n\t\t\tAstNode *arg = nullptr;\n\t\t\tbool explicitly_sized;\n\t\t};\n\t\tbool has_const_only_constructs();\n\t\tbool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);\n\t\tstd::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);\n\t\tbool is_simple_const_expr();\n\n\t\t// helper for parsing format strings\n\t\tFmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0, bool may_fail = false);\n\n\t\tbool is_recursive_function() const;\n\t\tstd::pair<AstNode*, AstNode*> get_tern_choice();\n\n\t\t// create a human-readable text representation of the AST (for debugging)\n\t\tvoid dumpAst(FILE *f, std::string indent) const;\n\t\tvoid dumpVlog(FILE *f, std::string indent) const;\n\n\t\t// Generate RTLIL for a bind construct\n\t\tstd::vector<RTLIL::Binding *> genBindings() const;\n\n\t\t// used by genRTLIL() for detecting expression width and sign\n\t\tvoid detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);\n\t\tvoid detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);\n\n\t\t// create RTLIL code for this AST node\n\t\t// for expressions the resulting signal vector is returned\n\t\t// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module\n\t\tRTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);\n\t\tRTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);\n\n\t\t// compare AST nodes\n\t\tbool operator==(const AstNode &other) const;\n\t\tbool operator!=(const AstNode &other) const;\n\t\tbool contains(const AstNode *other) const;\n\t\tAstNode operator=(AstNode) = delete;\n\n\t\t// helper functions for creating AST nodes for constants\n\t\tstatic std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);\n\t\tstatic std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);\n\t\tstatic std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);\n\t\tstatic std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);\n\t\tstatic std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);\n\n\t\t// helper function to create an AST node for a temporary register\n\t\tstd::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);\n\n\t\t// helper function for creating sign-extended const objects\n\t\tRTLIL::Const bitsAsConst(int width, bool is_signed);\n\t\tRTLIL::Const bitsAsConst(int width = -1);\n\t\tRTLIL::Const bitsAsUnsizedConst(int width);\n\t\tRTLIL::Const asAttrConst() const;\n\t\tRTLIL::Const asParaConst() const;\n\t\tuint64_t asInt(bool is_signed);\n\t\tbool bits_only_01() const;\n\t\tbool asBool() const;\n\n\t\t// helper functions for real valued const eval\n\t\tint isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE\n\t\tdouble asReal(bool is_signed);\n\t\tRTLIL::Const realAsConst(int width);\n\n\t\t// helpers for enum\n\t\tvoid allocateDefaultEnumValues();\n\t\tvoid annotateTypedEnums(AstNode *template_node);\n\n\t\t// helpers for locations\n\t\tstd::string loc_string() const;\n\n\t\t// Helper for looking up identifiers which are prefixed with the current module name\n\t\tstd::string try_pop_module_prefix() const;\n\n\t\t// helper to clone the node with some of its subexpressions replaced with zero (this is used\n\t\t// to evaluate widths of dynamic ranges)\n\t\tstd::unique_ptr<AstNode> clone_at_zero();\n\n\t\tvoid set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)\n\t\t{\n\t\t\tnode->set_in_param_flag(true);\n\t\t\tattributes[key] = std::move(node);\n\t\t}\n\n\t\t// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag\n\t\t// can be overridden based on the intrinsic properties of this node, i.e. based on its type)\n\t\tvoid set_in_lvalue_flag(bool flag, bool no_descend = false);\n\t\tvoid set_in_param_flag(bool flag, bool no_descend = false);\n\n\t\t// fix up the hierarchy flags (in_lvalue/in_param) of this node and its children\n\t\t//\n\t\t// to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after\n\t\t// parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs\n\t\t// localized fixups after modifying children/attributes of a particular node\n\t\tvoid fixup_hierarchy_flags(bool force_descend = false);\n\n\t\t// helpers for indexing\n\t\tstd::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);\n\t\tAstNode *get_struct_member() const;\n\n\t\t// helper to print errors from simplify/genrtlil code\n\t\t[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));\n\t};\n\n\t// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code\n\tvoid process(RTLIL::Design *design, AstNode *ast, bool nodisplay, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,\n\t\t\tbool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire);\n\n\t// parametric modules are supported directly by the AST library\n\t// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions\n\tstruct AstModule : RTLIL::Module {\n\t\tstd::unique_ptr<AstNode> ast;\n\t\tbool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;\n\t\tRTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;\n\t\tRTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;\n\t\tstd::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);\n\t\tvoid expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;\n\t\tbool reprocess_if_necessary(RTLIL::Design *design) override;\n\t\tRTLIL::Module *clone() const override;\n\t\tvoid loadconfig() const;\n\t};\n\n\t// this must be set by the language frontend before parsing the sources\n\t// the AstNode constructor then uses current_filename and get_line_num()\n\t// to initialize the filename and linenum properties of new nodes\n\t// extern std::string current_filename;\n\t// also set by the language frontend to control some AST processing\n\textern bool sv_mode_but_global_and_used_for_literally_one_condition;\n\n\t// for stats\n\tunsigned long long astnode_count();\n\n\t// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive\n\t// to control the filename and linenum properties of new nodes not generated by a frontend parser)\n\tvoid use_internal_line_num();\n\n\t// call a DPI function\n\tstd::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);\n\n\t// Helper functions related to handling SystemVerilog interfaces\n\tstd::pair<std::string,std::string> split_modport_from_type(std::string name_type);\n\tAstNode * find_modport(AstNode *intf, std::string name);\n\tvoid explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);\n\n\t// Helper for setting the src attribute.\n\tvoid set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);\n\n\t// generate standard $paramod... derived module name; parameters should be\n\t// in the order they are declared in the instantiated module\n\tstd::string derived_module_name(std::string stripped_name, const std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> ¶meters);\n\n\t// used to provide simplify() access to the current design for looking up\n\t// modules, ports, wires, etc.\n\tvoid set_simplify_design_context(const RTLIL::Design *design);\n}\n\nnamespace AST_INTERNAL\n{\n\t// internal state variables\n\textern bool flag_nodisplay, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_rtlil, flag_nolatches, flag_nomeminit;\n\textern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_pwires, flag_autowire;\n\textern AST::AstNode *current_ast, *current_ast_mod;\n\textern std::map<std::string, AST::AstNode*> current_scope;\n\textern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;\n\textern RTLIL::SigSpec ignoreThisSignalsInInitial;\n\textern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;\n\textern RTLIL::Module *current_module;\n\textern bool current_always_clocked;\n\textern dict<std::string, int> current_memwr_count;\n\textern dict<std::string, pool<int>> current_memwr_visible;\n\tstruct LookaheadRewriter;\n\tstruct ProcessGenerator;\n\n\t// Create and add a new AstModule from new_ast, then use it to replace\n\t// old_module in design, renaming old_module to move it out of the way.\n\t// Return the new module.\n\t//\n\t// If original_ast is not null, it will be used as the AST node for the\n\t// new module. Otherwise, new_ast will be used.\n\tRTLIL::Module *\n\tprocess_and_replace_module(RTLIL::Design *design,\n\t RTLIL::Module *old_module,\n\t AST::AstNode *new_ast,\n\t std::unique_ptr<AST::AstNode> original_ast = nullptr);\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
155
155
|
"ast_binding.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * ---\n *\n * This header declares the AST::Binding class\n *\n * This is used to support the bind directive and is to RTLIL::Binding as\n * AST::AstModule is to RTLIL::Module, holding a syntax-level representation of\n * cells until we get to a stage where they make sense. In the case of a bind\n * directive, this is when we elaborate the design in the hierarchy pass.\n *\n */\n\n#ifndef AST_BINDING_H\n#define AST_BINDING_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/binding.h\"\n\n#include <memory>\n\nYOSYS_NAMESPACE_BEGIN\n\nnamespace AST\n{\n\tclass Binding : public RTLIL::Binding\n\t{\n\tpublic:\n\t\tBinding(RTLIL::IdString target_type,\n\t\t RTLIL::IdString target_name,\n\t\t const AstNode &cell);\n\n\t\tstd::string describe() const override;\n\n\tprivate:\n\t\t// The syntax-level representation of the cell to be bound.\n\t\tstd::unique_ptr<AstNode> ast_node;\n\t};\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
156
156
|
},
|
|
157
157
|
"blif": {
|
|
@@ -163,30 +163,30 @@ export const filesystem = {
|
|
|
163
163
|
"bitpattern.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef BITPATTERN_H\n#define BITPATTERN_H\n\n#include \"kernel/log.h\"\n#include \"kernel/rtlil.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct BitPatternPool\n{\n\tint width;\n\tstruct bits_t {\n\t\tstd::vector<RTLIL::State> bitdata;\n\t\tmutable Hasher::hash_t cached_hash;\n\t\tbits_t(int width = 0) : bitdata(width), cached_hash(0) { }\n\t\tRTLIL::State &operator[](int index) {\n\t\t\treturn bitdata[index];\n\t\t}\n\t\tconst RTLIL::State &operator[](int index) const {\n\t\t\treturn bitdata[index];\n\t\t}\n\t\tbool operator==(const bits_t &other) const {\n\t\t\tif (run_hash(*this) != run_hash(other))\n\t\t\t\treturn false;\n\t\t\treturn bitdata == other.bitdata;\n\t\t}\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\tif (!cached_hash)\n\t\t\t\tcached_hash = run_hash(bitdata);\n\t\t\th.eat(cached_hash);\n\t\t\treturn h;\n\t\t}\n\t};\n\tpool<bits_t> database;\n\n\tBitPatternPool(RTLIL::SigSpec sig)\n\t{\n\t\twidth = sig.size();\n\t\tif (width > 0) {\n\t\t\tbits_t pattern(width);\n\t\t\tfor (int i = 0; i < width; i++) {\n\t\t\t\tif (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)\n\t\t\t\t\tpattern[i] = sig[i].data;\n\t\t\t\telse\n\t\t\t\t\tpattern[i] = RTLIL::State::Sa;\n\t\t\t}\n\t\t\tdatabase.insert(pattern);\n\t\t}\n\t}\n\n\tBitPatternPool(int width)\n\t{\n\t\tthis->width = width;\n\t\tif (width > 0) {\n\t\t\tbits_t pattern(width);\n\t\t\tfor (int i = 0; i < width; i++)\n\t\t\t\tpattern[i] = RTLIL::State::Sa;\n\t\t\tdatabase.insert(pattern);\n\t\t}\n\t}\n\n\tbits_t sig2bits(RTLIL::SigSpec sig)\n\t{\n\t\tbits_t bits;\n\t\tbits.bitdata = sig.as_const().bits();\n\t\tfor (auto &b : bits.bitdata)\n\t\t\tif (b > RTLIL::State::S1)\n\t\t\t\tb = RTLIL::State::Sa;\n\t\treturn bits;\n\t}\n\n\tbool match(bits_t a, bits_t b)\n\t{\n\t\tlog_assert(int(a.bitdata.size()) == width);\n\t\tlog_assert(int(b.bitdata.size()) == width);\n\t\tfor (int i = 0; i < width; i++)\n\t\t\tif (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])\n\t\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tbool has_any(RTLIL::SigSpec sig)\n\t{\n\t\tbits_t bits = sig2bits(sig);\n\t\tfor (auto &it : database)\n\t\t\tif (match(it, bits))\n\t\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool has_all(RTLIL::SigSpec sig)\n\t{\n\t\tbits_t bits = sig2bits(sig);\n\t\tfor (auto &it : database)\n\t\t\tif (match(it, bits)) {\n\t\t\t\tfor (int i = 0; i < width; i++)\n\t\t\t\t\tif (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)\n\t\t\t\t\t\tgoto next_database_entry;\n\t\t\t\treturn true;\n\tnext_database_entry:;\n\t\t\t}\n\t\treturn false;\n\t}\n\n\tbool take(RTLIL::SigSpec sig)\n\t{\n\t\tbool status = false;\n\t\tbits_t bits = sig2bits(sig);\n\t\tfor (auto it = database.begin(); it != database.end();)\n\t\t\tif (match(*it, bits)) {\n\t\t\t\tfor (int i = 0; i < width; i++) {\n\t\t\t\t\tif ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tbits_t new_pattern;\n\t\t\t\t\tnew_pattern.bitdata = it->bitdata;\n\t\t\t\t\tnew_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;\n\t\t\t\t\tdatabase.insert(new_pattern);\n\t\t\t\t}\n\t\t\t\tit = database.erase(it);\n\t\t\t\tstatus = true;\n\t\t\t\tcontinue;\n\t\t\t} else\n\t\t\t\t++it;\n\t\treturn status;\n\t}\n\n\tbool take_all()\n\t{\n\t\tif (database.empty())\n\t\t\treturn false;\n\t\tdatabase.clear();\n\t\treturn true;\n\t}\n\n\tbool empty()\n\t{\n\t\treturn database.empty();\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
164
164
|
"cellaigs.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CELLAIGS_H\n#define CELLAIGS_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct AigNode\n{\n\tIdString portname;\n\tint portbit;\n\tbool inverter;\n\tint left_parent, right_parent;\n\tvector<pair<IdString, int>> outports;\n\n\tAigNode();\n\tbool operator==(const AigNode &other) const;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\nstruct Aig\n{\n\tstring name;\n\tvector<AigNode> nodes;\n\tAig(Cell *cell);\n\n\tbool operator==(const Aig &other) const;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
165
165
|
"celledges.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CELLEDGES_H\n#define CELLEDGES_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/sigtools.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct AbstractCellEdgesDatabase\n{\n\tvirtual ~AbstractCellEdgesDatabase() { }\n\tvirtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int delay) = 0;\n\tbool add_edges_from_cell(RTLIL::Cell *cell);\n};\n\nstruct FwdCellEdgesDatabase : AbstractCellEdgesDatabase\n{\n\tSigMap &sigmap;\n\tdict<SigBit, pool<SigBit>> db;\n\tFwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }\n\n\tvoid add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {\n\t\tSigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);\n\t\tSigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);\n\t\tdb[from_sigbit].insert(to_sigbit);\n\t}\n};\n\nstruct RevCellEdgesDatabase : AbstractCellEdgesDatabase\n{\n\tSigMap &sigmap;\n\tdict<SigBit, pool<SigBit>> db;\n\tRevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }\n\n\tvoid add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {\n\t\tSigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);\n\t\tSigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);\n\t\tdb[to_sigbit].insert(from_sigbit);\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
166
|
-
"celltypes.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CELLTYPES_H\n#define CELLTYPES_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct CellType\n{\n\tRTLIL::IdString type;\n\tpool<RTLIL::IdString> inputs, outputs;\n\tbool is_evaluable;\n\tbool is_combinatorial;\n\tbool is_synthesizable;\n};\n\nstruct CellTypes\n{\n\tdict<RTLIL::IdString, CellType> cell_types;\n\n\tCellTypes()\n\t{\n\t}\n\n\tCellTypes(RTLIL::Design *design)\n\t{\n\t\tsetup(design);\n\t}\n\n\tvoid setup(RTLIL::Design *design = NULL)\n\t{\n\t\tif (design)\n\t\t\tsetup_design(design);\n\n\t\tsetup_internals();\n\t\tsetup_internals_mem();\n\t\tsetup_internals_anyinit();\n\t\tsetup_stdcells();\n\t\tsetup_stdcells_mem();\n\t}\n\n\tvoid setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false)\n\t{\n\t\tCellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable};\n\t\tcell_types[ct.type] = ct;\n\t}\n\n\tvoid setup_module(RTLIL::Module *module)\n\t{\n\t\tpool<RTLIL::IdString> inputs, outputs;\n\t\tfor (RTLIL::IdString wire_name : module->ports) {\n\t\t\tRTLIL::Wire *wire = module->wire(wire_name);\n\t\t\tif (wire->port_input)\n\t\t\t\tinputs.insert(wire->name);\n\t\t\tif (wire->port_output)\n\t\t\t\toutputs.insert(wire->name);\n\t\t}\n\t\tsetup_type(module->name, inputs, outputs);\n\t}\n\n\tvoid setup_design(RTLIL::Design *design)\n\t{\n\t\tfor (auto module : design->modules())\n\t\t\tsetup_module(module);\n\t}\n\n\tvoid setup_internals()\n\t{\n\t\tsetup_internals_eval();\n\n\t\tsetup_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, true);\n\n\t\tsetup_type(ID($assert), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($assume), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($live), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($fair), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($cover), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($initstate), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($anyconst), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($anyseq), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($allconst), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($allseq), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y});\n\t\tsetup_type(ID($get_tag), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($original_tag), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($future_ff), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($scopeinfo), {}, {});\n\t}\n\n\tvoid setup_internals_eval()\n\t{\n\t\tstd::vector<RTLIL::IdString> unary_ops = {\n\t\t\tID($not), ID($pos), ID($buf), ID($neg),\n\t\t\tID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),\n\t\t\tID($logic_not), ID($slice), ID($lut), ID($sop)\n\t\t};\n\n\t\tstd::vector<RTLIL::IdString> binary_ops = {\n\t\t\tID($and), ID($or), ID($xor), ID($xnor),\n\t\t\tID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),\n\t\t\tID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),\n\t\t\tID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),\n\t\t\tID($logic_and), ID($logic_or), ID($concat), ID($macc),\n\t\t\tID($bweqx)\n\t\t};\n\n\t\tfor (auto type : unary_ops)\n\t\t\tsetup_type(type, {ID::A}, {ID::Y}, true);\n\n\t\tfor (auto type : binary_ops)\n\t\t\tsetup_type(type, {ID::A, ID::B}, {ID::Y}, true);\n\n\t\tfor (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux), ID($bwmux)}))\n\t\t\tsetup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\n\t\tfor (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))\n\t\t\tsetup_type(type, {ID::A, ID::S}, {ID::Y}, true);\n\n\t\tsetup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);\n\t\tsetup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);\n\t\tsetup_type(ID($macc_v2), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);\n\t}\n\n\tvoid setup_internals_ff()\n\t{\n\t\tsetup_type(ID($sr), {ID::SET, ID::CLR}, {ID::Q});\n\t\tsetup_type(ID($ff), {ID::D}, {ID::Q});\n\t\tsetup_type(ID($dff), {ID::CLK, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q});\n\t\tsetup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q});\n\t\tsetup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q});\n\t\tsetup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q});\n\t\tsetup_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q});\n\t\tsetup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});\n\t}\n\n\tvoid setup_internals_anyinit()\n\t{\n\t\tsetup_type(ID($anyinit), {ID::D}, {ID::Q});\n\t}\n\n\tvoid setup_internals_mem()\n\t{\n\t\tsetup_internals_ff();\n\n\t\tsetup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA});\n\t\tsetup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA});\n\t\tsetup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});\n\t\tsetup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});\n\n\t\tsetup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT});\n\t}\n\n\tvoid setup_stdcells()\n\t{\n\t\tsetup_stdcells_eval();\n\n\t\tsetup_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}, true);\n\t}\n\n\tvoid setup_stdcells_eval()\n\t{\n\t\tsetup_type(ID($_BUF_), {ID::A}, {ID::Y}, true);\n\t\tsetup_type(ID($_NOT_), {ID::A}, {ID::Y}, true);\n\t\tsetup_type(ID($_AND_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_NAND_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_OR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_NOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_XOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_XNOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_ANDNOT_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_ORNOT_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\t\tsetup_type(ID($_NMUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX4_), {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX8_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX16_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V}, {ID::Y}, true);\n\t\tsetup_type(ID($_AOI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($_OAI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($_AOI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true);\n\t\tsetup_type(ID($_OAI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true);\n\t}\n\n\tvoid setup_stdcells_mem()\n\t{\n\t\tstd::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_SR_%c%c_\", c1, c2), {ID::S, ID::R}, {ID::Q});\n\n\t\tsetup_type(ID($_FF_), {ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFF_%c_\", c1), {ID::C, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFE_%c%c_\", c1, c2), {ID::C, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_DFF_%c%c%c_\", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_ALDFF_%c%c_\", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_ALDFFE_%c%c%c_\", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFSR_%c%c%c_\", c1, c2, c3), {ID::C, ID::S, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFSRE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::S, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_SDFF_%c%c%c_\", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_SDFFE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_SDFFCE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\t\tsetup_type(stringf(\"$_DLATCH_%c_\", c1), {ID::E, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_DLATCH_%c%c%c_\", c1, c2, c3), {ID::E, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_DLATCHSR_%c%c%c_\", c1, c2, c3), {ID::E, ID::S, ID::R, ID::D}, {ID::Q});\n\t}\n\n\tvoid clear()\n\t{\n\t\tcell_types.clear();\n\t}\n\n\tbool cell_known(RTLIL::IdString type) const\n\t{\n\t\treturn cell_types.count(type) != 0;\n\t}\n\n\tbool cell_output(RTLIL::IdString type, RTLIL::IdString port) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.outputs.count(port) != 0;\n\t}\n\n\tbool cell_input(RTLIL::IdString type, RTLIL::IdString port) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.inputs.count(port) != 0;\n\t}\n\n\tbool cell_evaluable(RTLIL::IdString type) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.is_evaluable;\n\t}\n\n\tstatic RTLIL::Const eval_not(RTLIL::Const v)\n\t{\n\t\tfor (auto &bit : v.bits())\n\t\t\tif (bit == State::S0) bit = State::S1;\n\t\t\telse if (bit == State::S1) bit = State::S0;\n\t\treturn v;\n\t}\n\n\tstatic RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)\n\t{\n\t\tif (type == ID($sshr) && !signed1)\n\t\t\ttype = ID($shr);\n\t\tif (type == ID($sshl) && !signed1)\n\t\t\ttype = ID($shl);\n\n\t\tif (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&\n\t\t\t\ttype != ID($pos) && type != ID($buf) && type != ID($neg) && type != ID($not)) {\n\t\t\tif (!signed1 || !signed2)\n\t\t\t\tsigned1 = false, signed2 = false;\n\t\t}\n\n#define HANDLE_CELL_TYPE(_t) if (type == ID($##_t)) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);\n\t\tHANDLE_CELL_TYPE(not)\n\t\tHANDLE_CELL_TYPE(and)\n\t\tHANDLE_CELL_TYPE(or)\n\t\tHANDLE_CELL_TYPE(xor)\n\t\tHANDLE_CELL_TYPE(xnor)\n\t\tHANDLE_CELL_TYPE(reduce_and)\n\t\tHANDLE_CELL_TYPE(reduce_or)\n\t\tHANDLE_CELL_TYPE(reduce_xor)\n\t\tHANDLE_CELL_TYPE(reduce_xnor)\n\t\tHANDLE_CELL_TYPE(reduce_bool)\n\t\tHANDLE_CELL_TYPE(logic_not)\n\t\tHANDLE_CELL_TYPE(logic_and)\n\t\tHANDLE_CELL_TYPE(logic_or)\n\t\tHANDLE_CELL_TYPE(shl)\n\t\tHANDLE_CELL_TYPE(shr)\n\t\tHANDLE_CELL_TYPE(sshl)\n\t\tHANDLE_CELL_TYPE(sshr)\n\t\tHANDLE_CELL_TYPE(shift)\n\t\tHANDLE_CELL_TYPE(shiftx)\n\t\tHANDLE_CELL_TYPE(lt)\n\t\tHANDLE_CELL_TYPE(le)\n\t\tHANDLE_CELL_TYPE(eq)\n\t\tHANDLE_CELL_TYPE(ne)\n\t\tHANDLE_CELL_TYPE(eqx)\n\t\tHANDLE_CELL_TYPE(nex)\n\t\tHANDLE_CELL_TYPE(ge)\n\t\tHANDLE_CELL_TYPE(gt)\n\t\tHANDLE_CELL_TYPE(add)\n\t\tHANDLE_CELL_TYPE(sub)\n\t\tHANDLE_CELL_TYPE(mul)\n\t\tHANDLE_CELL_TYPE(div)\n\t\tHANDLE_CELL_TYPE(mod)\n\t\tHANDLE_CELL_TYPE(divfloor)\n\t\tHANDLE_CELL_TYPE(modfloor)\n\t\tHANDLE_CELL_TYPE(pow)\n\t\tHANDLE_CELL_TYPE(pos)\n\t\tHANDLE_CELL_TYPE(neg)\n#undef HANDLE_CELL_TYPE\n\n\t\tif (type.in(ID($_BUF_), ID($buf)))\n\t\t\treturn arg1;\n\t\tif (type == ID($_NOT_))\n\t\t\treturn eval_not(arg1);\n\t\tif (type == ID($_AND_))\n\t\t\treturn const_and(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_NAND_))\n\t\t\treturn eval_not(const_and(arg1, arg2, false, false, 1));\n\t\tif (type == ID($_OR_))\n\t\t\treturn const_or(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_NOR_))\n\t\t\treturn eval_not(const_or(arg1, arg2, false, false, 1));\n\t\tif (type == ID($_XOR_))\n\t\t\treturn const_xor(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_XNOR_))\n\t\t\treturn const_xnor(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_ANDNOT_))\n\t\t\treturn const_and(arg1, eval_not(arg2), false, false, 1);\n\t\tif (type == ID($_ORNOT_))\n\t\t\treturn const_or(arg1, eval_not(arg2), false, false, 1);\n\n\t\tif (errp != nullptr) {\n\t\t\t*errp = true;\n\t\t\treturn State::Sm;\n\t\t}\n\n\t\tlog_abort();\n\t}\n\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)\n\t{\n\t\tif (cell->type == ID($slice)) {\n\t\t\tRTLIL::Const ret;\n\t\t\tint width = cell->parameters.at(ID::Y_WIDTH).as_int();\n\t\t\tint offset = cell->parameters.at(ID::OFFSET).as_int();\n\t\t\tret.bits().insert(ret.bits().end(), arg1.begin()+offset, arg1.begin()+offset+width);\n\t\t\treturn ret;\n\t\t}\n\n\t\tif (cell->type == ID($concat)) {\n\t\t\tRTLIL::Const ret = arg1;\n\t\t\tret.bits().insert(ret.bits().end(), arg2.begin(), arg2.end());\n\t\t\treturn ret;\n\t\t}\n\n\t\tif (cell->type == ID($bmux))\n\t\t{\n\t\t\treturn const_bmux(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($demux))\n\t\t{\n\t\t\treturn const_demux(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($bweqx))\n\t\t{\n\t\t\treturn const_bweqx(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($lut))\n\t\t{\n\t\t\tint width = cell->parameters.at(ID::WIDTH).as_int();\n\n\t\t\tstd::vector<RTLIL::State> t = cell->parameters.at(ID::LUT).to_bits();\n\t\t\twhile (GetSize(t) < (1 << width))\n\t\t\t\tt.push_back(State::S0);\n\t\t\tt.resize(1 << width);\n\n\t\t\treturn const_bmux(t, arg1);\n\t\t}\n\n\t\tif (cell->type == ID($sop))\n\t\t{\n\t\t\tint width = cell->parameters.at(ID::WIDTH).as_int();\n\t\t\tint depth = cell->parameters.at(ID::DEPTH).as_int();\n\t\t\tstd::vector<RTLIL::State> t = cell->parameters.at(ID::TABLE).to_bits();\n\n\t\t\twhile (GetSize(t) < width*depth*2)\n\t\t\t\tt.push_back(State::S0);\n\n\t\t\tRTLIL::State default_ret = State::S0;\n\n\t\t\tfor (int i = 0; i < depth; i++)\n\t\t\t{\n\t\t\t\tbool match = true;\n\t\t\t\tbool match_x = true;\n\n\t\t\t\tfor (int j = 0; j < width; j++) {\n\t\t\t\t\tRTLIL::State a = arg1.at(j);\n\t\t\t\t\tif (t.at(2*width*i + 2*j + 0) == State::S1) {\n\t\t\t\t\t\tif (a == State::S1) match_x = false;\n\t\t\t\t\t\tif (a != State::S0) match = false;\n\t\t\t\t\t}\n\t\t\t\t\tif (t.at(2*width*i + 2*j + 1) == State::S1) {\n\t\t\t\t\t\tif (a == State::S0) match_x = false;\n\t\t\t\t\t\tif (a != State::S1) match = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (match)\n\t\t\t\t\treturn State::S1;\n\n\t\t\t\tif (match_x)\n\t\t\t\t\tdefault_ret = State::Sx;\n\t\t\t}\n\n\t\t\treturn default_ret;\n\t\t}\n\n\t\tbool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool();\n\t\tbool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool();\n\t\tint result_len = cell->parameters.count(ID::Y_WIDTH) > 0 ? cell->parameters[ID::Y_WIDTH].as_int() : -1;\n\t\treturn eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);\n\t}\n\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)\n\t{\n\t\tif (cell->type.in(ID($mux), ID($_MUX_)))\n\t\t\treturn const_mux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($bwmux))\n\t\t\treturn const_bwmux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($pmux))\n\t\t\treturn const_pmux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($_AOI3_))\n\t\t\treturn eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));\n\t\tif (cell->type == ID($_OAI3_))\n\t\t\treturn eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));\n\n\t\tlog_assert(arg3.size() == 0);\n\t\treturn eval(cell, arg1, arg2, errp);\n\t}\n\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)\n\t{\n\t\tif (cell->type == ID($_AOI4_))\n\t\t\treturn eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));\n\t\tif (cell->type == ID($_OAI4_))\n\t\t\treturn eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));\n\n\t\tlog_assert(arg4.size() == 0);\n\t\treturn eval(cell, arg1, arg2, arg3, errp);\n\t}\n};\n\n// initialized by yosys_setup()\nextern CellTypes yosys_celltypes;\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
167
|
-
"consteval.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CONSTEVAL_H\n#define CONSTEVAL_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n#include \"kernel/macc.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct ConstEval\n{\n\tRTLIL::Module *module;\n\tSigMap assign_map;\n\tSigMap values_map;\n\tSigPool stop_signals;\n\tSigSet<RTLIL::Cell*> sig2driver;\n\tstd::set<RTLIL::Cell*> busy;\n\tstd::vector<SigMap> stack;\n\tRTLIL::State defaultval;\n\n\tConstEval(RTLIL::Module *module, RTLIL::State defaultval = RTLIL::State::Sm) : module(module), assign_map(module), defaultval(defaultval)\n\t{\n\t\tCellTypes ct;\n\t\tct.setup_internals();\n\t\tct.setup_stdcells();\n\n\t\tfor (auto &it : module->cells_) {\n\t\t\tif (!ct.cell_known(it.second->type))\n\t\t\t\tcontinue;\n\t\t\tfor (auto &it2 : it.second->connections())\n\t\t\t\tif (ct.cell_output(it.second->type, it2.first))\n\t\t\t\t\tsig2driver.insert(assign_map(it2.second), it.second);\n\t\t}\n\t}\n\n\tvoid clear()\n\t{\n\t\tvalues_map.clear();\n\t\tstop_signals.clear();\n\t}\n\n\tvoid push()\n\t{\n\t\tstack.push_back(values_map);\n\t}\n\n\tvoid pop()\n\t{\n\t\tvalues_map.swap(stack.back());\n\t\tstack.pop_back();\n\t}\n\n\tvoid set(RTLIL::SigSpec sig, RTLIL::Const value)\n\t{\n\t\tassign_map.apply(sig);\n#ifndef NDEBUG\n\t\tRTLIL::SigSpec current_val = values_map(sig);\n\t\tfor (int i = 0; i < GetSize(current_val); i++)\n\t\t\tlog_assert(current_val[i].wire != NULL || current_val[i] == value[i]);\n#endif\n\t\tvalues_map.add(sig, RTLIL::SigSpec(value));\n\t}\n\n\tvoid stop(RTLIL::SigSpec sig)\n\t{\n\t\tassign_map.apply(sig);\n\t\tstop_signals.add(sig);\n\t}\n\n\tbool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)\n\t{\n\t\tif (cell->type == ID($lcu))\n\t\t{\n\t\t\tRTLIL::SigSpec sig_p = cell->getPort(ID::P);\n\t\t\tRTLIL::SigSpec sig_g = cell->getPort(ID::G);\n\t\t\tRTLIL::SigSpec sig_ci = cell->getPort(ID::CI);\n\t\t\tRTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort(ID::CO)));\n\n\t\t\tif (sig_co.is_fully_const())\n\t\t\t\treturn true;\n\n\t\t\tif (!eval(sig_p, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_g, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_ci, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())\n\t\t\t{\n\t\t\t\tRTLIL::Const coval(RTLIL::Sx, GetSize(sig_co));\n\t\t\t\tbool carry = sig_ci.as_bool();\n\n\t\t\t\tfor (int i = 0; i < GetSize(coval); i++) {\n\t\t\t\t\tcarry = (sig_g[i] == State::S1) || (sig_p[i] == RTLIL::S1 && carry);\n\t\t\t\t\tcoval.bits()[i] = carry ? State::S1 : State::S0;\n\t\t\t\t}\n\n\t\t\t\tset(sig_co, coval);\n\t\t\t}\n\t\t\telse\n\t\t\t\tset(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co)));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tRTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;\n\n\t\tlog_assert(cell->hasPort(ID::Y));\n\t\tsig_y = values_map(assign_map(cell->getPort(ID::Y)));\n\t\tif (sig_y.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (cell->hasPort(ID::S)) {\n\t\t\tsig_s = cell->getPort(ID::S);\n\t\t}\n\n\t\tif (cell->hasPort(ID::A))\n\t\t\tsig_a = cell->getPort(ID::A);\n\n\t\tif (cell->hasPort(ID::B))\n\t\t\tsig_b = cell->getPort(ID::B);\n\n\t\tif (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_)))\n\t\t{\n\t\t\tstd::vector<RTLIL::SigSpec> y_candidates;\n\t\t\tint count_set_s_bits = 0;\n\n\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tfor (int i = 0; i < sig_s.size(); i++)\n\t\t\t{\n\t\t\t\tRTLIL::State s_bit = sig_s.extract(i, 1).as_const().at(0);\n\t\t\t\tRTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size());\n\n\t\t\t\tif (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1)\n\t\t\t\t\ty_candidates.push_back(b_slice);\n\n\t\t\t\tif (s_bit == RTLIL::State::S1)\n\t\t\t\t\tcount_set_s_bits++;\n\t\t\t}\n\n\t\t\tif (count_set_s_bits == 0)\n\t\t\t\ty_candidates.push_back(sig_a);\n\n\t\t\tstd::vector<RTLIL::Const> y_values;\n\n\t\t\tlog_assert(y_candidates.size() > 0);\n\t\t\tfor (auto &yc : y_candidates) {\n\t\t\t\tif (!eval(yc, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tif (cell->type == ID($_NMUX_))\n\t\t\t\t\ty_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc)));\n\t\t\t\telse\n\t\t\t\t\ty_values.push_back(yc.as_const());\n\t\t\t}\n\n\t\t\tif (y_values.size() > 1)\n\t\t\t{\n\t\t\t\tstd::vector<RTLIL::State> master_bits = y_values.at(0).to_bits();\n\n\t\t\t\tfor (size_t i = 1; i < y_values.size(); i++) {\n\t\t\t\t\tstd::vector<RTLIL::State> slave_bits = y_values.at(i).to_bits();\n\t\t\t\t\tlog_assert(master_bits.size() == slave_bits.size());\n\t\t\t\t\tfor (size_t j = 0; j < master_bits.size(); j++)\n\t\t\t\t\t\tif (master_bits[j] != slave_bits[j])\n\t\t\t\t\t\t\tmaster_bits[j] = RTLIL::State::Sx;\n\t\t\t\t}\n\n\t\t\t\tset(sig_y, RTLIL::Const(master_bits));\n\t\t\t}\n\t\t\telse\n\t\t\t\tset(sig_y, y_values.front());\n\t\t}\n\t\telse if (cell->type == ID($bmux))\n\t\t{\n\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (sig_s.is_fully_def()) {\n\t\t\t\tint sel = sig_s.as_int();\n\t\t\t\tint width = GetSize(sig_y);\n\t\t\t\tSigSpec res = sig_a.extract(sel * width, width);\n\t\t\t\tif (!eval(res, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, res.as_const());\n\t\t\t} else {\n\t\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));\n\t\t\t}\n\t\t}\n\t\telse if (cell->type == ID($demux))\n\t\t{\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_a.is_fully_zero()) {\n\t\t\t\tset(sig_y, Const(0, GetSize(sig_y)));\n\t\t\t} else {\n\t\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));\n\t\t\t}\n\t\t}\n\t\telse if (cell->type == ID($fa))\n\t\t{\n\t\t\tRTLIL::SigSpec sig_c = cell->getPort(ID::C);\n\t\t\tRTLIL::SigSpec sig_x = cell->getPort(ID::X);\n\t\t\tint width = GetSize(sig_c);\n\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_c, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tRTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width);\n\t\t\tRTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width);\n\n\t\t\tRTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width);\n\t\t\tRTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);\n\t\t\tRTLIL::Const val_x = const_or(t2, t3, false, false, width);\n\n\t\t\tfor (int i = 0; i < GetSize(val_y); i++)\n\t\t\t\tif (val_y[i] == RTLIL::Sx)\n\t\t\t\t\tval_x.bits()[i] = RTLIL::Sx;\n\n\t\t\tset(sig_y, val_y);\n\t\t\tset(sig_x, val_x);\n\t\t}\n\t\telse if (cell->type == ID($alu))\n\t\t{\n\t\t\tbool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool();\n\t\t\tbool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool();\n\n\t\t\tRTLIL::SigSpec sig_ci = cell->getPort(ID::CI);\n\t\t\tRTLIL::SigSpec sig_bi = cell->getPort(ID::BI);\n\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_ci, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_bi, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tRTLIL::SigSpec sig_x = cell->getPort(ID::X);\n\t\t\tRTLIL::SigSpec sig_co = cell->getPort(ID::CO);\n\n\t\t\tbool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());\n\t\t\tsig_a.extend_u0(GetSize(sig_y), signed_a);\n\t\t\tsig_b.extend_u0(GetSize(sig_y), signed_b);\n\n\t\t\tbool carry = sig_ci[0] == State::S1;\n\t\t\tbool b_inv = sig_bi[0] == State::S1;\n\n\t\t\tfor (int i = 0; i < GetSize(sig_y); i++)\n\t\t\t{\n\t\t\t\tRTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };\n\n\t\t\t\tif (!x_inputs.is_fully_def()) {\n\t\t\t\t\tset(sig_x[i], RTLIL::Sx);\n\t\t\t\t} else {\n\t\t\t\t\tbool bit_a = sig_a[i] == State::S1;\n\t\t\t\t\tbool bit_b = (sig_b[i] == State::S1) != b_inv;\n\t\t\t\t\tbool bit_x = bit_a != bit_b;\n\t\t\t\t\tset(sig_x[i], bit_x ? State::S1 : State::S0);\n\t\t\t\t}\n\n\t\t\t\tif (any_input_undef) {\n\t\t\t\t\tset(sig_y[i], RTLIL::Sx);\n\t\t\t\t\tset(sig_co[i], RTLIL::Sx);\n\t\t\t\t} else {\n\t\t\t\t\tbool bit_a = sig_a[i] == State::S1;\n\t\t\t\t\tbool bit_b = (sig_b[i] == State::S1) != b_inv;\n\t\t\t\t\tbool bit_y = (bit_a != bit_b) != carry;\n\t\t\t\t\tcarry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry);\n\t\t\t\t\tset(sig_y[i], bit_y ? State::S1 : State::S0);\n\t\t\t\t\tset(sig_co[i], carry ? State::S1 : State::S0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (cell->type.in(ID($macc), ID($macc_v2)))\n\t\t{\n\t\t\tMacc macc;\n\t\t\tmacc.from_cell(cell);\n\n\t\t\tfor (auto &port : macc.terms) {\n\t\t\t\tif (!eval(port.in_a, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tif (!eval(port.in_b, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tRTLIL::Const result(0, GetSize(cell->getPort(ID::Y)));\n\t\t\tif (!macc.eval(result))\n\t\t\t\tlog_abort();\n\n\t\t\tset(cell->getPort(ID::Y), result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRTLIL::SigSpec sig_c, sig_d;\n\n\t\t\tif (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) {\n\t\t\t\tif (cell->hasPort(ID::C))\n\t\t\t\t\tsig_c = cell->getPort(ID::C);\n\t\t\t\tif (cell->hasPort(ID::D))\n\t\t\t\t\tsig_d = cell->getPort(ID::D);\n\t\t\t}\n\n\t\t\tif (sig_a.size() > 0 && !eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_b.size() > 0 && !eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_c.size() > 0 && !eval(sig_c, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_d.size() > 0 && !eval(sig_d, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tbool eval_err = false;\n\t\t\tRTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);\n\n\t\t\tif (eval_err)\n\t\t\t\treturn false;\n\n\t\t\tset(sig_y, eval_ret);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL)\n\t{\n\t\tassign_map.apply(sig);\n\t\tvalues_map.apply(sig);\n\n\t\tif (sig.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (stop_signals.check_any(sig)) {\n\t\t\tundef = stop_signals.extract(sig);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (busy_cell) {\n\t\t\tif (busy.count(busy_cell) > 0) {\n\t\t\t\tundef = sig;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tbusy.insert(busy_cell);\n\t\t}\n\n\t\tstd::set<RTLIL::Cell*> driver_cells;\n\t\tsig2driver.find(sig, driver_cells);\n\t\tfor (auto cell : driver_cells) {\n\t\t\tif (!eval(cell, undef)) {\n\t\t\t\tif (busy_cell)\n\t\t\t\t\tbusy.erase(busy_cell);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tif (busy_cell)\n\t\t\tbusy.erase(busy_cell);\n\n\t\tvalues_map.apply(sig);\n\t\tif (sig.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (defaultval != RTLIL::State::Sm) {\n\t\t\tfor (auto &bit : sig)\n\t\t\t\tif (bit.wire) bit = defaultval;\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (auto &c : sig.chunks())\n\t\t\tif (c.wire != NULL)\n\t\t\t\tundef.append(c);\n\t\treturn false;\n\t}\n\n\tbool eval(RTLIL::SigSpec &sig)\n\t{\n\t\tRTLIL::SigSpec undef;\n\t\treturn eval(sig, undef);\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
166
|
+
"celltypes.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CELLTYPES_H\n#define CELLTYPES_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct CellType\n{\n\tRTLIL::IdString type;\n\tpool<RTLIL::IdString> inputs, outputs;\n\tbool is_evaluable;\n\tbool is_combinatorial;\n\tbool is_synthesizable;\n};\n\nstruct CellTypes\n{\n\tdict<RTLIL::IdString, CellType> cell_types;\n\n\tCellTypes()\n\t{\n\t}\n\n\tCellTypes(RTLIL::Design *design)\n\t{\n\t\tsetup(design);\n\t}\n\n\tvoid setup(RTLIL::Design *design = NULL)\n\t{\n\t\tif (design)\n\t\t\tsetup_design(design);\n\n\t\tsetup_internals();\n\t\tsetup_internals_mem();\n\t\tsetup_internals_anyinit();\n\t\tsetup_stdcells();\n\t\tsetup_stdcells_mem();\n\t}\n\n\tvoid setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false, bool is_combinatorial = false, bool is_synthesizable = false)\n\t{\n\t\tCellType ct = {type, inputs, outputs, is_evaluable, is_combinatorial, is_synthesizable};\n\t\tcell_types[ct.type] = ct;\n\t}\n\n\tvoid setup_module(RTLIL::Module *module)\n\t{\n\t\tpool<RTLIL::IdString> inputs, outputs;\n\t\tfor (RTLIL::IdString wire_name : module->ports) {\n\t\t\tRTLIL::Wire *wire = module->wire(wire_name);\n\t\t\tif (wire->port_input)\n\t\t\t\tinputs.insert(wire->name);\n\t\t\tif (wire->port_output)\n\t\t\t\toutputs.insert(wire->name);\n\t\t}\n\t\tsetup_type(module->name, inputs, outputs);\n\t}\n\n\tvoid setup_design(RTLIL::Design *design)\n\t{\n\t\tfor (auto module : design->modules())\n\t\t\tsetup_module(module);\n\t}\n\n\tvoid setup_internals()\n\t{\n\t\tsetup_internals_eval();\n\n\t\tsetup_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, true);\n\n\t\tsetup_type(ID($assert), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($assume), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($live), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($fair), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($cover), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($initstate), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($anyconst), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($anyseq), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($allconst), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($allseq), pool<RTLIL::IdString>(), {ID::Y}, true);\n\t\tsetup_type(ID($equiv), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool<RTLIL::IdString>(), true);\n\t\tsetup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($check), {ID::A, ID::EN, ID::ARGS, ID::TRG}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y});\n\t\tsetup_type(ID($get_tag), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($original_tag), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($future_ff), {ID::A}, {ID::Y});\n\t\tsetup_type(ID($scopeinfo), {}, {});\n\t}\n\n\tvoid setup_internals_eval()\n\t{\n\t\tstd::vector<RTLIL::IdString> unary_ops = {\n\t\t\tID($not), ID($pos), ID($buf), ID($neg),\n\t\t\tID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),\n\t\t\tID($logic_not), ID($slice), ID($lut), ID($sop)\n\t\t};\n\n\t\tstd::vector<RTLIL::IdString> binary_ops = {\n\t\t\tID($and), ID($or), ID($xor), ID($xnor),\n\t\t\tID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),\n\t\t\tID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),\n\t\t\tID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),\n\t\t\tID($logic_and), ID($logic_or), ID($concat), ID($macc),\n\t\t\tID($bweqx)\n\t\t};\n\n\t\tfor (auto type : unary_ops)\n\t\t\tsetup_type(type, {ID::A}, {ID::Y}, true);\n\n\t\tfor (auto type : binary_ops)\n\t\t\tsetup_type(type, {ID::A, ID::B}, {ID::Y}, true);\n\n\t\tfor (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux), ID($bwmux)}))\n\t\t\tsetup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\n\t\tfor (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))\n\t\t\tsetup_type(type, {ID::A, ID::S}, {ID::Y}, true);\n\n\t\tsetup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);\n\t\tsetup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);\n\t\tsetup_type(ID($macc_v2), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);\n\t}\n\n\tvoid setup_internals_ff()\n\t{\n\t\tsetup_type(ID($sr), {ID::SET, ID::CLR}, {ID::Q});\n\t\tsetup_type(ID($ff), {ID::D}, {ID::Q});\n\t\tsetup_type(ID($dff), {ID::CLK, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q});\n\t\tsetup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q});\n\t\tsetup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($aldff), {ID::CLK, ID::ALOAD, ID::AD, ID::D}, {ID::Q});\n\t\tsetup_type(ID($aldffe), {ID::CLK, ID::ALOAD, ID::AD, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q});\n\t\tsetup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q});\n\t\tsetup_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q});\n\t\tsetup_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q});\n\t\tsetup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});\n\t}\n\n\tvoid setup_internals_anyinit()\n\t{\n\t\tsetup_type(ID($anyinit), {ID::D}, {ID::Q});\n\t}\n\n\tvoid setup_internals_mem()\n\t{\n\t\tsetup_internals_ff();\n\n\t\tsetup_type(ID($memrd), {ID::CLK, ID::EN, ID::ADDR}, {ID::DATA});\n\t\tsetup_type(ID($memrd_v2), {ID::CLK, ID::EN, ID::ARST, ID::SRST, ID::ADDR}, {ID::DATA});\n\t\tsetup_type(ID($memwr), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($memwr_v2), {ID::CLK, ID::EN, ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($meminit), {ID::ADDR, ID::DATA}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($meminit_v2), {ID::ADDR, ID::DATA, ID::EN}, pool<RTLIL::IdString>());\n\t\tsetup_type(ID($mem), {ID::RD_CLK, ID::RD_EN, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});\n\t\tsetup_type(ID($mem_v2), {ID::RD_CLK, ID::RD_EN, ID::RD_ARST, ID::RD_SRST, ID::RD_ADDR, ID::WR_CLK, ID::WR_EN, ID::WR_ADDR, ID::WR_DATA}, {ID::RD_DATA});\n\n\t\tsetup_type(ID($fsm), {ID::CLK, ID::ARST, ID::CTRL_IN}, {ID::CTRL_OUT});\n\t}\n\n\tvoid setup_stdcells()\n\t{\n\t\tsetup_stdcells_eval();\n\n\t\tsetup_type(ID($_TBUF_), {ID::A, ID::E}, {ID::Y}, true);\n\t}\n\n\tvoid setup_stdcells_eval()\n\t{\n\t\tsetup_type(ID($_BUF_), {ID::A}, {ID::Y}, true);\n\t\tsetup_type(ID($_NOT_), {ID::A}, {ID::Y}, true);\n\t\tsetup_type(ID($_AND_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_NAND_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_OR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_NOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_XOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_XNOR_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_ANDNOT_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_ORNOT_), {ID::A, ID::B}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\t\tsetup_type(ID($_NMUX_), {ID::A, ID::B, ID::S}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX4_), {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX8_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U}, {ID::Y}, true);\n\t\tsetup_type(ID($_MUX16_), {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V}, {ID::Y}, true);\n\t\tsetup_type(ID($_AOI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($_OAI3_), {ID::A, ID::B, ID::C}, {ID::Y}, true);\n\t\tsetup_type(ID($_AOI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true);\n\t\tsetup_type(ID($_OAI4_), {ID::A, ID::B, ID::C, ID::D}, {ID::Y}, true);\n\t}\n\n\tvoid setup_stdcells_mem()\n\t{\n\t\tstd::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_SR_%c%c_\", c1, c2), {ID::S, ID::R}, {ID::Q});\n\n\t\tsetup_type(ID($_FF_), {ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFF_%c_\", c1), {ID::C, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFE_%c%c_\", c1, c2), {ID::C, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_DFF_%c%c%c_\", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\t\tsetup_type(stringf(\"$_ALDFF_%c%c_\", c1, c2), {ID::C, ID::L, ID::AD, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_ALDFFE_%c%c%c_\", c1, c2, c3), {ID::C, ID::L, ID::AD, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFSR_%c%c%c_\", c1, c2, c3), {ID::C, ID::S, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_DFFSRE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::S, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_SDFF_%c%c%c_\", c1, c2, c3), {ID::C, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_SDFFE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\tfor (auto c4 : list_np)\n\t\t\tsetup_type(stringf(\"$_SDFFCE_%c%c%c%c_\", c1, c2, c3, c4), {ID::C, ID::R, ID::D, ID::E}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\t\tsetup_type(stringf(\"$_DLATCH_%c_\", c1), {ID::E, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_01)\n\t\t\tsetup_type(stringf(\"$_DLATCH_%c%c%c_\", c1, c2, c3), {ID::E, ID::R, ID::D}, {ID::Q});\n\n\t\tfor (auto c1 : list_np)\n\t\tfor (auto c2 : list_np)\n\t\tfor (auto c3 : list_np)\n\t\t\tsetup_type(stringf(\"$_DLATCHSR_%c%c%c_\", c1, c2, c3), {ID::E, ID::S, ID::R, ID::D}, {ID::Q});\n\t}\n\n\tvoid clear()\n\t{\n\t\tcell_types.clear();\n\t}\n\n\tbool cell_known(RTLIL::IdString type) const\n\t{\n\t\treturn cell_types.count(type) != 0;\n\t}\n\n\tbool cell_output(RTLIL::IdString type, RTLIL::IdString port) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.outputs.count(port) != 0;\n\t}\n\n\tbool cell_input(RTLIL::IdString type, RTLIL::IdString port) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.inputs.count(port) != 0;\n\t}\n\n\tbool cell_evaluable(RTLIL::IdString type) const\n\t{\n\t\tauto it = cell_types.find(type);\n\t\treturn it != cell_types.end() && it->second.is_evaluable;\n\t}\n\n\tstatic RTLIL::Const eval_not(RTLIL::Const v)\n\t{\n\t\tfor (auto &bit : v.bits())\n\t\t\tif (bit == State::S0) bit = State::S1;\n\t\t\telse if (bit == State::S1) bit = State::S0;\n\t\treturn v;\n\t}\n\n\t// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs\n\tstatic RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr)\n\t{\n\t\tif (type == ID($sshr) && !signed1)\n\t\t\ttype = ID($shr);\n\t\tif (type == ID($sshl) && !signed1)\n\t\t\ttype = ID($shl);\n\n\t\tif (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) &&\n\t\t\t\ttype != ID($pos) && type != ID($buf) && type != ID($neg) && type != ID($not)) {\n\t\t\tif (!signed1 || !signed2)\n\t\t\t\tsigned1 = false, signed2 = false;\n\t\t}\n\n#define HANDLE_CELL_TYPE(_t) if (type == ID($##_t)) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);\n\t\tHANDLE_CELL_TYPE(not)\n\t\tHANDLE_CELL_TYPE(and)\n\t\tHANDLE_CELL_TYPE(or)\n\t\tHANDLE_CELL_TYPE(xor)\n\t\tHANDLE_CELL_TYPE(xnor)\n\t\tHANDLE_CELL_TYPE(reduce_and)\n\t\tHANDLE_CELL_TYPE(reduce_or)\n\t\tHANDLE_CELL_TYPE(reduce_xor)\n\t\tHANDLE_CELL_TYPE(reduce_xnor)\n\t\tHANDLE_CELL_TYPE(reduce_bool)\n\t\tHANDLE_CELL_TYPE(logic_not)\n\t\tHANDLE_CELL_TYPE(logic_and)\n\t\tHANDLE_CELL_TYPE(logic_or)\n\t\tHANDLE_CELL_TYPE(shl)\n\t\tHANDLE_CELL_TYPE(shr)\n\t\tHANDLE_CELL_TYPE(sshl)\n\t\tHANDLE_CELL_TYPE(sshr)\n\t\tHANDLE_CELL_TYPE(shift)\n\t\tHANDLE_CELL_TYPE(shiftx)\n\t\tHANDLE_CELL_TYPE(lt)\n\t\tHANDLE_CELL_TYPE(le)\n\t\tHANDLE_CELL_TYPE(eq)\n\t\tHANDLE_CELL_TYPE(ne)\n\t\tHANDLE_CELL_TYPE(eqx)\n\t\tHANDLE_CELL_TYPE(nex)\n\t\tHANDLE_CELL_TYPE(ge)\n\t\tHANDLE_CELL_TYPE(gt)\n\t\tHANDLE_CELL_TYPE(add)\n\t\tHANDLE_CELL_TYPE(sub)\n\t\tHANDLE_CELL_TYPE(mul)\n\t\tHANDLE_CELL_TYPE(div)\n\t\tHANDLE_CELL_TYPE(mod)\n\t\tHANDLE_CELL_TYPE(divfloor)\n\t\tHANDLE_CELL_TYPE(modfloor)\n\t\tHANDLE_CELL_TYPE(pow)\n\t\tHANDLE_CELL_TYPE(pos)\n\t\tHANDLE_CELL_TYPE(neg)\n#undef HANDLE_CELL_TYPE\n\n\t\tif (type.in(ID($_BUF_), ID($buf)))\n\t\t\treturn arg1;\n\t\tif (type == ID($_NOT_))\n\t\t\treturn eval_not(arg1);\n\t\tif (type == ID($_AND_))\n\t\t\treturn const_and(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_NAND_))\n\t\t\treturn eval_not(const_and(arg1, arg2, false, false, 1));\n\t\tif (type == ID($_OR_))\n\t\t\treturn const_or(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_NOR_))\n\t\t\treturn eval_not(const_or(arg1, arg2, false, false, 1));\n\t\tif (type == ID($_XOR_))\n\t\t\treturn const_xor(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_XNOR_))\n\t\t\treturn const_xnor(arg1, arg2, false, false, 1);\n\t\tif (type == ID($_ANDNOT_))\n\t\t\treturn const_and(arg1, eval_not(arg2), false, false, 1);\n\t\tif (type == ID($_ORNOT_))\n\t\t\treturn const_or(arg1, eval_not(arg2), false, false, 1);\n\n\t\tif (errp != nullptr) {\n\t\t\t*errp = true;\n\t\t\treturn State::Sm;\n\t\t}\n\n\t\tlog_abort();\n\t}\n\n\t// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr)\n\t{\n\t\tif (cell->type == ID($slice)) {\n\t\t\tRTLIL::Const ret;\n\t\t\tint width = cell->parameters.at(ID::Y_WIDTH).as_int();\n\t\t\tint offset = cell->parameters.at(ID::OFFSET).as_int();\n\t\t\tret.bits().insert(ret.bits().end(), arg1.begin()+offset, arg1.begin()+offset+width);\n\t\t\treturn ret;\n\t\t}\n\n\t\tif (cell->type == ID($concat)) {\n\t\t\tRTLIL::Const ret = arg1;\n\t\t\tret.bits().insert(ret.bits().end(), arg2.begin(), arg2.end());\n\t\t\treturn ret;\n\t\t}\n\n\t\tif (cell->type == ID($bmux))\n\t\t{\n\t\t\treturn const_bmux(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($demux))\n\t\t{\n\t\t\treturn const_demux(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($bweqx))\n\t\t{\n\t\t\treturn const_bweqx(arg1, arg2);\n\t\t}\n\n\t\tif (cell->type == ID($lut))\n\t\t{\n\t\t\tint width = cell->parameters.at(ID::WIDTH).as_int();\n\n\t\t\tstd::vector<RTLIL::State> t = cell->parameters.at(ID::LUT).to_bits();\n\t\t\twhile (GetSize(t) < (1 << width))\n\t\t\t\tt.push_back(State::S0);\n\t\t\tt.resize(1 << width);\n\n\t\t\treturn const_bmux(t, arg1);\n\t\t}\n\n\t\tif (cell->type == ID($sop))\n\t\t{\n\t\t\tint width = cell->parameters.at(ID::WIDTH).as_int();\n\t\t\tint depth = cell->parameters.at(ID::DEPTH).as_int();\n\t\t\tstd::vector<RTLIL::State> t = cell->parameters.at(ID::TABLE).to_bits();\n\n\t\t\twhile (GetSize(t) < width*depth*2)\n\t\t\t\tt.push_back(State::S0);\n\n\t\t\tRTLIL::State default_ret = State::S0;\n\n\t\t\tfor (int i = 0; i < depth; i++)\n\t\t\t{\n\t\t\t\tbool match = true;\n\t\t\t\tbool match_x = true;\n\n\t\t\t\tfor (int j = 0; j < width; j++) {\n\t\t\t\t\tRTLIL::State a = arg1.at(j);\n\t\t\t\t\tif (t.at(2*width*i + 2*j + 0) == State::S1) {\n\t\t\t\t\t\tif (a == State::S1) match_x = false;\n\t\t\t\t\t\tif (a != State::S0) match = false;\n\t\t\t\t\t}\n\t\t\t\t\tif (t.at(2*width*i + 2*j + 1) == State::S1) {\n\t\t\t\t\t\tif (a == State::S0) match_x = false;\n\t\t\t\t\t\tif (a != State::S1) match = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (match)\n\t\t\t\t\treturn State::S1;\n\n\t\t\t\tif (match_x)\n\t\t\t\t\tdefault_ret = State::Sx;\n\t\t\t}\n\n\t\t\treturn default_ret;\n\t\t}\n\n\t\tbool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool();\n\t\tbool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool();\n\t\tint result_len = cell->parameters.count(ID::Y_WIDTH) > 0 ? cell->parameters[ID::Y_WIDTH].as_int() : -1;\n\t\treturn eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp);\n\t}\n\n\t// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)\n\t{\n\t\tif (cell->type.in(ID($mux), ID($_MUX_)))\n\t\t\treturn const_mux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($_NMUX_))\n\t\t\treturn eval_not(const_mux(arg1, arg2, arg3));\n\t\tif (cell->type == ID($bwmux))\n\t\t\treturn const_bwmux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($pmux))\n\t\t\treturn const_pmux(arg1, arg2, arg3);\n\t\tif (cell->type == ID($_AOI3_))\n\t\t\treturn eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));\n\t\tif (cell->type == ID($_OAI3_))\n\t\t\treturn eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1));\n\n\t\tlog_assert(arg3.size() == 0);\n\t\treturn eval(cell, arg1, arg2, errp);\n\t}\n\n\t// Consider using the ConstEval struct instead if you need named ports and/or multiple outputs\n\tstatic RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr)\n\t{\n\t\tif (cell->type == ID($_AOI4_))\n\t\t\treturn eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));\n\t\tif (cell->type == ID($_OAI4_))\n\t\t\treturn eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));\n\n\t\tlog_assert(arg4.size() == 0);\n\t\treturn eval(cell, arg1, arg2, arg3, errp);\n\t}\n};\n\n// initialized by yosys_setup()\nextern CellTypes yosys_celltypes;\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
167
|
+
"consteval.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef CONSTEVAL_H\n#define CONSTEVAL_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n#include \"kernel/macc.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct ConstEval\n{\n\tRTLIL::Module *module;\n\tSigMap assign_map;\n\tSigMap values_map;\n\tSigPool stop_signals;\n\tSigSet<RTLIL::Cell*> sig2driver;\n\tstd::set<RTLIL::Cell*> busy;\n\tstd::vector<SigMap> stack;\n\tRTLIL::State defaultval;\n\n\tConstEval(RTLIL::Module *module, RTLIL::State defaultval = RTLIL::State::Sm) : module(module), assign_map(module), defaultval(defaultval)\n\t{\n\t\tCellTypes ct;\n\t\tct.setup_internals();\n\t\tct.setup_stdcells();\n\n\t\tfor (auto &it : module->cells_) {\n\t\t\tif (!ct.cell_known(it.second->type))\n\t\t\t\tcontinue;\n\t\t\tfor (auto &it2 : it.second->connections())\n\t\t\t\tif (ct.cell_output(it.second->type, it2.first))\n\t\t\t\t\tsig2driver.insert(assign_map(it2.second), it.second);\n\t\t}\n\t}\n\n\tvoid clear()\n\t{\n\t\tvalues_map.clear();\n\t\tstop_signals.clear();\n\t}\n\n\tvoid push()\n\t{\n\t\tstack.push_back(values_map);\n\t}\n\n\tvoid pop()\n\t{\n\t\tvalues_map.swap(stack.back());\n\t\tstack.pop_back();\n\t}\n\n\tvoid set(RTLIL::SigSpec sig, RTLIL::Const value)\n\t{\n\t\tassign_map.apply(sig);\n#ifndef NDEBUG\n\t\tRTLIL::SigSpec current_val = values_map(sig);\n\t\tfor (int i = 0; i < GetSize(current_val); i++)\n\t\t\tlog_assert(current_val[i].wire != NULL || current_val[i] == value[i]);\n#endif\n\t\tvalues_map.add(sig, RTLIL::SigSpec(value));\n\t}\n\n\tvoid stop(RTLIL::SigSpec sig)\n\t{\n\t\tassign_map.apply(sig);\n\t\tstop_signals.add(sig);\n\t}\n\n\tbool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)\n\t{\n\t\tif (cell->type == ID($lcu))\n\t\t{\n\t\t\tRTLIL::SigSpec sig_p = cell->getPort(ID::P);\n\t\t\tRTLIL::SigSpec sig_g = cell->getPort(ID::G);\n\t\t\tRTLIL::SigSpec sig_ci = cell->getPort(ID::CI);\n\t\t\tRTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort(ID::CO)));\n\n\t\t\tif (sig_co.is_fully_const())\n\t\t\t\treturn true;\n\n\t\t\tif (!eval(sig_p, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_g, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_ci, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())\n\t\t\t{\n\t\t\t\tRTLIL::Const coval(RTLIL::Sx, GetSize(sig_co));\n\t\t\t\tbool carry = sig_ci.as_bool();\n\n\t\t\t\tfor (int i = 0; i < GetSize(coval); i++) {\n\t\t\t\t\tcarry = (sig_g[i] == State::S1) || (sig_p[i] == RTLIL::S1 && carry);\n\t\t\t\t\tcoval.bits()[i] = carry ? State::S1 : State::S0;\n\t\t\t\t}\n\n\t\t\t\tset(sig_co, coval);\n\t\t\t}\n\t\t\telse\n\t\t\t\tset(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co)));\n\n\t\t\treturn true;\n\t\t}\n\n\t\tRTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;\n\n\t\tlog_assert(cell->hasPort(ID::Y));\n\t\tsig_y = values_map(assign_map(cell->getPort(ID::Y)));\n\t\tif (sig_y.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (cell->hasPort(ID::S)) {\n\t\t\tsig_s = cell->getPort(ID::S);\n\t\t}\n\n\t\tif (cell->hasPort(ID::A))\n\t\t\tsig_a = cell->getPort(ID::A);\n\n\t\tif (cell->hasPort(ID::B))\n\t\t\tsig_b = cell->getPort(ID::B);\n\n\t\tif (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_)))\n\t\t{\n\t\t\tstd::vector<RTLIL::SigSpec> y_candidates;\n\t\t\tint count_set_s_bits = 0;\n\n\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tfor (int i = 0; i < sig_s.size(); i++)\n\t\t\t{\n\t\t\t\tRTLIL::State s_bit = sig_s.extract(i, 1).as_const().at(0);\n\t\t\t\tRTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size());\n\n\t\t\t\tif (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1)\n\t\t\t\t\ty_candidates.push_back(b_slice);\n\n\t\t\t\tif (s_bit == RTLIL::State::S1)\n\t\t\t\t\tcount_set_s_bits++;\n\t\t\t}\n\n\t\t\tif (count_set_s_bits == 0)\n\t\t\t\ty_candidates.push_back(sig_a);\n\n\t\t\tstd::vector<RTLIL::Const> y_values;\n\n\t\t\tlog_assert(y_candidates.size() > 0);\n\t\t\tfor (auto &yc : y_candidates) {\n\t\t\t\tif (!eval(yc, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tif (cell->type == ID($_NMUX_))\n\t\t\t\t\ty_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc)));\n\t\t\t\telse\n\t\t\t\t\ty_values.push_back(yc.as_const());\n\t\t\t}\n\n\t\t\tif (y_values.size() > 1)\n\t\t\t{\n\t\t\t\tstd::vector<RTLIL::State> master_bits = y_values.at(0).to_bits();\n\n\t\t\t\tfor (size_t i = 1; i < y_values.size(); i++) {\n\t\t\t\t\tstd::vector<RTLIL::State> slave_bits = y_values.at(i).to_bits();\n\t\t\t\t\tlog_assert(master_bits.size() == slave_bits.size());\n\t\t\t\t\tfor (size_t j = 0; j < master_bits.size(); j++)\n\t\t\t\t\t\tif (master_bits[j] != slave_bits[j])\n\t\t\t\t\t\t\tmaster_bits[j] = RTLIL::State::Sx;\n\t\t\t\t}\n\n\t\t\t\tset(sig_y, RTLIL::Const(master_bits));\n\t\t\t}\n\t\t\telse\n\t\t\t\tset(sig_y, y_values.front());\n\t\t}\n\t\telse if (cell->type == ID($bmux))\n\t\t{\n\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (sig_s.is_fully_def()) {\n\t\t\t\tint sel = sig_s.as_int();\n\t\t\t\tint width = GetSize(sig_y);\n\t\t\t\tSigSpec res = sig_a.extract(sel * width, width);\n\t\t\t\tif (!eval(res, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, res.as_const());\n\t\t\t} else {\n\t\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));\n\t\t\t}\n\t\t}\n\t\telse if (cell->type == ID($demux))\n\t\t{\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_a.is_fully_zero()) {\n\t\t\t\tset(sig_y, Const(0, GetSize(sig_y)));\n\t\t\t} else {\n\t\t\t\tif (!eval(sig_s, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tset(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));\n\t\t\t}\n\t\t}\n\t\telse if (cell->type == ID($fa))\n\t\t{\n\t\t\tRTLIL::SigSpec sig_c = cell->getPort(ID::C);\n\t\t\tRTLIL::SigSpec sig_x = cell->getPort(ID::X);\n\t\t\tint width = GetSize(sig_c);\n\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_c, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tRTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width);\n\t\t\tRTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width);\n\n\t\t\tRTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width);\n\t\t\tRTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);\n\t\t\tRTLIL::Const val_x = const_or(t2, t3, false, false, width);\n\n\t\t\tfor (int i = 0; i < GetSize(val_y); i++)\n\t\t\t\tif (val_y[i] == RTLIL::Sx)\n\t\t\t\t\tval_x.bits()[i] = RTLIL::Sx;\n\n\t\t\tset(sig_y, val_y);\n\t\t\tset(sig_x, val_x);\n\t\t}\n\t\telse if (cell->type == ID($alu))\n\t\t{\n\t\t\tbool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool();\n\t\t\tbool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool();\n\n\t\t\tRTLIL::SigSpec sig_ci = cell->getPort(ID::CI);\n\t\t\tRTLIL::SigSpec sig_bi = cell->getPort(ID::BI);\n\n\t\t\tif (!eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_ci, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tif (!eval(sig_bi, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tRTLIL::SigSpec sig_x = cell->getPort(ID::X);\n\t\t\tRTLIL::SigSpec sig_co = cell->getPort(ID::CO);\n\n\t\t\tbool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def());\n\t\t\tsig_a.extend_u0(GetSize(sig_y), signed_a);\n\t\t\tsig_b.extend_u0(GetSize(sig_y), signed_b);\n\n\t\t\tbool carry = sig_ci[0] == State::S1;\n\t\t\tbool b_inv = sig_bi[0] == State::S1;\n\n\t\t\tfor (int i = 0; i < GetSize(sig_y); i++)\n\t\t\t{\n\t\t\t\tRTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };\n\n\t\t\t\tif (!x_inputs.is_fully_def()) {\n\t\t\t\t\tset(sig_x[i], RTLIL::Sx);\n\t\t\t\t} else {\n\t\t\t\t\tbool bit_a = sig_a[i] == State::S1;\n\t\t\t\t\tbool bit_b = (sig_b[i] == State::S1) != b_inv;\n\t\t\t\t\tbool bit_x = bit_a != bit_b;\n\t\t\t\t\tset(sig_x[i], bit_x ? State::S1 : State::S0);\n\t\t\t\t}\n\n\t\t\t\tif (any_input_undef) {\n\t\t\t\t\tset(sig_y[i], RTLIL::Sx);\n\t\t\t\t\tset(sig_co[i], RTLIL::Sx);\n\t\t\t\t} else {\n\t\t\t\t\tbool bit_a = sig_a[i] == State::S1;\n\t\t\t\t\tbool bit_b = (sig_b[i] == State::S1) != b_inv;\n\t\t\t\t\tbool bit_y = (bit_a != bit_b) != carry;\n\t\t\t\t\tcarry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry);\n\t\t\t\t\tset(sig_y[i], bit_y ? State::S1 : State::S0);\n\t\t\t\t\tset(sig_co[i], carry ? State::S1 : State::S0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (cell->type.in(ID($macc), ID($macc_v2)))\n\t\t{\n\t\t\tMacc macc;\n\t\t\tmacc.from_cell(cell);\n\n\t\t\tfor (auto &port : macc.terms) {\n\t\t\t\tif (!eval(port.in_a, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t\tif (!eval(port.in_b, undef, cell))\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tRTLIL::Const result(0, GetSize(cell->getPort(ID::Y)));\n\t\t\tif (!macc.eval(result))\n\t\t\t\tlog_abort();\n\n\t\t\tset(cell->getPort(ID::Y), result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRTLIL::SigSpec sig_c, sig_d;\n\n\t\t\tif (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) {\n\t\t\t\tif (cell->hasPort(ID::C))\n\t\t\t\t\tsig_c = cell->getPort(ID::C);\n\t\t\t\tif (cell->hasPort(ID::D))\n\t\t\t\t\tsig_d = cell->getPort(ID::D);\n\t\t\t}\n\n\t\t\tif (sig_a.size() > 0 && !eval(sig_a, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_b.size() > 0 && !eval(sig_b, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_c.size() > 0 && !eval(sig_c, undef, cell))\n\t\t\t\treturn false;\n\t\t\tif (sig_d.size() > 0 && !eval(sig_d, undef, cell))\n\t\t\t\treturn false;\n\n\t\t\tbool eval_err = false;\n\t\t\tRTLIL::Const eval_ret;\n\t\t\tif (sig_s.size() > 0 && eval(sig_s, undef, cell)) {\n\t\t\t\teval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_s.as_const(), &eval_err);\n\t\t\t} else\n\t\t\t\teval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err);\n\n\t\t\tif (eval_err)\n\t\t\t\treturn false;\n\n\t\t\tset(sig_y, eval_ret);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL)\n\t{\n\t\tassign_map.apply(sig);\n\t\tvalues_map.apply(sig);\n\n\t\tif (sig.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (stop_signals.check_any(sig)) {\n\t\t\tundef = stop_signals.extract(sig);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (busy_cell) {\n\t\t\tif (busy.count(busy_cell) > 0) {\n\t\t\t\tundef = sig;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tbusy.insert(busy_cell);\n\t\t}\n\n\t\tstd::set<RTLIL::Cell*> driver_cells;\n\t\tsig2driver.find(sig, driver_cells);\n\t\tfor (auto cell : driver_cells) {\n\t\t\tif (!eval(cell, undef)) {\n\t\t\t\tif (busy_cell)\n\t\t\t\t\tbusy.erase(busy_cell);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tif (busy_cell)\n\t\t\tbusy.erase(busy_cell);\n\n\t\tvalues_map.apply(sig);\n\t\tif (sig.is_fully_const())\n\t\t\treturn true;\n\n\t\tif (defaultval != RTLIL::State::Sm) {\n\t\t\tfor (auto &bit : sig)\n\t\t\t\tif (bit.wire) bit = defaultval;\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (auto &c : sig.chunks())\n\t\t\tif (c.wire != NULL)\n\t\t\t\tundef.append(c);\n\t\treturn false;\n\t}\n\n\tbool eval(RTLIL::SigSpec &sig)\n\t{\n\t\tRTLIL::SigSpec undef;\n\t\treturn eval(sig, undef);\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
168
168
|
"constids.inc": "X(A)\nX(abc9_box)\nX(abc9_box_id)\nX(abc9_box_seq)\nX(abc9_bypass)\nX(abc9_carry)\nX(abc9_flop)\nX(abc9_keep)\nX(abc9_lut)\nX(abc9_mergeability)\nX(abc9_scc_id)\nX(abcgroup)\nX(ABITS)\nX(AD)\nX(ADDR)\nX(allconst)\nX(allseq)\nX(ALOAD)\nX(ALOAD_POLARITY)\nX(always_comb)\nX(always_ff)\nX(always_latch)\nX(anyconst)\nX(anyseq)\nX(ARGS)\nX(ARGS_WIDTH)\nX(ARST)\nX(ARST_POLARITY)\nX(ARST_VALUE)\nX(A_SIGNED)\nX(A_WIDTH)\nX(B)\nX(BI)\nX(BITS_USED)\nX(blackbox)\nX(B_SIGNED)\nX(bugpoint_keep)\nX(B_WIDTH)\nX(BYTE)\nX(C)\nX(cells_not_processed)\nX(CE_OVER_SRST)\nX(CFG_ABITS)\nX(CFG_DBITS)\nX(CFG_INIT)\nX(chain)\nX(CI)\nX(CLK)\nX(clkbuf_driver)\nX(clkbuf_inhibit)\nX(clkbuf_inv)\nX(clkbuf_sink)\nX(CLK_ENABLE)\nX(CLK_POLARITY)\nX(CLR)\nX(CLR_POLARITY)\nX(CO)\nX(COLLISION_X_MASK)\nX(CONFIG)\nX(CONFIG_WIDTH)\nX(CTRL_IN)\nX(CTRL_IN_WIDTH)\nX(CTRL_OUT)\nX(CTRL_OUT_WIDTH)\nX(D)\nX(DAT)\nX(DATA)\nX(DAT_DST_PEN)\nX(DAT_DST_POL)\nX(defaultvalue)\nX(DELAY)\nX(DEPTH)\nX(DST)\nX(DST_EN)\nX(DST_PEN)\nX(DST_POL)\nX(DST_WIDTH)\nX(dynports)\nX(E)\nX(EDGE_EN)\nX(EDGE_POL)\nX(EN)\nX(EN_DST)\nX(EN_POLARITY)\nX(EN_SRC)\nX(enum_base_type)\nX(enum_type)\nX(equiv_merged)\nX(equiv_region)\nX(extract_order)\nX(F)\nX(FLAVOR)\nX(FORMAT)\nX(force_downto)\nX(force_upto)\nX(fsm_encoding)\nX(fsm_export)\nX(FULL)\nX(full_case)\nX(G)\nX(gclk)\nX(gentb_clock)\nX(gentb_constant)\nX(gentb_skip)\nX(H)\nX(hdlname)\nX(hierconn)\nX(I)\nX(INIT)\nX(INIT_VALUE)\nX(init)\nX(initial_top)\nX(interface_modport)\nX(interfaces_replaced_in_module)\nX(interface_type)\nX(invertible_pin)\nX(iopad_external_pin)\nX(is_interface)\nX(J)\nX(K)\nX(keep)\nX(keep_hierarchy)\nX(L)\nX(lib_whitebox)\nX(localparam)\nX(logic_block)\nX(lram)\nX(LUT)\nX(lut_keep)\nX(M)\nX(maximize)\nX(mem2reg)\nX(MEMID)\nX(minimize)\nX(module_not_derived)\nX(N)\nX(NAME)\nX(noblackbox)\nX(nolatches)\nX(nomem2init)\nX(nomem2reg)\nX(nomeminit)\nX(nosync)\nX(nowrshmsk)\nX(no_ram)\nX(no_rw_check)\nX(O)\nX(OFFSET)\nX(onehot)\nX(P)\nX(parallel_case)\nX(parameter)\nX(PORTID)\nX(PRIORITY)\nX(PRIORITY_MASK)\nX(promoted_if)\nX(Q)\nX(R)\nX(ram_block)\nX(ram_style)\nX(ramstyle)\nX(RD_ADDR)\nX(RD_ARST)\nX(RD_ARST_VALUE)\nX(RD_CE_OVER_SRST)\nX(RD_CLK)\nX(RD_CLK_ENABLE)\nX(RD_CLK_POLARITY)\nX(RD_COLLISION_X_MASK)\nX(RD_DATA)\nX(RD_EN)\nX(RD_INIT_VALUE)\nX(RD_PORTS)\nX(RD_SRST)\nX(RD_SRST_VALUE)\nX(RD_TRANSPARENCY_MASK)\nX(RD_TRANSPARENT)\nX(RD_WIDE_CONTINUATION)\nX(reg)\nX(replaced_by_gclk)\nX(reprocess_after)\nX(rom_block)\nX(rom_style)\nX(romstyle)\nX(S)\nX(SET)\nX(SET_POLARITY)\nX(single_bit_vector)\nX(SIZE)\nX(SRC)\nX(src)\nX(SRC_DST_PEN)\nX(SRC_DST_POL)\nX(SRC_EN)\nX(SRC_PEN)\nX(SRC_POL)\nX(SRC_WIDTH)\nX(SRST)\nX(SRST_POLARITY)\nX(SRST_VALUE)\nX(sta_arrival)\nX(STATE_BITS)\nX(STATE_NUM)\nX(STATE_NUM_LOG2)\nX(STATE_RST)\nX(STATE_TABLE)\nX(smtlib2_module)\nX(smtlib2_comb_expr)\nX(submod)\nX(syn_ramstyle)\nX(syn_romstyle)\nX(S_WIDTH)\nX(T)\nX(TABLE)\nX(TAG)\nX(techmap_autopurge)\nX(_TECHMAP_BITS_CONNMAP_)\nX(_TECHMAP_CELLNAME_)\nX(_TECHMAP_CELLTYPE_)\nX(techmap_celltype)\nX(_TECHMAP_FAIL_)\nX(techmap_maccmap)\nX(_TECHMAP_REPLACE_)\nX(techmap_simplemap)\nX(_techmap_special_)\nX(techmap_wrap)\nX(_TECHMAP_PLACEHOLDER_)\nX(techmap_chtype)\nX(T_FALL_MAX)\nX(T_FALL_MIN)\nX(T_FALL_TYP)\nX(T_LIMIT)\nX(T_LIMIT2)\nX(T_LIMIT2_MAX)\nX(T_LIMIT2_MIN)\nX(T_LIMIT2_TYP)\nX(T_LIMIT_MAX)\nX(T_LIMIT_MIN)\nX(T_LIMIT_TYP)\nX(to_delete)\nX(top)\nX(TRANS_NUM)\nX(TRANSPARENCY_MASK)\nX(TRANSPARENT)\nX(TRANS_TABLE)\nX(TRG)\nX(TRG_ENABLE)\nX(TRG_POLARITY)\nX(TRG_WIDTH)\nX(T_RISE_MAX)\nX(T_RISE_MIN)\nX(T_RISE_TYP)\nX(TYPE)\nX(U)\nX(unique)\nX(unused_bits)\nX(V)\nX(via_celltype)\nX(wand)\nX(whitebox)\nX(WIDTH)\nX(wildcard_port_conns)\nX(wiretype)\nX(wor)\nX(WORDS)\nX(WR_ADDR)\nX(WR_CLK)\nX(WR_CLK_ENABLE)\nX(WR_CLK_POLARITY)\nX(WR_DATA)\nX(WR_EN)\nX(WR_PORTS)\nX(WR_PRIORITY_MASK)\nX(WR_WIDE_CONTINUATION)\nX(X)\nX(xprop_decoder)\nX(Y)\nX(Y_WIDTH)\nX(area)\nX(capacitance)\nX(NPRODUCTS)\nX(NADDENDS)\nX(PRODUCT_NEGATED)\nX(ADDEND_NEGATED)\nX(A_WIDTHS)\nX(B_WIDTHS)\nX(C_WIDTHS)\nX(C_SIGNED)\nX(raise_error)\n",
|
|
169
169
|
"cost.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef COST_H\n#define COST_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct CellCosts\n{\n\n\tprivate:\n\tdict<RTLIL::IdString, int> mod_cost_cache_;\n\tDesign *design_ = nullptr;\n\n\tpublic:\n\tCellCosts(RTLIL::Design *design) : design_(design) { }\n\n\tstatic const dict<RTLIL::IdString, int>& default_gate_cost() {\n\t\t// Default size heuristics for several common PDK standard cells\n\t\t// used by abc and stat\n\t\tstatic const dict<RTLIL::IdString, int> db = {\n\t\t\t{ ID($_BUF_), 1 },\n\t\t\t{ ID($_NOT_), 2 },\n\t\t\t{ ID($_AND_), 4 },\n\t\t\t{ ID($_NAND_), 4 },\n\t\t\t{ ID($_OR_), 4 },\n\t\t\t{ ID($_NOR_), 4 },\n\t\t\t{ ID($_ANDNOT_), 4 },\n\t\t\t{ ID($_ORNOT_), 4 },\n\t\t\t{ ID($_XOR_), 5 },\n\t\t\t{ ID($_XNOR_), 5 },\n\t\t\t{ ID($_AOI3_), 6 },\n\t\t\t{ ID($_OAI3_), 6 },\n\t\t\t{ ID($_AOI4_), 7 },\n\t\t\t{ ID($_OAI4_), 7 },\n\t\t\t{ ID($_MUX_), 4 },\n\t\t\t{ ID($_NMUX_), 4 },\n\t\t};\n\t\treturn db;\n\t}\n\n\tstatic const dict<RTLIL::IdString, int>& cmos_gate_cost() {\n\t\t// Estimated CMOS transistor counts for several common PDK standard cells\n\t\t// used by stat and optionally by abc\n\t\tstatic const dict<RTLIL::IdString, int> db = {\n\t\t\t{ ID($_BUF_), 1 },\n\t\t\t{ ID($_NOT_), 2 },\n\t\t\t{ ID($_AND_), 6 },\n\t\t\t{ ID($_NAND_), 4 },\n\t\t\t{ ID($_OR_), 6 },\n\t\t\t{ ID($_NOR_), 4 },\n\t\t\t{ ID($_ANDNOT_), 6 },\n\t\t\t{ ID($_ORNOT_), 6 },\n\t\t\t{ ID($_XOR_), 12 },\n\t\t\t{ ID($_XNOR_), 12 },\n\t\t\t{ ID($_AOI3_), 6 },\n\t\t\t{ ID($_OAI3_), 6 },\n\t\t\t{ ID($_AOI4_), 8 },\n\t\t\t{ ID($_OAI4_), 8 },\n\t\t\t{ ID($_MUX_), 12 },\n\t\t\t{ ID($_NMUX_), 10 },\n\t\t\t{ ID($_DFF_P_), 16 },\n\t\t\t{ ID($_DFF_N_), 16 },\n\t\t};\n\t\treturn db;\n\t}\n\n\t// Get the cell cost for a cell based on its parameters.\n\t// This cost is an *approximate* upper bound for the number of gates that\n\t// the cell will get mapped to with \"opt -fast; techmap\"\n\t// The intended usage is for flattening heuristics and similar situations\n\tunsigned int get(RTLIL::Cell *cell);\n\t// Sum up the cell costs of all cells in the module\n\t// and all its submodules recursively\n\tunsigned int get(RTLIL::Module *mod);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
170
170
|
"drivertools.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2024 Jannis Harder <jix@yosyshq.com> <me@jix.one>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef DRIVERTOOLS_H\n#define DRIVERTOOLS_H\n\n#include <type_traits>\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// TODO move implementation into a .cc file\n\nstruct DriveBit;\n\nstruct DriveChunkWire;\nstruct DriveChunkPort;\nstruct DriveChunkMarker;\nstruct DriveChunk;\n\nstruct DriveSpec;\n\nconst char *log_signal(DriveChunkWire const &chunk);\nconst char *log_signal(DriveChunkPort const &chunk);\nconst char *log_signal(DriveChunkMarker const &chunk);\nconst char *log_signal(DriveChunk const &chunk);\nconst char *log_signal(DriveSpec const &chunk);\n\nenum class DriveType : unsigned char\n{\n\tNONE,\n\tCONSTANT,\n\tWIRE,\n\tPORT,\n\tMULTIPLE,\n\tMARKER,\n};\n\nstruct DriveBitWire\n{\n\tWire *wire;\n\tint offset;\n\n\tDriveBitWire(Wire *wire, int offset) : wire(wire), offset(offset) {}\n\n\tbool operator==(const DriveBitWire &other) const\n\t{\n\t\treturn wire == other.wire && offset == other.offset;\n\t}\n\n\tbool operator<(const DriveBitWire &other) const\n\t{\n\t\tif (wire != other.wire)\n\t\t\treturn wire->name < other.wire->name;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n\n\toperator SigBit() const\n\t{\n\t\treturn SigBit(wire, offset);\n\t}\n};\n\nstruct DriveBitPort\n{\n\tCell *cell;\n\tIdString port;\n\tint offset;\n\n\tDriveBitPort(Cell *cell, IdString port, int offset) : cell(cell), port(port), offset(offset) {}\n\n\tbool operator==(const DriveBitPort &other) const\n\t{\n\t\treturn cell == other.cell && port == other.port && offset == other.offset;\n\t}\n\n\tbool operator<(const DriveBitPort &other) const\n\t{\n\t\tif (cell != other.cell)\n\t\t\treturn cell->name < other.cell->name;\n\t\tif (port != other.port)\n\t\t\treturn port < other.port;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n};\n\n\nstruct DriveBitMarker\n{\n\tint marker;\n\tint offset;\n\n\tDriveBitMarker(int marker, int offset) : marker(marker), offset(offset) {}\n\n\tbool operator==(const DriveBitMarker &other) const\n\t{\n\t\treturn marker == other.marker && offset == other.offset;\n\t}\n\n\tbool operator<(const DriveBitMarker &other) const\n\t{\n\t\tif (marker != other.marker)\n\t\t\treturn marker < other.marker;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n};\n\nstruct DriveBitMultiple\n{\nprivate:\n\tpool<DriveBit> multiple_;\n\npublic:\n\tDriveBitMultiple();\n\tDriveBitMultiple(DriveBit const &single);\n\n\tpool<DriveBit> const &multiple() const { return multiple_; }\n\n\tvoid merge(DriveBitMultiple const &other)\n\t{\n\t\tfor (DriveBit const &single : other.multiple_)\n\t\t\tmerge(single);\n\t}\n\n\tvoid merge(DriveBitMultiple &&other)\n\t{\n\t\tfor (DriveBit &single : other.multiple_)\n\t\t\tmerge(std::move(single));\n\t}\n\n\tvoid merge(DriveBit const &single);\n\tvoid merge(DriveBit &&single);\n\n\tbool operator==(const DriveBitMultiple &other) const\n\t{\n\t\treturn multiple_ == other.multiple_;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\nstruct DriveBit\n{\nprivate:\n\tDriveType type_ = DriveType::NONE;\n\tunion\n\t{\n\t\tState constant_;\n\t\tDriveBitWire wire_;\n\t\tDriveBitPort port_;\n\t\tDriveBitMarker marker_;\n\t\tDriveBitMultiple multiple_;\n\t};\npublic:\n\tDriveBit() {}\n\n\tDriveBit(SigBit const &bit);\n\n\tDriveBit(DriveBit const &other) { *this = other; }\n\tDriveBit(DriveBit &&other) { *this = other; }\n\n\n\tDriveBit(State constant) { *this = constant; }\n\tDriveBit(DriveBitWire const &wire) { *this = wire; }\n\tDriveBit(DriveBitWire &&wire) { *this = wire; }\n\tDriveBit(DriveBitPort const &port) { *this = port; }\n\tDriveBit(DriveBitPort &&port) { *this = port; }\n\tDriveBit(DriveBitMarker const &marker) { *this = marker; }\n\tDriveBit(DriveBitMarker &&marker) { *this = marker; }\n\tDriveBit(DriveBitMultiple const &multiple) { *this = multiple; }\n\tDriveBit(DriveBitMultiple &&multiple) { *this = multiple; }\n\n\t~DriveBit() { set_none(); }\n\n\tvoid set_none()\n\t{\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\twire_.~DriveBitWire();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\tport_.~DriveBitPort();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\tmarker_.~DriveBitMarker();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\tmultiple_.~DriveBitMultiple();\n\t\t\t\tbreak;\n\t\t}\n\t\ttype_ = DriveType::NONE;\n\t}\n\n\tDriveBit &operator=(DriveBit const &other)\n\t{\n\t\tswitch (other.type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tset_none();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\t*this = other.constant_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\t*this = other.wire_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\t*this = other.port_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\t*this = other.marker_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\t*this = other.multiple_;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBit &&other)\n\t{\n\t\tswitch (other.type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tset_none();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\t*this = std::move(other.constant_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\t*this = std::move(other.wire_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\t*this = std::move(other.port_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\t*this = std::move(other.marker_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\t*this = std::move(other.multiple_);\n\t\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(State constant)\n\t{\n\t\tset_none();\n\t\tconstant_ = constant;\n\t\ttype_ = DriveType::CONSTANT;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitWire const &wire)\n\t{\n\t\tset_none();\n\t\tnew (&wire_) DriveBitWire(wire);\n\t\ttype_ = DriveType::WIRE;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitWire &&wire)\n\t{\n\t\tset_none();\n\t\tnew (&wire_) DriveBitWire(wire);\n\t\ttype_ = DriveType::WIRE;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitPort const &port)\n\t{\n\t\tset_none();\n\t\tnew (&port_) DriveBitPort(port);\n\t\ttype_ = DriveType::PORT;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitPort &&port)\n\t{\n\t\tset_none();\n\t\tnew (&port_) DriveBitPort(port);\n\t\ttype_ = DriveType::PORT;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitMarker const &marker)\n\t{\n\t\tset_none();\n\t\tnew (&marker_) DriveBitMarker(marker);\n\t\ttype_ = DriveType::MARKER;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitMarker &&marker)\n\t{\n\t\tset_none();\n\t\tnew (&marker_) DriveBitMarker(marker);\n\t\ttype_ = DriveType::MARKER;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitMultiple const &multiple)\n\t{\n\t\tset_none();\n\t\tif (multiple.multiple().empty())\n\t\t\treturn *this;\n\t\tnew (&multiple_) DriveBitMultiple(multiple);\n\t\ttype_ = DriveType::MULTIPLE;\n\t\treturn *this;\n\t}\n\n\tDriveBit &operator=(DriveBitMultiple &&multiple)\n\t{\n\t\tset_none();\n\t\tif (multiple.multiple().empty())\n\t\t\treturn *this;\n\t\tnew (&multiple_) DriveBitMultiple(multiple);\n\t\ttype_ = DriveType::MULTIPLE;\n\t\treturn *this;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n\tbool operator==(const DriveBit &other) const\n\t{\n\t\tif (type_ != other.type_)\n\t\t\treturn false;\n\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn true;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_ == other.constant_;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_ == other.wire_;\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_ == other.port_;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_ == other.marker_;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\treturn multiple_ == other.multiple_;\n\t\t}\n\t\tlog_abort();\n\t}\n\n\tbool operator!=(const DriveBit &other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n\n\tbool operator<(const DriveBit &other) const\n\t{\n\t\tif (type_ != other.type_)\n\t\t\treturn type_ < other.type_;\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn false;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_ < other.constant_;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_ < other.wire_;\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_ < other.port_;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_ < other.marker_;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\tlog_assert(!\"TODO\");\n\t\t}\n\t\tlog_abort();\n\t}\n\n\n\tDriveType type() const { return type_; }\n\n\tbool is_none() const { return type_ == DriveType::NONE; }\n\tbool is_constant() const { return type_ == DriveType::CONSTANT; }\n\tbool is_wire() const { return type_ == DriveType::WIRE; }\n\tbool is_port() const { return type_ == DriveType::PORT; }\n\tbool is_marker() const { return type_ == DriveType::MARKER; }\n\tbool is_multiple() const { return type_ == DriveType::MULTIPLE; }\n\n\tState &constant() { log_assert(is_constant()); return constant_; }\n\tState const &constant() const { log_assert(is_constant()); return constant_; }\n\tDriveBitWire &wire() { log_assert(is_wire()); return wire_; }\n\tDriveBitWire const &wire() const { log_assert(is_wire()); return wire_; }\n\tDriveBitPort &port() { log_assert(is_port()); return port_; }\n\tDriveBitPort const &port() const { log_assert(is_port()); return port_; }\n\tDriveBitMarker &marker() { log_assert(is_marker()); return marker_; }\n\tDriveBitMarker const &marker() const { log_assert(is_marker()); return marker_; }\n\tDriveBitMultiple &multiple() { log_assert(is_multiple()); return multiple_; }\n\tDriveBitMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; }\n\n\tvoid merge(DriveBit const &other);\n\n};\n\ninline DriveBitMultiple::DriveBitMultiple() {}\ninline DriveBitMultiple::DriveBitMultiple(DriveBit const &single)\n{\n\tmultiple_.emplace(single);\n}\n\nstruct DriveChunkWire\n{\n\tWire *wire;\n\tint offset;\n\tint width;\n\n\tDriveChunkWire(Wire *wire, int offset, int width) : wire(wire), offset(offset), width(width) {}\n\tDriveChunkWire(DriveBitWire const &bit) : wire(bit.wire), offset(bit.offset), width(1) {}\n\n\tint size() const { return width; }\n\n\tDriveBitWire operator[](int i) const\n\t{\n\t\tlog_assert(i >= 0 && i < width);\n\t\treturn DriveBitWire(wire, offset + i);\n\t}\n\n\tbool can_append(DriveBitWire const &bit) const;\n\tbool try_append(DriveBitWire const &bit);\n\tbool try_append(DriveChunkWire const &chunk);\n\n\t// Whether this chunk is a whole wire\n\tbool is_whole() const { return offset == 0 && width == wire->width; }\n\n\tbool operator==(const DriveChunkWire &other) const\n\t{\n\t\treturn wire == other.wire && offset == other.offset && width == other.width;\n\t}\n\n\tbool operator<(const DriveChunkWire &other) const\n\t{\n\t\tif (wire != other.wire)\n\t\t\treturn wire->name < other.wire->name;\n\t\tif (width != other.width)\n\t\t\treturn width < other.width;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n\texplicit operator SigChunk() const\n\t{\n\t\treturn SigChunk(wire, offset, width);\n\t}\n};\n\nstruct DriveChunkPort\n{\n\tCell *cell;\n\tIdString port;\n\tint offset;\n\tint width;\n\n\tDriveChunkPort(Cell *cell, IdString port, int offset, int width) :\n\t\tcell(cell), port(port), offset(offset), width(width) { }\n\tDriveChunkPort(Cell *cell, IdString port) :\n\t\tcell(cell), port(port), offset(0), width(GetSize(cell->connections().at(port))) { }\n\tDriveChunkPort(Cell *cell, std::pair<IdString, SigSpec> const &conn) :\n\t\tcell(cell), port(conn.first), offset(0), width(GetSize(conn.second)) { }\n\tDriveChunkPort(DriveBitPort const &bit) :\n\t\tcell(bit.cell), port(bit.port), offset(bit.offset), width(1) { }\n\n\tint size() const { return width; }\n\n\tDriveBitPort operator[](int i) const\n\t{\n\t\tlog_assert(i >= 0 && i < width);\n\t\treturn DriveBitPort(cell, port, offset + i);\n\t}\n\n\tbool can_append(DriveBitPort const &bit) const;\n\tbool try_append(DriveBitPort const &bit);\n\tbool try_append(DriveChunkPort const &chunk);\n\n\t// Whether this chunk is a whole port\n\tbool is_whole() const\n\t{\n\t\treturn offset == 0 && width == cell->connections().at(port).size();\n\t}\n\n\tbool operator==(const DriveChunkPort &other) const\n\t{\n\t\treturn cell == other.cell && port == other.port && offset == other.offset && width == other.width;\n\t}\n\n\tbool operator<(const DriveChunkPort &other) const\n\t{\n\t\tif (cell != other.cell)\n\t\t\treturn cell->name < other.cell->name;\n\t\tif (port != other.port)\n\t\t\treturn port < other.port;\n\t\tif (width != other.width)\n\t\t\treturn width < other.width;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\n\nstruct DriveChunkMarker\n{\n\tint marker;\n\tint offset;\n\tint width;\n\n\tDriveChunkMarker(int marker, int offset, int width) :\n\t\tmarker(marker), offset(offset), width(width) {}\n\tDriveChunkMarker(DriveBitMarker const &bit) :\n\t\tmarker(bit.marker), offset(bit.offset), width(1) {}\n\n\tint size() const { return width; }\n\n\tDriveBitMarker operator[](int i) const\n\t{\n\t\tlog_assert(i >= 0 && i < width);\n\t\treturn DriveBitMarker(marker, offset + i);\n\t}\n\n\tbool can_append(DriveBitMarker const &bit) const;\n\tbool try_append(DriveBitMarker const &bit);\n\tbool try_append(DriveChunkMarker const &chunk);\n\n\tbool operator==(const DriveChunkMarker &other) const\n\t{\n\t\treturn marker == other.marker && offset == other.offset && width == other.width;\n\t}\n\n\tbool operator<(const DriveChunkMarker &other) const\n\t{\n\t\tif (marker != other.marker)\n\t\t\treturn marker < other.marker;\n\t\tif (width != other.width)\n\t\t\treturn width < other.width;\n\t\treturn offset < other.offset;\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\nstruct DriveChunkMultiple\n{\nprivate:\n\tmutable pool<DriveChunk> multiple_;\n\tint width_;\n\npublic:\n\tpool<DriveChunk> const &multiple() const { return multiple_; }\n\n\tDriveChunkMultiple(DriveBitMultiple const &bit);\n\n\tint size() const { return width_; }\n\n\tDriveBitMultiple operator[](int i) const;\n\n\tbool can_append(DriveBitMultiple const &bit) const;\n\n\tbool try_append(DriveBitMultiple const &bit);\n\n\n\tbool can_append(DriveChunkMultiple const &bit) const;\n\n\tbool try_append(DriveChunkMultiple const &bit);\n\n\tbool operator==(const DriveChunkMultiple &other) const\n\t{\n\t\treturn width_ == other.width_ && multiple_ == other.multiple_;\n\t}\n\n\tbool operator<(const DriveChunkMultiple &other) const\n\t{\n\t\tif (multiple_.size() < other.multiple_.size())\n\n\t\tmultiple_.sort();\n\t\treturn false; // TODO implement, canonicalize order\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n};\n\nstruct DriveChunk\n{\nprivate:\n\tDriveType type_ = DriveType::NONE;\n\tunion\n\t{\n\t\tint none_;\n\t\tConst constant_;\n\t\tDriveChunkWire wire_;\n\t\tDriveChunkPort port_;\n\t\tDriveChunkMarker marker_;\n\t\tDriveChunkMultiple multiple_;\n\t};\n\npublic:\n\tDriveChunk() { set_none(); }\n\n\tDriveChunk(DriveChunk const &other) { *this = other; }\n\tDriveChunk(DriveChunk &&other) { *this = other; }\n\n\tDriveChunk(DriveBit const &other) { *this = other; }\n\n\tDriveChunk(Const const &constant) { *this = constant; }\n\tDriveChunk(Const &&constant) { *this = constant; }\n\tDriveChunk(DriveChunkWire const &wire) { *this = wire; }\n\tDriveChunk(DriveChunkWire &&wire) { *this = wire; }\n\tDriveChunk(DriveChunkPort const &port) { *this = port; }\n\tDriveChunk(DriveChunkPort &&port) { *this = port; }\n\tDriveChunk(DriveChunkMarker const &marker) { *this = marker; }\n\tDriveChunk(DriveChunkMarker &&marker) { *this = marker; }\n\tDriveChunk(DriveChunkMultiple const &multiple) { *this = multiple; }\n\tDriveChunk(DriveChunkMultiple &&multiple) { *this = multiple; }\n\n\t~DriveChunk() { set_none(); }\n\n\tDriveBit operator[](int i) const\n\t{\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn DriveBit();\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_[i];\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_[i];\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_[i];\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_[i];\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\treturn multiple_[i];\n\t\t}\n\t\tlog_abort();\n\t}\n\n\tvoid set_none(int width = 0)\n\t{\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tnone_ = width;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\tconstant_.~Const();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\twire_.~DriveChunkWire();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\tport_.~DriveChunkPort();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\tmarker_.~DriveChunkMarker();\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\tmultiple_.~DriveChunkMultiple();\n\t\t\t\tbreak;\n\t\t}\n\t\ttype_ = DriveType::NONE;\n\t\tnone_ = width;\n\t}\n\n\tDriveChunk &operator=(DriveChunk const &other)\n\t{\n\t\tswitch (other.type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tset_none(other.none_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\t*this = other.constant_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\t*this = other.wire_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\t*this = other.port_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\t*this = other.marker_;\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\t*this = other.multiple_;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunk &&other)\n\t{\n\t\tswitch (other.type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tset_none(other.none_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\t*this = std::move(other.constant_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\t*this = std::move(other.wire_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\t*this = std::move(other.port_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\t*this = std::move(other.marker_);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\t*this = std::move(other.multiple_);\n\t\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(Const const &constant)\n\t{\n\t\tset_none();\n\t\tnew (&constant_) Const(constant);\n\t\ttype_ = DriveType::CONSTANT;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(Const &&constant)\n\t{\n\t\tset_none();\n\t\tnew (&constant_) Const(std::move(constant));\n\t\ttype_ = DriveType::CONSTANT;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkWire const &wire)\n\t{\n\t\tset_none();\n\t\tnew (&wire_) DriveChunkWire(wire);\n\t\ttype_ = DriveType::WIRE;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkWire &&wire)\n\t{\n\t\tset_none();\n\t\tnew (&wire_) DriveChunkWire(wire);\n\t\ttype_ = DriveType::WIRE;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkPort const &port)\n\t{\n\t\tset_none();\n\t\tnew (&port_) DriveChunkPort(port);\n\t\ttype_ = DriveType::PORT;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkPort &&port)\n\t{\n\t\tset_none();\n\t\tnew (&port_) DriveChunkPort(port);\n\t\ttype_ = DriveType::PORT;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkMarker const &marker)\n\t{\n\t\tset_none();\n\t\tnew (&marker_) DriveChunkMarker(marker);\n\t\ttype_ = DriveType::MARKER;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkMarker &&marker)\n\t{\n\t\tset_none();\n\t\tnew (&marker_) DriveChunkMarker(marker);\n\t\ttype_ = DriveType::MARKER;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkMultiple const &multiple)\n\t{\n\t\tset_none(multiple.size());\n\t\tif (multiple.multiple().empty())\n\t\t\treturn *this;\n\t\tnew (&multiple_) DriveChunkMultiple(multiple);\n\t\ttype_ = DriveType::MULTIPLE;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveChunkMultiple &&multiple)\n\t{\n\t\tset_none(multiple.size());\n\t\tif (multiple.multiple().empty())\n\t\t\treturn *this;\n\t\tnew (&multiple_) DriveChunkMultiple(multiple);\n\t\ttype_ = DriveType::MULTIPLE;\n\t\treturn *this;\n\t}\n\n\tDriveChunk &operator=(DriveBit const &other)\n\t{\n\t\tswitch (other.type())\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\tset_none(1);\n\t\t\t\tbreak;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\t*this = Const(other.constant());\n\t\t\t\tbreak;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\t*this = DriveChunkWire(other.wire());\n\t\t\t\tbreak;\n\t\t\tcase DriveType::PORT:\n\t\t\t\t*this = DriveChunkPort(other.port());\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\t*this = DriveChunkMarker(other.marker());\n\t\t\t\tbreak;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\t*this = DriveChunkMultiple(other.multiple());\n\t\t\t\tbreak;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tbool can_append(DriveBit const &bit) const;\n\tbool try_append(DriveBit const &bit);\n\tbool try_append(DriveChunk const &chunk);\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n\tbool operator==(const DriveChunk &other) const\n\t{\n\t\tif (type_ != other.type_)\n\t\t\treturn false;\n\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn true;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_ == other.constant_;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_ == other.wire_;\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_ == other.port_;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_ == other.marker_;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\treturn multiple_ == other.multiple_;\n\t\t}\n\t\tlog_abort();\n\t}\n\n\tbool operator!=(const DriveChunk &other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n\n\tbool operator<(const DriveChunk &other) const\n\t{\n\t\tif (type_ != other.type_)\n\t\t\treturn type_ < other.type_;\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn false;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_ < other.constant_;\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_ < other.wire_;\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_ < other.port_;\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_ < other.marker_;\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\treturn multiple_ < other.multiple_;\n\t\t}\n\t\tlog_abort();\n\t}\n\n\tDriveType type() const { return type_; }\n\n\tbool is_none() const { return type_ == DriveType::NONE; }\n\tbool is_constant() const { return type_ == DriveType::CONSTANT; }\n\tbool is_wire() const { return type_ == DriveType::WIRE; }\n\tbool is_port() const { return type_ == DriveType::PORT; }\n\tbool is_marker() const { return type_ == DriveType::MARKER; }\n\tbool is_multiple() const { return type_ == DriveType::MULTIPLE; }\n\n\tConst &constant() { log_assert(is_constant()); return constant_; }\n\tConst const &constant() const { log_assert(is_constant()); return constant_; }\n\tDriveChunkWire &wire() { log_assert(is_wire()); return wire_; }\n\tDriveChunkWire const &wire() const { log_assert(is_wire()); return wire_; }\n\tDriveChunkPort &port() { log_assert(is_port()); return port_; }\n\tDriveChunkPort const &port() const { log_assert(is_port()); return port_; }\n\tDriveChunkMarker &marker() { log_assert(is_marker()); return marker_; }\n\tDriveChunkMarker const &marker() const { log_assert(is_marker()); return marker_; }\n\tDriveChunkMultiple &multiple() { log_assert(is_multiple()); return multiple_; }\n\tDriveChunkMultiple const &multiple() const { log_assert(is_multiple()); return multiple_; }\n\n\n\tint size() const\n\t{\n\t\tswitch (type_)\n\t\t{\n\t\t\tcase DriveType::NONE:\n\t\t\t\treturn none_;\n\t\t\tcase DriveType::CONSTANT:\n\t\t\t\treturn constant_.size();\n\t\t\tcase DriveType::WIRE:\n\t\t\t\treturn wire_.size();\n\t\t\tcase DriveType::PORT:\n\t\t\t\treturn port_.size();\n\t\t\tcase DriveType::MARKER:\n\t\t\t\treturn marker_.size();\n\t\t\tcase DriveType::MULTIPLE:\n\t\t\t\treturn multiple_.size();\n\t\t}\n\t\tlog_abort();\n\t}\n};\n\ninline DriveChunkMultiple::DriveChunkMultiple(DriveBitMultiple const &bit)\n\t: width_(1)\n{\n\tfor (auto const &bit : bit.multiple())\n\t\tmultiple_.emplace(bit);\n}\n\nstruct DriveSpec\n{\nprivate:\n\tint width_ = 0;\n\tmutable std::vector<DriveChunk> chunks_;\n\tmutable std::vector<DriveBit> bits_;\n\tmutable unsigned int hash_ = 0;\npublic:\n\n\tinline bool packed() const {\n\t\treturn bits_.empty();\n\t}\n\n\tDriveSpec() {}\n\n\tDriveSpec(DriveChunk const &chunk) { *this = chunk; }\n\tDriveSpec(DriveChunkWire const &chunk) { *this = chunk; }\n\tDriveSpec(DriveChunkPort const &chunk) { *this = chunk; }\n\tDriveSpec(DriveChunkMarker const &chunk) { *this = chunk; }\n\tDriveSpec(DriveChunkMultiple const &chunk) { *this = chunk; }\n\n\tDriveSpec(DriveBit const &bit) { *this = bit; }\n\tDriveSpec(DriveBitWire const &bit) { *this = bit; }\n\tDriveSpec(DriveBitPort const &bit) { *this = bit; }\n\tDriveSpec(DriveBitMarker const &bit) { *this = bit; }\n\tDriveSpec(DriveBitMultiple const &bit) { *this = bit; }\n\n\tDriveSpec(std::vector<DriveChunk> const &chunks) : chunks_(chunks) { compute_width(); }\n\n\tDriveSpec(std::vector<DriveBit> const &bits)\n\t{\n\t\tfor (auto const &bit : bits)\n\t\t\tappend(bit);\n\t}\n\n\tDriveSpec(SigSpec const &sig)\n\t{\n\t\t// TODO: converting one chunk at a time would be faster\n\t\tfor (auto const &bit : sig.bits())\n\t\t\tappend(bit);\n\t}\n\n\tstd::vector<DriveChunk> const &chunks() const { pack(); return chunks_; }\n\tstd::vector<DriveBit> const &bits() const { unpack(); return bits_; }\n\n\tint size() const { return width_; }\n\n\tvoid append(DriveBit const &bit);\n\n\tvoid append(DriveChunk const &chunk);\n\n\tvoid pack() const;\n\n\tvoid unpack() const;\n\n\tDriveBit &operator[](int index)\n\t{\n\t\tlog_assert(index >= 0 && index < size());\n\t\tunpack();\n\t\treturn bits_[index];\n\t}\n\n\tconst DriveBit &operator[](int index) const\n\t{\n\t\tlog_assert(index >= 0 && index < size());\n\t\tunpack();\n\t\treturn bits_[index];\n\t}\n\n\tvoid clear()\n\t{\n\t\tchunks_.clear();\n\t\tbits_.clear();\n\t\twidth_ = 0;\n\t}\n\n\tDriveSpec &operator=(DriveChunk const &chunk)\n\t{\n\t\tchunks_.clear();\n\t\tbits_.clear();\n\t\tappend(chunk);\n\t\treturn *this;\n\t}\n\n\tDriveSpec &operator=(DriveChunkWire const &chunk) { return *this = DriveChunk(chunk); }\n\tDriveSpec &operator=(DriveChunkPort const &chunk) { return *this = DriveChunk(chunk); }\n\tDriveSpec &operator=(DriveChunkMarker const &chunk) { return *this = DriveChunk(chunk); }\n\tDriveSpec &operator=(DriveChunkMultiple const &chunk) { return *this = DriveChunk(chunk); }\n\n\tDriveSpec &operator=(DriveBit const &bit)\n\t{\n\t\tchunks_.clear();\n\t\tbits_.clear();\n\t\tappend(bit);\n\t\treturn *this;\n\t}\n\n\tDriveSpec &operator=(DriveBitWire const &bit) { return *this = DriveBit(bit); }\n\tDriveSpec &operator=(DriveBitPort const &bit) { return *this = DriveBit(bit); }\n\tDriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); }\n\tDriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); }\n\n\tvoid updhash() const {\n\t\tif (hash_ != 0)\n\t\t\treturn;\n\t\tpack();\n\t\thash_ = run_hash(chunks_);\n\t\thash_ |= (hash_ == 0);\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\n\tbool operator==(DriveSpec const &other) const {\n\t\tupdhash();\n\t\tother.updhash();\n\t\tif (size() != other.size() || hash_ != other.hash_)\n\t\t\treturn false;\n\t\treturn chunks() == other.chunks();\n\t}\n\nprivate:\n\tvoid compute_width();\n};\n\n\n\nstruct DriverMap\n{\n\tCellTypes celltypes;\n\n\tDriverMap() { celltypes.setup(); }\n\tDriverMap(Design *design) { celltypes.setup(); celltypes.setup_design(design); }\n\nprivate:\n\n\t// Internally we represent all DriveBits by mapping them to DriveBitIds\n\t// which use less memory and are cheaper to compare.\n\tstruct DriveBitId\n\t{\n\t\tint id = -1;\n\n\t\tDriveBitId() {};\n\n\t\tDriveBitId(int id) : id(id) { }\n\n\t\tbool operator==(const DriveBitId &other) const { return id == other.id; }\n\t\tbool operator!=(const DriveBitId &other) const { return id != other.id; }\n\t\tbool operator<(const DriveBitId &other) const { return id < other.id; }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\t};\n\t// Essentially a dict<DriveBitId, pool<DriveBitId>> but using less memory\n\t// and fewer allocations\n\tstruct DriveBitGraph {\n\t\tdict<DriveBitId, DriveBitId> first_edges;\n\t\tdict<DriveBitId, DriveBitId> second_edges;\n\t\tdict<DriveBitId, pool<DriveBitId>> more_edges;\n\n\t\tvoid add_edge(DriveBitId src, DriveBitId dst);\n\t\tDriveBitId pop_edge(DriveBitId src);\n\t\tvoid clear(DriveBitId src);\n\t\tbool contains(DriveBitId src);\n\t\tint count(DriveBitId src);\n\n\t\tDriveBitId at(DriveBitId src, int index);\n\t};\n\n\t// The following two maps maintain a sparse DriveBit to DriveBitId mapping.\n\t// This saves a lot of memory compared to a `dict<DriveBit, DriveBitId>` or\n\t// `idict<DriveBit>`.\n\n\t// Maps wires to the first DriveBitId of the consecutive range used for\n\t// that wire.\n\tdict<Wire *, DriveBitId> wire_offsets;\n\n\t// Maps cell ports to a the first DriveBitId of the consecutive range used\n\t// for that cell port.\n\tdict<pair<Cell *, IdString>, DriveBitId> port_offsets;\n\n\t// For the inverse map that maps DriveBitIds back to DriveBits we use a\n\t// sorted map containing only the first DriveBit for each wire and cell\n\t// port.\n\tstd::map<DriveBitId, DriveBit> drive_bits;\n\n\t// As a memory optimization for gate level net lists we store single-bit\n\t// wires and cell ports in a `dict` which requires less memory and fewer\n\t// allocations than `std::map` but doesn't support the kind of lookups we\n\t// need for a sparse coarse grained mapping.\n\tdict<DriveBitId, DriveBit> isolated_drive_bits;\n\n\t// Used for allocating DriveBitIds, none and constant states use a fixewd\n\t// mapping to the first few ids, which we need to skip.\n\tint next_offset = 1 + (int)State::Sm;\n\n\t// Union-Find over directly connected bits that share the same single\n\t// driver or are undriven. We never merge connections between drivers\n\t// and/or kept wires.\n\tmfp<DriveBitId> same_driver;\n\n\t// For each bit, store a set of connected driver bits for which the\n\t// explicit connection should be preserved and the driving direction is\n\t// locally unambiguous (one side only drives or requires a driven value).\n\tDriveBitGraph connected_drivers;\n\n\t// For each bit, store a set of connected driver bits for which the\n\t// explicit connection should be preserved and the driving direction is\n\t// locally ambiguous. Every such ambiguous connection is also present in\n\t// the reverse direction and has to be resolved when querying drivers.\n\tDriveBitGraph connected_undirected;\n\n\t// Subset of `connected_undirected` for caching the resolved driving\n\t// direction. In case multiple drivers are present this can still contain\n\t// both orientations of a single connection, but for a single driver only\n\t// one will be present.\n\tDriveBitGraph connected_oriented;\n\n\t// Stores for which bits we already resolved the orientation (cached in\n\t// `connected_oriented`).\n\tpool<DriveBitId> oriented_present;\n\n\n\tenum class BitMode {\n\t\tNONE = 0, // Not driven, no need to keep wire\n\t\tDRIVEN = 1, // Not driven, uses a value driven elsewhere\n\t\tDRIVEN_UNIQUE = 2, // Uses a value driven elsewhere, has at most one direct connection\n\t\tKEEP = 3, // Wire that should be kept\n\t\tTRISTATE = 4, // Can drive a value but can also use a value driven elsewhere\n\t\tDRIVER = 5, // Drives a value\n\t};\n\n\tBitMode bit_mode(DriveBit const &bit);\n\tDriveBitId id_from_drive_bit(DriveBit const &bit);\n\tDriveBit drive_bit_from_id(DriveBitId id);\n\n\tvoid connect_directed_merge(DriveBitId driven_id, DriveBitId driver_id);\n\tvoid connect_directed_buffer(DriveBitId driven_id, DriveBitId driver_id);\n\tvoid connect_undirected(DriveBitId a_id, DriveBitId b_id);\n\npublic:\n\n\tvoid add(Module *module);\n\n\t// Add a single bit connection to the driver map.\n\tvoid add(DriveBit const &a, DriveBit const &b);\n\n\ttemplate<typename T>\n\tstatic constexpr bool is_sig_type() {\n\t\treturn\n\t\t\tstd::is_same<T, SigSpec>::value ||\n\t\t\tstd::is_same<T, SigChunk>::value ||\n\t\t\tstd::is_same<T, DriveSpec>::value ||\n\t\t\tstd::is_same<T, DriveChunk>::value ||\n\t\t\tstd::is_same<T, DriveChunkPort>::value ||\n\t\t\tstd::is_same<T, DriveChunkWire>::value ||\n\t\t\tstd::is_same<T, Const>::value;\n\t}\n\n\t// We use the enable_if to produce better compiler errors when unsupported\n\t// types are used\n\ttemplate<typename T, typename U>\n\ttypename std::enable_if<is_sig_type<T>() && is_sig_type<U>()>::type\n\tadd(T const &a, U const &b)\n\t{\n\t\tlog_assert(a.size() == b.size());\n\t\tfor (int i = 0; i != GetSize(a); ++i)\n\t\t\tadd(DriveBit(a[i]), DriveBit(b[i]));\n\t}\n\n\n\t// Specialized version that avoids unpacking\n\tvoid add(SigSpec const &a, SigSpec const &b);\n\nprivate:\n\tvoid add_port(Cell *cell, IdString const &port, SigSpec const &b);\n\n\t// Only used a local variables in `orient_undirected`, always cleared, only\n\t// stored to reduce allocations.\n\tpool<DriveBitId> orient_undirected_seen;\n\tpool<DriveBitId> orient_undirected_drivers;\n\tdict<DriveBitId, int> orient_undirected_distance;\n\n\tvoid orient_undirected(DriveBitId id);\n\npublic:\n\tDriveBit operator()(DriveBit const &bit);\n\n\tDriveSpec operator()(DriveSpec spec);\n\nprivate:\n\tbool keep_wire(Wire *wire) {\n\t\t// TODO configurable\n\t\treturn wire->has_attribute(ID(keep));\n\t}\n};\n\ninline Hasher DriveBitWire::hash_into(Hasher h) const\n{\n\th.eat(wire->name);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveBitPort::hash_into(Hasher h) const\n{\n\th.eat(cell->name);\n\th.eat(port);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveBitMarker::hash_into(Hasher h) const\n{\n\th.eat(marker);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveBitMultiple::hash_into(Hasher h) const\n{\n\th.eat(multiple_);\n\treturn h;\n}\n\ninline Hasher DriveBit::hash_into(Hasher h) const\n{\n\tswitch (type_) {\n\tcase DriveType::NONE:\n\t\th.eat(0);\n\t\tbreak;\n\tcase DriveType::CONSTANT:\n\t\th.eat(constant_);\n\t\tbreak;\n\tcase DriveType::WIRE:\n\t\th.eat(wire_);\n\t\tbreak;\n\tcase DriveType::PORT:\n\t\th.eat(port_);\n\t\tbreak;\n\tcase DriveType::MARKER:\n\t\th.eat(marker_);\n\t\tbreak;\n\tcase DriveType::MULTIPLE:\n\t\th.eat(multiple_);\n\t\tbreak;\n\t}\n\th.eat(type_);\n\treturn h;\n}\n\ninline Hasher DriveChunkWire::hash_into(Hasher h) const\n{\n\th.eat(wire->name);\n\th.eat(width);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveChunkPort::hash_into(Hasher h) const\n{\n\th.eat(cell->name);\n\th.eat(port);\n\th.eat(width);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveChunkMarker::hash_into(Hasher h) const\n{\n\th.eat(marker);\n\th.eat(width);\n\th.eat(offset);\n\treturn h;\n}\n\ninline Hasher DriveChunkMultiple::hash_into(Hasher h) const\n{\n\th.eat(width_);\n\th.eat(multiple_);\n\treturn h;\n}\n\ninline Hasher DriveChunk::hash_into(Hasher h) const\n{\n\tswitch (type_) {\n\tcase DriveType::NONE:\n\t\th.eat(0);\n\t\tbreak;\n\tcase DriveType::CONSTANT:\n\t\th.eat(constant_);\n\t\tbreak;\n\tcase DriveType::WIRE:\n\t\th.eat(wire_);\n\t\tbreak;\n\tcase DriveType::PORT:\n\t\th.eat(port_);\n\t\tbreak;\n\tcase DriveType::MARKER:\n\t\th.eat(marker_);\n\t\tbreak;\n\tcase DriveType::MULTIPLE:\n\t\th.eat(multiple_);\n\t\tbreak;\n\t}\n\th.eat(type_);\n\treturn h;\n}\n\ninline Hasher DriveSpec::hash_into(Hasher h) const\n{\n\tupdhash();\n\th.eat(hash_);\n\treturn h;\n}\n\ninline Hasher DriverMap::DriveBitId::hash_into(Hasher h) const\n{\n\th.eat(id);\n\treturn h;\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
171
171
|
"ff.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FF_H\n#define FF_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/ffinit.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// Describes a flip-flop or a latch.\n//\n// If has_gclk, this is a formal verification FF with implicit global clock:\n// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is\n// an $anyinit cell which always has an undefined initialization value. Note\n// that $anyinit is not considered to be among the FF celltypes, so a pass has\n// to explicitly opt-in to process $anyinit cells with FfData.\n//\n// Otherwise, the FF/latch can have any number of features selected by has_*\n// attributes that determine Q's value (in order of decreasing priority):\n//\n// - on start, register is initialized to val_init\n// - if has_sr is present:\n// - sig_clr is per-bit async clear, and sets the corresponding bit to 0\n// if active\n// - sig_set is per-bit async set, and sets the corresponding bit to 1\n// if active\n// - if has_arst is present:\n// - sig_arst is whole-reg async reset, and sets the whole register to val_arst\n// - if has_aload is present:\n// - sig_aload is whole-reg async load (aka latch gate enable), and sets the whole\n// register to sig_ad\n// - if has_clk is present, and we're currently on a clock edge:\n// - if has_ce is present and ce_over_srst is true:\n// - ignore clock edge (don't change value) unless sig_ce is active\n// - if has_srst is present:\n// - sig_srst is whole-reg sync reset and sets the register to val_srst\n// - if has_ce is present and ce_over_srst is false:\n// - ignore clock edge (don't change value) unless sig_ce is active\n// - set whole reg to sig_d\n// - if nothing of the above applies, the reg value remains unchanged\n//\n// Since the yosys FF cell library isn't fully generic, not all combinations\n// of the features above can be supported:\n//\n// - only one of has_srst, has_arst, has_sr can be used\n// - if has_clk is used together with has_aload, then has_srst, has_arst,\n// has_sr cannot be used\n//\n// The valid feature combinations are thus:\n//\n// - has_clk + optional has_ce [dff/dffe]\n// - has_clk + optional has_ce + has_arst [adff/adffe]\n// - has_clk + optional has_ce + has_aload [aldff/aldffe]\n// - has_clk + optional has_ce + has_sr [dffsr/dffsre]\n// - has_clk + optional has_ce + has_srst [sdff/sdffe/sdffce]\n// - has_aload [dlatch]\n// - has_aload + has_arst [adlatch]\n// - has_aload + has_sr [dlatchsr]\n// - has_sr [sr]\n// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]\n// - empty set [not a cell — will be emitted as a simple direct connection]\n\nstruct FfData {\n\tModule *module;\n\tFfInitVals *initvals;\n\tCell *cell;\n\tIdString name;\n\t// The FF output.\n\tSigSpec sig_q;\n\t// The sync data input, present if has_clk or has_gclk.\n\tSigSpec sig_d;\n\t// The async data input, present if has_aload.\n\tSigSpec sig_ad;\n\t// The sync clock, present if has_clk.\n\tSigSpec sig_clk;\n\t// The clock enable, present if has_ce.\n\tSigSpec sig_ce;\n\t// The async load enable, present if has_aload.\n\tSigSpec sig_aload;\n\t// The async reset, preset if has_arst.\n\tSigSpec sig_arst;\n\t// The sync reset, preset if has_srst.\n\tSigSpec sig_srst;\n\t// The async clear (per-lane), present if has_sr.\n\tSigSpec sig_clr;\n\t// The async set (per-lane), present if has_sr.\n\tSigSpec sig_set;\n\t// True if this is a clocked (edge-sensitive) flip-flop.\n\tbool has_clk;\n\t// True if this is a $ff, exclusive with every other has_*.\n\tbool has_gclk;\n\t// True if this FF has a clock enable. Depends on has_clk.\n\tbool has_ce;\n\t// True if this FF has async load function — this includes D latches.\n\t// If this and has_clk are both set, has_arst and has_sr cannot be set.\n\tbool has_aload;\n\t// True if this FF has sync set/reset. Depends on has_clk, exclusive\n\t// with has_arst, has_sr, has_aload.\n\tbool has_srst;\n\t// True if this FF has async set/reset. Exclusive with has_srst,\n\t// has_sr. If this and has_clk are both set, has_aload cannot be set.\n\tbool has_arst;\n\t// True if this FF has per-bit async set + clear. Exclusive with\n\t// has_srst, has_arst. If this and has_clk are both set, has_aload\n\t// cannot be set.\n\tbool has_sr;\n\t// If has_ce and has_srst are both set, determines their relative\n\t// priorities: if true, inactive ce disables srst; if false, srst\n\t// operates independent of ce.\n\tbool ce_over_srst;\n\t// True if this FF is a fine cell, false if it is a coarse cell.\n\t// If true, width must be 1.\n\tbool is_fine;\n\t// True if this FF is an $anyinit cell. Depends on has_gclk.\n\tbool is_anyinit;\n\t// Polarities, corresponding to sig_*.\n\t// True means rising edge, false means falling edge.\n\tbool pol_clk;\n\t// True means active-high, false\n\t// means active-low.\n\tbool pol_ce;\n\tbool pol_aload;\n\tbool pol_arst;\n\tbool pol_srst;\n\tbool pol_clr;\n\tbool pol_set;\n\t// The value loaded by sig_arst.\n\tConst val_arst;\n\t// The value loaded by sig_srst.\n\tConst val_srst;\n\t// The initial value at power-up.\n\tConst val_init;\n\t// The FF data width in bits.\n\tint width;\n\tdict<IdString, Const> attributes;\n\n\tFfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {\n\t\twidth = 0;\n\t\thas_clk = false;\n\t\thas_gclk = false;\n\t\thas_ce = false;\n\t\thas_aload = false;\n\t\thas_srst = false;\n\t\thas_arst = false;\n\t\thas_sr = false;\n\t\tce_over_srst = false;\n\t\tis_fine = false;\n\t\tis_anyinit = false;\n\t\tpol_clk = false;\n\t\tpol_aload = false;\n\t\tpol_ce = false;\n\t\tpol_arst = false;\n\t\tpol_srst = false;\n\t\tpol_clr = false;\n\t\tpol_set = false;\n\t}\n\n\tFfData(FfInitVals *initvals, Cell *cell_);\n\n\t// Returns a FF identical to this one, but only keeping bit indices from the argument.\n\tFfData slice(const std::vector<int> &bits);\n\n\tvoid add_dummy_ce();\n\tvoid add_dummy_srst();\n\tvoid add_dummy_arst();\n\tvoid add_dummy_aload();\n\tvoid add_dummy_sr();\n\tvoid add_dummy_clk();\n\n\tvoid arst_to_aload();\n\tvoid arst_to_sr();\n\n\tvoid aload_to_sr();\n\n\t// Given a FF with both has_ce and has_srst, sets ce_over_srst to the given value and\n\t// fixes up control signals appropriately to preserve semantics.\n\tvoid convert_ce_over_srst(bool val);\n\n\tvoid unmap_ce();\n\tvoid unmap_srst();\n\n\tvoid unmap_ce_srst() {\n\t\tunmap_ce();\n\t\tunmap_srst();\n\t}\n\n\tCell *emit();\n\n\t// Removes init attribute from the Q output, but keeps val_init unchanged.\n\t// It will be automatically reattached on emit. Use this before changing sig_q.\n\tvoid remove_init() {\n\t\tif (initvals)\n\t\t\tinitvals->remove_init(sig_q);\n\t}\n\n\tvoid remove();\n\n\t// Flip the sense of the given bit slices of the FF: insert inverters on data\n\t// inputs and output, flip the corresponding init/reset bits, swap clr/set\n\t// inputs with proper priority fix.\n\tvoid flip_bits(const pool<int> &bits);\n\n\tvoid flip_rst_bits(const pool<int> &bits);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
172
|
-
"ffinit.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FFINIT_H\n#define FFINIT_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/sigtools.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct FfInitVals\n{\n\tconst
|
|
173
|
-
"ffmerge.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FFMERGE_H\n#define FFMERGE_H\n\n#include \"kernel/ffinit.h\"\n#include \"kernel/ff.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// A helper class for passes that want to merge FFs on the input or output\n// of a cell into the cell itself.\n//\n// The procedure is:\n//\n// 1. Construct this class (at beginning of processing for a given module).\n// 2. For every considered cell:\n//\n// a. Call find_output_ff for every considered output.\n// b. Call find_input_ff for every considered input.\n// c. Look at the FF description returned (if any) from each call, reject\n// results that cannot be merged into given cell for any reason.\n// If both inputs and outputs are being merged, take care of FF bits that\n// are returned in both input and output results (a FF bit cannot be\n// merged to both). Decide on the final set of FF bits to merge.\n// d. Call remove_output_ff for every find_output_ff result that will be used\n// for merging. This removes the actual FF bits from design and from index.\n// e. Call mark_input_ff for every find_input_ff result that will be used\n// for merging. This updates the index disallowing further usage of these\n// FF bits for output FF merging, if they were eligible before. The actual\n// FF bits are still left in the design and can be merged into other inputs.\n// If the FF bits are not otherwise used, they will be removed by later\n// opt passes.\n// f. Merge the FFs into the cell.\n//\n// Note that, if both inputs and outputs are being considered for merging in\n// a single pass, the result may be nondeterministic (depending on cell iteration\n// order) because a given FF bit could be eligible for both input and output merge,\n// perhaps in different cells. For this reason, it may be a good idea to separate\n// input and output merging.\n\nstruct FfMergeHelper\n{\n\tconst
|
|
172
|
+
"ffinit.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FFINIT_H\n#define FFINIT_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/sigtools.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct FfInitVals\n{\n\tconst SigMapView *sigmap;\n\tdict<SigBit, std::pair<State,SigBit>> initbits;\n\n\tvoid set(const SigMapView *sigmap_, RTLIL::Module *module)\n\t{\n\t\tsigmap = sigmap_;\n\t\tinitbits.clear();\n\t\tfor (auto wire : module->wires())\n\t\t{\n\t\t\tif (wire->attributes.count(ID::init) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tSigSpec wirebits = (*sigmap)(wire);\n\t\t\tConst initval = wire->attributes.at(ID::init);\n\n\t\t\tfor (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)\n\t\t\t{\n\t\t\t\tSigBit bit = wirebits[i];\n\t\t\t\tState val = initval[i];\n\n\t\t\t\tif (val != State::S0 && val != State::S1 && bit.wire != nullptr)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (initbits.count(bit)) {\n\t\t\t\t\tif (initbits.at(bit).first != val)\n\t\t\t\t\t\tlog_error(\"Conflicting init values for signal %s (%s = %s != %s).\\n\",\n\t\t\t\t\t\t\t\tlog_signal(bit), log_signal(SigBit(wire, i)),\n\t\t\t\t\t\t\t\tlog_signal(val), log_signal(initbits.at(bit).first));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tinitbits[bit] = std::make_pair(val,SigBit(wire,i));\n\t\t\t}\n\t\t}\n\t}\n\n\tRTLIL::State operator()(RTLIL::SigBit bit) const\n\t{\n\t\tauto it = initbits.find((*sigmap)(bit));\n\t\tif (it != initbits.end())\n\t\t\treturn it->second.first;\n\t\telse\n\t\t\treturn State::Sx;\n\t}\n\n\tRTLIL::Const operator()(const RTLIL::SigSpec &sig) const\n\t{\n\t\tRTLIL::Const res;\n\t\tfor (auto bit : sig)\n\t\t\tres.bits().push_back((*this)(bit));\n\t\treturn res;\n\t}\n\n\tvoid set_init(RTLIL::SigBit bit, RTLIL::State val)\n\t{\n\t\tSigBit mbit = (*sigmap)(bit);\n\t\tSigBit abit = bit;\n\t\tauto it = initbits.find(mbit);\n\t\tif (it != initbits.end())\n\t\t\tabit = it->second.second;\n\t\telse if (val == State::Sx)\n\t\t\treturn;\n\t\tlog_assert(abit.wire);\n\t\tinitbits[mbit] = std::make_pair(val,abit);\n\t\tauto it2 = abit.wire->attributes.find(ID::init);\n\t\tif (it2 != abit.wire->attributes.end()) {\n\t\t\tit2->second.bits()[abit.offset] = val;\n\t\t\tif (it2->second.is_fully_undef())\n\t\t\t\tabit.wire->attributes.erase(it2);\n\t\t} else if (val != State::Sx) {\n\t\t\tConst cval(State::Sx, GetSize(abit.wire));\n\t\t\tcval.bits()[abit.offset] = val;\n\t\t\tabit.wire->attributes[ID::init] = cval;\n\t\t}\n\t}\n\n\tvoid set_init(const RTLIL::SigSpec &sig, RTLIL::Const val)\n\t{\n\t\tlog_assert(GetSize(sig) == GetSize(val));\n\t\tfor (int i = 0; i < GetSize(sig); i++)\n\t\t\tset_init(sig[i], val[i]);\n\t}\n\n\tvoid remove_init(RTLIL::SigBit bit)\n\t{\n\t\tset_init(bit, State::Sx);\n\t}\n\n\tvoid remove_init(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto bit : sig)\n\t\t\tremove_init(bit);\n\t}\n\n\tvoid clear()\n\t{\n\t\tinitbits.clear();\n\t}\n\n\tFfInitVals (const SigMapView *sigmap, RTLIL::Module *module)\n\t{\n\t\tset(sigmap, module);\n\t}\n\n\tFfInitVals () {}\n};\n\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
173
|
+
"ffmerge.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FFMERGE_H\n#define FFMERGE_H\n\n#include \"kernel/ffinit.h\"\n#include \"kernel/ff.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// A helper class for passes that want to merge FFs on the input or output\n// of a cell into the cell itself.\n//\n// The procedure is:\n//\n// 1. Construct this class (at beginning of processing for a given module).\n// 2. For every considered cell:\n//\n// a. Call find_output_ff for every considered output.\n// b. Call find_input_ff for every considered input.\n// c. Look at the FF description returned (if any) from each call, reject\n// results that cannot be merged into given cell for any reason.\n// If both inputs and outputs are being merged, take care of FF bits that\n// are returned in both input and output results (a FF bit cannot be\n// merged to both). Decide on the final set of FF bits to merge.\n// d. Call remove_output_ff for every find_output_ff result that will be used\n// for merging. This removes the actual FF bits from design and from index.\n// e. Call mark_input_ff for every find_input_ff result that will be used\n// for merging. This updates the index disallowing further usage of these\n// FF bits for output FF merging, if they were eligible before. The actual\n// FF bits are still left in the design and can be merged into other inputs.\n// If the FF bits are not otherwise used, they will be removed by later\n// opt passes.\n// f. Merge the FFs into the cell.\n//\n// Note that, if both inputs and outputs are being considered for merging in\n// a single pass, the result may be nondeterministic (depending on cell iteration\n// order) because a given FF bit could be eligible for both input and output merge,\n// perhaps in different cells. For this reason, it may be a good idea to separate\n// input and output merging.\n\nstruct FfMergeHelper\n{\n\tconst SigMapView *sigmap;\n\tRTLIL::Module *module;\n\tFfInitVals *initvals;\n\n\tdict<SigBit, std::pair<Cell*, int>> dff_driver;\n\tdict<SigBit, pool<std::pair<Cell*, int>>> dff_sink;\n\tdict<SigBit, int> sigbit_users_count;\n\n\t// Returns true if all bits in sig are completely unused.\n\tbool is_output_unused(RTLIL::SigSpec sig);\n\n\t// Finds the FF to merge into a given cell output. Takes sig, which\n\t// is the current cell output — it will be the sig_d of the found FF.\n\t// If found, returns true, and fills the two output arguments.\n\t//\n\t// For every bit of sig, this function finds a FF bit that has\n\t// the same sig_d, and fills the output FfData according to the FF\n\t// bits found. This function will only consider FF bits that are\n\t// the only user of the given sig bits — if any bit in sig is used\n\t// by anything other than a single FF, this function will return false.\n\t//\n\t// The returned FfData structure does not correspond to any actual FF\n\t// cell in the design — it is the amalgamation of extracted FF bits,\n\t// possibly coming from several FF cells.\n\t//\n\t// If some of the bits in sig have no users at all, this function\n\t// will accept them as well (and fill returned FfData with dummy values\n\t// for the given bit, effectively synthesizing an unused FF bit of the\n\t// appropriate type). However, if all bits in sig are completely\n\t// unused, this function will fail and return false (having no idea\n\t// what kind of FF to produce) — use the above helper if that case\n\t// is important to handle.\n\t//\n\t// Note that this function does not remove the FF bits returned from\n\t// the design — this is so that the caller can decide whether to accept\n\t// this FF for merging or not. If the result is accepted,\n\t// remove_output_ff should be called on the second output argument.\n\tbool find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);\n\n\t// Like above, but returns a FF to merge into a given cell input. Takes\n\t// sig_q, which is the current cell input — it will search for FFs with\n\t// matching sig_q.\n\t//\n\t// As opposed to find_output_ff, this function doesn't care about usage\n\t// counts, and may return FF bits that also have other fanout. This\n\t// should not be a problem for input FF merging.\n\t//\n\t// As a special case, if some of the bits in sig_q are constant, this\n\t// function will accept them as well, by synthesizing in-place\n\t// a constant-input FF bit (with matching initial value and reset value).\n\t// However, this will not work if the input is all-constant — if the caller\n\t// cares about this case, it needs to check for it explicitely.\n\tbool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits);\n\n\t// To be called on find_output_ff result that will be merged. This\n\t// marks the given FF bits as used up (and not to be considered for\n\t// further merging as inputs), and reconnects their Q ports to a dummy\n\t// wire (since the wire previously connected there will now be driven\n\t// by the merged-to cell instead).\n\tvoid remove_output_ff(const pool<std::pair<Cell *, int>> &bits);\n\n\t// To be called on find_input_ff result that will be merged. This\n\t// marks the given FF bits as used, and disallows merging them as\n\t// outputs. They can, however, still be merged as inputs again\n\t// (perhaps for another cell).\n\tvoid mark_input_ff(const pool<std::pair<Cell *, int>> &bits);\n\n\tvoid set(FfInitVals *initvals_, RTLIL::Module *module_);\n\n\tvoid clear();\n\n\tFfMergeHelper(FfInitVals *initvals, RTLIL::Module *module) {\n\t\tset(initvals, module);\n\t}\n\n\tFfMergeHelper() {}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
174
174
|
"fmt.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2020 whitequark <whitequark@whitequark.org>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef FMT_H\n#define FMT_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// Verilog format argument, such as the arguments in:\n// $display(\"foo %d bar %01x\", 4'b0, $signed(2'b11))\nstruct VerilogFmtArg {\n\tenum {\n\t\tSTRING = 0,\n\t\tINTEGER = 1,\n\t\tTIME = 2,\n\t} type;\n\n\t// All types\n\tstd::string filename;\n\tunsigned first_line;\n\n\t// STRING type\n\tstd::string str;\n\n\t// INTEGER type\n\tRTLIL::SigSpec sig;\n\tbool signed_ = false;\n\n\t// TIME type\n\tbool realtime = false;\n};\n\n// RTLIL format part, such as the substitutions in:\n// \"foo {4:> 4du} bar {2:<01hs}\"\n// Must be kept in sync with `struct fmt_part` in backends/cxxrtl/runtime/cxxrtl/cxxrtl.h!\nstruct FmtPart {\n\tenum {\n\t\tLITERAL \t= 0,\n\t\tINTEGER \t= 1,\n\t\tSTRING = 2,\n\t\tUNICHAR = 3,\n\t\tVLOG_TIME = 4,\n\t} type;\n\n\t// LITERAL type\n\tstd::string str;\n\n\t// INTEGER/STRING/UNICHAR types\n\tRTLIL::SigSpec sig;\n\n\t// INTEGER/STRING/VLOG_TIME types\n\tenum {\n\t\tRIGHT\t= 0,\n\t\tLEFT\t= 1,\n\t\tNUMERIC\t= 2,\n\t} justify = RIGHT;\n\tchar padding = '\\0';\n\tsize_t width = 0;\n\n\t// INTEGER type\n\tunsigned base = 10;\n\tbool signed_ = false;\n\tenum {\n\t\tMINUS\t\t= 0,\n\t\tPLUS_MINUS\t= 1,\n\t\tSPACE_MINUS\t= 2,\n\t} sign = MINUS;\n\tbool hex_upper = false;\n\tbool show_base = false;\n\tbool group = false;\n\n\t// VLOG_TIME type\n\tbool realtime = false;\n};\n\nstruct Fmt {\npublic:\n\tstd::vector<FmtPart> parts;\n\n\tvoid append_literal(const std::string &str);\n\n\tvoid parse_rtlil(const RTLIL::Cell *cell);\n\tvoid emit_rtlil(RTLIL::Cell *cell) const;\n\n\tvoid parse_verilog(const std::vector<VerilogFmtArg> &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name);\n\tstd::vector<VerilogFmtArg> emit_verilog() const;\n\n\tvoid emit_cxxrtl(std::ostream &os, std::string indent, std::function<void(const RTLIL::SigSpec &)> emit_sig, const std::string &context) const;\n\n\tstd::string render() const;\n\nprivate:\n\tvoid apply_verilog_automatic_sizing_and_add(FmtPart &part);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
175
175
|
"gzip.h": "#include <string>\n#include \"kernel/yosys_common.h\"\n\n#ifndef YOSYS_GZIP_H\n#define YOSYS_GZIP_H\n\nYOSYS_NAMESPACE_BEGIN\n\n#ifdef YOSYS_ENABLE_ZLIB\n\nnamespace Zlib {\n#include <zlib.h>\n}\n\n/*\nAn output stream that uses a stringbuf to buffer data internally,\nusing zlib to write gzip-compressed data every time the stream is flushed.\n*/\nclass gzip_ostream : public std::ostream {\npublic:\n\tgzip_ostream(): std::ostream(nullptr) {\n\t\trdbuf(&outbuf);\n\t}\n\tbool open(const std::string &filename) {\n\t\treturn outbuf.open(filename);\n\t}\nprivate:\n\tclass obuf : public std::stringbuf {\n\tpublic:\n\t\tobuf();\n\t\tbool open(const std::string &filename);\n\t\tvirtual int sync() override;\n\t\tvirtual ~obuf();\n\tprivate:\n\t\tstatic const int buffer_size = 4096;\n\t\tchar buffer[buffer_size]; // Internal buffer for compressed data\n\t\tZlib::gzFile gzf = nullptr; // Handle to the gzip file\n\t};\n\n\tobuf outbuf; // The stream buffer instance\n};\n\n/*\nAn input stream that uses zlib to read gzip-compressed data from a file,\nbuffering the decompressed data internally using its own buffer.\n*/\nclass gzip_istream final : public std::istream {\npublic:\n\tgzip_istream() : std::istream(&inbuf) {}\n\tbool open(const std::string& filename) {\n\t\treturn inbuf.open(filename);\n\t}\nprivate:\n\tclass ibuf final : public std::streambuf {\n\tpublic:\n\t\tibuf() : gzf(nullptr) {}\n\t\tbool open(const std::string& filename);\n\t\tvirtual ~ibuf();\n\n\tprotected:\n\t\t// Called when the buffer is empty and more input is needed\n\t\tvirtual int_type underflow() override;\n\tprivate:\n\t\tstatic const int buffer_size = 8192;\n\t\tchar buffer[buffer_size];\n\t\tZlib::gzFile gzf;\n\t};\n\n\tibuf inbuf; // The stream buffer instance\n};\n\n#endif // YOSYS_ENABLE_ZLIB\n\nstd::istream* uncompressed(const std::string filename, std::ios_base::openmode mode = std::ios_base::in);\n\nYOSYS_NAMESPACE_END\n\n#endif // YOSYS_GZIP_H\n",
|
|
176
|
-
"hashlib.h": "// This is free and unencumbered software released into the public domain.\n//\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// -------------------------------------------------------\n// Written by Claire Xenia Wolf <claire@yosyshq.com> in 2014\n// -------------------------------------------------------\n\n#ifndef HASHLIB_H\n#define HASHLIB_H\n\n#include <stdexcept>\n#include <algorithm>\n#include <optional>\n#include <string>\n#include <variant>\n#include <vector>\n#include <type_traits>\n#include <stdint.h>\n\n#define YS_HASHING_VERSION 1\n\nnamespace hashlib {\n\n/**\n * HASHING\n *\n * Also refer to docs/source/yosys_internals/hashing.rst\n *\n * The Hasher knows how to hash 32 and 64-bit integers. That's it.\n * In the future, it could be expanded to do vectors with SIMD.\n *\n * The Hasher doesn't know how to hash common standard containers\n * and compositions. However, hashlib provides centralized wrappers.\n *\n * Hashlib doesn't know how to hash silly Yosys-specific types.\n * Hashlib doesn't depend on Yosys and can be used standalone.\n * Please don't use hashlib standalone for new projects.\n * Never directly include kernel/hashlib.h in Yosys code.\n * Instead include kernel/yosys_common.h\n *\n * The hash_ops type is now always left to its default value, derived\n * from templated functions through SFINAE. Providing custom ops is\n * still supported.\n *\n * HASH TABLES\n *\n * We implement associative data structures with separate chaining.\n * Linked lists use integers into the indirection hashtable array\n * instead of pointers.\n */\n\nconst int hashtable_size_trigger = 2;\nconst int hashtable_size_factor = 3;\n\nnamespace legacy {\n\tinline uint32_t djb2_add(uint32_t a, uint32_t b) {\n\t\treturn ((a << 5) + a) + b;\n\t}\n};\n\ntemplate<typename T>\nstruct hash_ops;\n\ninline unsigned int mkhash_xorshift(unsigned int a) {\n\tif (sizeof(a) == 4) {\n\t\ta ^= a << 13;\n\t\ta ^= a >> 17;\n\t\ta ^= a << 5;\n\t} else if (sizeof(a) == 8) {\n\t\ta ^= a << 13;\n\t\ta ^= a >> 7;\n\t\ta ^= a << 17;\n\t} else\n\t\tthrow std::runtime_error(\"mkhash_xorshift() only implemented for 32 bit and 64 bit ints\");\n\treturn a;\n}\n\nclass HasherDJB32 {\npublic:\n\tusing hash_t = uint32_t;\n\n\tHasherDJB32() {\n\t\t// traditionally 5381 is used as starting value for the djb2 hash\n\t\tstate = 5381;\n\t}\n\tstatic void set_fudge(hash_t f) {\n\t\tfudge = f;\n\t}\n\nprivate:\n\tuint32_t state;\n\tstatic uint32_t fudge;\n\t// The XOR version of DJB2\n\t[[nodiscard]]\n\tstatic uint32_t djb2_xor(uint32_t a, uint32_t b) {\n\t\tuint32_t hash = ((a << 5) + a) ^ b;\n\t\treturn hash;\n\t}\n\tpublic:\n\tvoid hash32(uint32_t i) {\n\t\tstate = djb2_xor(i, state);\n\t\tstate = mkhash_xorshift(fudge ^ state);\n\t\treturn;\n\t}\n\tvoid hash64(uint64_t i) {\n\t\tstate = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state);\n\t\tstate = djb2_xor((uint32_t)(i >> 32ULL), state);\n\t\tstate = mkhash_xorshift(fudge ^ state);\n\t\treturn;\n\t}\n\t[[nodiscard]]\n\thash_t yield() {\n\t\treturn (hash_t)state;\n\t}\n\n\ttemplate<typename T>\n\tvoid eat(T&& t) {\n\t\t*this = hash_ops<std::remove_cv_t<std::remove_reference_t<T>>>::hash_into(std::forward<T>(t), *this);\n\t}\n\n\ttemplate<typename T>\n\tvoid eat(const T& t) {\n\t\t*this = hash_ops<T>::hash_into(t, *this);\n\t}\n\n\tvoid commutative_eat(hash_t t) {\n\t\tstate ^= t;\n\t}\n\n\tvoid force(hash_t new_state) {\n\t\tstate = new_state;\n\t}\n};\n\nusing Hasher = HasherDJB32;\n\n// Boilerplate compressor for trivially implementing\n// top-level hash method with hash_into\n#define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash\n#define HASH_TOP_LOOP_SND { \\\n\tHasher h; \\\n\th = hash_into(a, h); \\\n\treturn h; \\\n}\n\ntemplate<typename T>\nstruct hash_ops {\n\tstatic inline bool cmp(const T &a, const T &b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const T &a, Hasher h) {\n\t\tif constexpr (std::is_integral_v<T>) {\n\t\t\tstatic_assert(sizeof(T) <= sizeof(uint64_t));\n\t\t\tif (sizeof(T) == sizeof(uint64_t))\n\t\t\t\th.hash64(a);\n\t\t\telse\n\t\t\t\th.hash32(a);\n\t\t\treturn h;\n\t\t} else if constexpr (std::is_enum_v<T>) {\n\t\t\tusing u_type = std::underlying_type_t<T>;\n\t\t\treturn hash_ops<u_type>::hash_into((u_type) a, h);\n\t\t} else if constexpr (std::is_pointer_v<T>) {\n\t\t\treturn hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);\n\t\t} else if constexpr (std::is_same_v<T, std::string>) {\n\t\t\tfor (auto c : a)\n\t\t\t\th.hash32(c);\n\t\t\treturn h;\n\t\t} else {\n\t\t\treturn a.hash_into(h);\n\t\t}\n\t}\n\tHASH_TOP_LOOP_FST (const T &a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {\n\tstatic inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {\n\t\th = hash_ops<P>::hash_into(a.first, h);\n\t\th = hash_ops<Q>::hash_into(a.second, h);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename... T> struct hash_ops<std::tuple<T...>> {\n\tstatic inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {\n\t\treturn a == b;\n\t}\n\ttemplate<size_t I = 0>\n\tstatic inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {\n\t\treturn h;\n\t}\n\ttemplate<size_t I = 0>\n\tstatic inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {\n\t\ttypedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;\n\t\th = hash_into<I+1>(a, h);\n\t\th = element_ops_t::hash_into(std::get<I>(a), h);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename T> struct hash_ops<std::vector<T>> {\n\tstatic inline bool cmp(std::vector<T> a, std::vector<T> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::vector<T> a, Hasher h) {\n\t\th.eat((uint32_t)a.size());\n\t\tfor (auto k : a)\n\t\t\th.eat(k);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename T, size_t N> struct hash_ops<std::array<T, N>> {\n static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {\n return a == b;\n }\n [[nodiscard]] static inline Hasher hash_into(std::array<T, N> a, Hasher h) {\n for (const auto& k : a)\n h = hash_ops<T>::hash_into(k, h);\n return h;\n }\n\tHASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND\n};\n\nstruct hash_cstr_ops {\n\tstatic inline bool cmp(const char *a, const char *b) {\n\t\treturn strcmp(a, b) == 0;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const char *a, Hasher h) {\n\t\twhile (*a)\n\t\t\th.hash32(*(a++));\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (const char *a) HASH_TOP_LOOP_SND\n};\n\ntemplate <> struct hash_ops<char*> : hash_cstr_ops {};\n\nstruct hash_ptr_ops {\n\tstatic inline bool cmp(const void *a, const void *b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) {\n\t\treturn hash_ops<uintptr_t>::hash_into((uintptr_t)a, h);\n\t}\n\tHASH_TOP_LOOP_FST (const void *a) HASH_TOP_LOOP_SND\n};\n\nstruct hash_obj_ops {\n\tstatic inline bool cmp(const void *a, const void *b) {\n\t\treturn a == b;\n\t}\n\ttemplate<typename T>\n\t[[nodiscard]] static inline Hasher hash_into(const T *a, Hasher h) {\n\t\tif (a)\n\t\t\th = a->hash_into(h);\n\t\telse\n\t\t\th.eat(0);\n\t\treturn h;\n\t}\n\ttemplate<typename T>\n\tHASH_TOP_LOOP_FST (const T *a) HASH_TOP_LOOP_SND\n};\n/**\n * If you find yourself using this function, think hard\n * about if it's the right thing to do. Mixing finalized\n * hashes together with XORs or worse can destroy\n * desirable qualities of the hash function\n */\ntemplate<typename T>\n[[nodiscard]]\nHasher::hash_t run_hash(const T& obj) {\n\treturn hash_ops<T>::hash(obj).yield();\n}\n\n/** Refer to docs/source/yosys_internals/hashing.rst */\ntemplate<typename T>\n[[nodiscard]]\n[[deprecated]]\ninline unsigned int mkhash(const T &v) {\n\treturn (unsigned int) run_hash<T>(v);\n}\n\ntemplate<> struct hash_ops<std::monostate> {\n\tstatic inline bool cmp(std::monostate a, std::monostate b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::monostate, Hasher h) {\n\t\treturn h;\n\t}\n};\n\ntemplate<typename... T> struct hash_ops<std::variant<T...>> {\n\tstatic inline bool cmp(std::variant<T...> a, std::variant<T...> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::variant<T...> a, Hasher h) {\n\t\tstd::visit([& h](const auto &v) { h.eat(v); }, a);\n\t\th.eat(a.index());\n\t\treturn h;\n\t}\n};\n\ntemplate<typename T> struct hash_ops<std::optional<T>> {\n\tstatic inline bool cmp(std::optional<T> a, std::optional<T> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::optional<T> a, Hasher h) {\n\t\tif(a.has_value())\n\t\t\th.eat(*a);\n\t\telse\n\t\t\th.eat(0);\n\t\treturn h;\n\t}\n};\n\ninline unsigned int hashtable_size(unsigned int min_size)\n{\n\t// Primes as generated by https://oeis.org/A175953\n\tstatic std::vector<unsigned int> zero_and_some_primes = {\n\t\t0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,\n\t\t853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,\n\t\t12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,\n\t\t120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,\n\t\t897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,\n\t\t5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,\n\t\t25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,\n\t\t121590311, 151987889, 189984863, 237481091, 296851369, 371064217,\n\t\t463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113,\n\t\t1769372713, 2211715897, 2764644887, 3455806139\n\t};\n\n\tfor (auto p : zero_and_some_primes)\n\t\tif (p >= min_size) return p;\n\n\tif (sizeof(unsigned int) == 4)\n\t\tthrow std::length_error(\"hash table exceeded maximum size.\\nDesign is likely too large for yosys to handle, if possible try not to flatten the design.\");\n\n\tfor (auto p : zero_and_some_primes)\n\t\tif (100129 * p > min_size) return 100129 * p;\n\n\tthrow std::length_error(\"hash table exceeded maximum size.\");\n}\n\ntemplate<typename K, typename T, typename OPS = hash_ops<K>> class dict;\ntemplate<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;\ntemplate<typename K, typename OPS = hash_ops<K>> class pool;\ntemplate<typename K, typename OPS = hash_ops<K>> class mfp;\n\ntemplate<typename K, typename T, typename OPS>\nclass dict {\n\tstruct entry_t\n\t{\n\t\tstd::pair<K, T> udata;\n\t\tint next;\n\n\t\tentry_t() { }\n\t\tentry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }\n\t\tentry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }\n\t\tbool operator<(const entry_t &other) const { return udata.first < other.udata.first; }\n\t};\n\n\tstd::vector<int> hashtable;\n\tstd::vector<entry_t> entries;\n\tOPS ops;\n\n#ifdef NDEBUG\n\tstatic inline void do_assert(bool) { }\n#else\n\tstatic inline void do_assert(bool cond) {\n\t\tif (!cond) throw std::runtime_error(\"dict<> assert failed.\");\n\t}\n#endif\n\n\tHasher::hash_t do_hash(const K &key) const\n\t{\n\t\tHasher::hash_t hash = 0;\n\t\tif (!hashtable.empty())\n\t\t\thash = ops.hash(key).yield() % (unsigned int)(hashtable.size());\n\t\treturn hash;\n\t}\n\n\tvoid do_rehash()\n\t{\n\t\thashtable.clear();\n\t\thashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);\n\n\t\tfor (int i = 0; i < int(entries.size()); i++) {\n\t\t\tdo_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));\n\t\t\tHasher::hash_t hash = do_hash(entries[i].udata.first);\n\t\t\tentries[i].next = hashtable[hash];\n\t\t\thashtable[hash] = i;\n\t\t}\n\t}\n\n\tint do_erase(int index, Hasher::hash_t hash)\n\t{\n\t\tdo_assert(index < int(entries.size()));\n\t\tif (hashtable.empty() || index < 0)\n\t\t\treturn 0;\n\n\t\tint k = hashtable[hash];\n\t\tdo_assert(0 <= k && k < int(entries.size()));\n\n\t\tif (k == index) {\n\t\t\thashtable[hash] = entries[index].next;\n\t\t} else {\n\t\t\twhile (entries[k].next != index) {\n\t\t\t\tk = entries[k].next;\n\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t}\n\t\t\tentries[k].next = entries[index].next;\n\t\t}\n\n\t\tint back_idx = entries.size()-1;\n\n\t\tif (index != back_idx)\n\t\t{\n\t\t\tHasher::hash_t back_hash = do_hash(entries[back_idx].udata.first);\n\n\t\t\tk = hashtable[back_hash];\n\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\n\t\t\tif (k == back_idx) {\n\t\t\t\thashtable[back_hash] = index;\n\t\t\t} else {\n\t\t\t\twhile (entries[k].next != back_idx) {\n\t\t\t\t\tk = entries[k].next;\n\t\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t\t}\n\t\t\t\tentries[k].next = index;\n\t\t\t}\n\n\t\t\tentries[index] = std::move(entries[back_idx]);\n\t\t}\n\n\t\tentries.pop_back();\n\n\t\tif (entries.empty())\n\t\t\thashtable.clear();\n\n\t\treturn 1;\n\t}\n\n\tint do_lookup(const K &key, Hasher::hash_t &hash) const\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\tif (entries.size() * hashtable_size_trigger > hashtable.size()) {\n\t\t\t((dict*)this)->do_rehash();\n\t\t\thash = do_hash(key);\n\t\t}\n\n\t\tint index = hashtable[hash];\n\n\t\twhile (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {\n\t\t\tindex = entries[index].next;\n\t\t\tdo_assert(-1 <= index && index < int(entries.size()));\n\t\t}\n\n\t\treturn index;\n\t}\n\n\tint do_insert(const K &key, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(std::pair<K, T>(key, T()), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t} else {\n\t\t\tentries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(const std::pair<K, T> &value, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(value, -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(value.first);\n\t\t} else {\n\t\t\tentries.emplace_back(value, hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(std::pair<K, T> &&rvalue, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tauto key = rvalue.first;\n\t\t\tentries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t} else {\n\t\t\tentries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class dict;\n\tprotected:\n\t\tconst dict *ptr;\n\t\tint index;\n\t\tconst_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef std::pair<K, T> value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef std::pair<K, T>* pointer;\n\t\ttypedef std::pair<K, T>& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index--; return *this; }\n\t\tconst_iterator operator+=(int amt) { index -= amt; return *this; }\n\t\tbool operator<(const const_iterator &other) const { return index > other.index; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }\n\t};\n\n\tclass iterator\n\t{\n\t\tfriend class dict;\n\tprotected:\n\t\tdict *ptr;\n\t\tint index;\n\t\titerator(dict *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef std::pair<K, T> value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef std::pair<K, T>* pointer;\n\t\ttypedef std::pair<K, T>& reference;\n\t\titerator() { }\n\t\titerator operator++() { index--; return *this; }\n\t\titerator operator+=(int amt) { index -= amt; return *this; }\n\t\tbool operator<(const iterator &other) const { return index > other.index; }\n\t\tbool operator==(const iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const iterator &other) const { return index != other.index; }\n\t\tstd::pair<K, T> &operator*() { return ptr->entries[index].udata; }\n\t\tstd::pair<K, T> *operator->() { return &ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }\n\t\toperator const_iterator() const { return const_iterator(ptr, index); }\n\t};\n\n\tconstexpr dict()\n\t{\n\t}\n\n\tdict(const dict &other)\n\t{\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t}\n\n\tdict(dict &&other)\n\t{\n\t\tswap(other);\n\t}\n\n\tdict &operator=(const dict &other) {\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t\treturn *this;\n\t}\n\n\tdict &operator=(dict &&other) {\n\t\tclear();\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tdict(const std::initializer_list<std::pair<K, T>> &list)\n\t{\n\t\tfor (auto &it : list)\n\t\t\tinsert(it);\n\t}\n\n\ttemplate<class InputIterator>\n\tdict(InputIterator first, InputIterator last)\n\t{\n\t\tinsert(first, last);\n\t}\n\n\ttemplate<class InputIterator>\n\tvoid insert(InputIterator first, InputIterator last)\n\t{\n\t\tfor (; first != last; ++first)\n\t\t\tinsert(*first);\n\t}\n\n\tstd::pair<iterator, bool> insert(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(key, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(const std::pair<K, T> &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(value.first);\n\t\tint i = do_lookup(value.first, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(value, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rvalue.first);\n\t\tint i = do_lookup(rvalue.first, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K const &key, T const &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(key, value), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K const &key, T &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K &&rkey, T const &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(rkey);\n\t\tint i = do_lookup(rkey, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rkey);\n\t\tint i = do_lookup(rkey, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tint erase(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint index = do_lookup(key, hash);\n\t\treturn do_erase(index, hash);\n\t}\n\n\titerator erase(iterator it)\n\t{\n\t\tHasher::hash_t hash = do_hash(it->first);\n\t\tdo_erase(it.index, hash);\n\t\treturn ++it;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tint count(const K &key, const_iterator it) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i < 0 || i > it.index ? 0 : 1;\n\t}\n\n\titerator find(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn iterator(this, i);\n\t}\n\n\tconst_iterator find(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn const_iterator(this, i);\n\t}\n\n\tT& at(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"dict::at()\");\n\t\treturn entries[i].udata.second;\n\t}\n\n\tconst T& at(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"dict::at()\");\n\t\treturn entries[i].udata.second;\n\t}\n\n\tconst T& at(const K &key, const T &defval) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn defval;\n\t\treturn entries[i].udata.second;\n\t}\n\n\tT& operator[](const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\ti = do_insert(std::pair<K, T>(key, T()), hash);\n\t\treturn entries[i].udata.second;\n\t}\n\n\ttemplate<typename Compare = std::less<K>>\n\tvoid sort(Compare comp = Compare())\n\t{\n\t\tstd::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });\n\t\tdo_rehash();\n\t}\n\n\tvoid swap(dict &other)\n\t{\n\t\thashtable.swap(other.hashtable);\n\t\tentries.swap(other.entries);\n\t}\n\n\tbool operator==(const dict &other) const {\n\t\tif (size() != other.size())\n\t\t\treturn false;\n\t\tfor (auto &it : entries) {\n\t\t\tauto oit = other.find(it.udata.first);\n\t\t\tif (oit == other.end() || !(oit->second == it.udata.second))\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool operator!=(const dict &other) const {\n\t\treturn !operator==(other);\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\tfor (auto &it : entries) {\n\t\t\tHasher entry_hash;\n\t\t\tentry_hash.eat(it.udata.first);\n\t\t\tentry_hash.eat(it.udata.second);\n\t\t\th.commutative_eat(entry_hash.yield());\n\t\t}\n\t\th.eat(entries.size());\n\t\treturn h;\n\t}\n\n\tvoid reserve(size_t n) { entries.reserve(n); }\n\tsize_t size() const { return entries.size(); }\n\tbool empty() const { return entries.empty(); }\n\tvoid clear() { hashtable.clear(); entries.clear(); }\n\n\titerator begin() { return iterator(this, int(entries.size())-1); }\n\titerator element(int n) { return iterator(this, int(entries.size())-1-n); }\n\titerator end() { return iterator(nullptr, -1); }\n\n\tconst_iterator begin() const { return const_iterator(this, int(entries.size())-1); }\n\tconst_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }\n\tconst_iterator end() const { return const_iterator(nullptr, -1); }\n};\n\ntemplate<typename K, typename OPS>\nclass pool\n{\n\ttemplate<typename, int, typename> friend class idict;\n\nprotected:\n\tstruct entry_t\n\t{\n\t\tK udata;\n\t\tint next;\n\n\t\tentry_t() { }\n\t\tentry_t(const K &udata, int next) : udata(udata), next(next) { }\n\t\tentry_t(K &&udata, int next) : udata(std::move(udata)), next(next) { }\n\t};\n\n\tstd::vector<int> hashtable;\n\tstd::vector<entry_t> entries;\n\tOPS ops;\n\n#ifdef NDEBUG\n\tstatic inline void do_assert(bool) { }\n#else\n\tstatic inline void do_assert(bool cond) {\n\t\tif (!cond) throw std::runtime_error(\"pool<> assert failed.\");\n\t}\n#endif\n\n\tHasher::hash_t do_hash(const K &key) const\n\t{\n\t\tHasher::hash_t hash = 0;\n\t\tif (!hashtable.empty())\n\t\t\thash = ops.hash(key).yield() % (unsigned int)(hashtable.size());\n\t\treturn hash;\n\t}\n\n\tvoid do_rehash()\n\t{\n\t\thashtable.clear();\n\t\thashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);\n\n\t\tfor (int i = 0; i < int(entries.size()); i++) {\n\t\t\tdo_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));\n\t\t\tHasher::hash_t hash = do_hash(entries[i].udata);\n\t\t\tentries[i].next = hashtable[hash];\n\t\t\thashtable[hash] = i;\n\t\t}\n\t}\n\n\tint do_erase(int index, Hasher::hash_t hash)\n\t{\n\t\tdo_assert(index < int(entries.size()));\n\t\tif (hashtable.empty() || index < 0)\n\t\t\treturn 0;\n\n\t\tint k = hashtable[hash];\n\t\tif (k == index) {\n\t\t\thashtable[hash] = entries[index].next;\n\t\t} else {\n\t\t\twhile (entries[k].next != index) {\n\t\t\t\tk = entries[k].next;\n\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t}\n\t\t\tentries[k].next = entries[index].next;\n\t\t}\n\n\t\tint back_idx = entries.size()-1;\n\n\t\tif (index != back_idx)\n\t\t{\n\t\t\tHasher::hash_t back_hash = do_hash(entries[back_idx].udata);\n\n\t\t\tk = hashtable[back_hash];\n\t\t\tif (k == back_idx) {\n\t\t\t\thashtable[back_hash] = index;\n\t\t\t} else {\n\t\t\t\twhile (entries[k].next != back_idx) {\n\t\t\t\t\tk = entries[k].next;\n\t\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t\t}\n\t\t\t\tentries[k].next = index;\n\t\t\t}\n\n\t\t\tentries[index] = std::move(entries[back_idx]);\n\t\t}\n\n\t\tentries.pop_back();\n\n\t\tif (entries.empty())\n\t\t\thashtable.clear();\n\n\t\treturn 1;\n\t}\n\n\tint do_lookup(const K &key, Hasher::hash_t &hash) const\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\tif (entries.size() * hashtable_size_trigger > hashtable.size()) {\n\t\t\t((pool*)this)->do_rehash();\n\t\t\thash = do_hash(key);\n\t\t}\n\n\t\tint index = hashtable[hash];\n\n\t\twhile (index >= 0 && !ops.cmp(entries[index].udata, key)) {\n\t\t\tindex = entries[index].next;\n\t\t\tdo_assert(-1 <= index && index < int(entries.size()));\n\t\t}\n\n\t\treturn index;\n\t}\n\n\tint do_insert(const K &value, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(value, -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(value);\n\t\t} else {\n\t\t\tentries.emplace_back(value, hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(K &&rvalue, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(std::forward<K>(rvalue), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(rvalue);\n\t\t} else {\n\t\t\tentries.emplace_back(std::forward<K>(rvalue), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class pool;\n\tprotected:\n\t\tconst pool *ptr;\n\t\tint index;\n\t\tconst_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index--; return *this; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst K &operator*() const { return ptr->entries[index].udata; }\n\t\tconst K *operator->() const { return &ptr->entries[index].udata; }\n\t};\n\n\tclass iterator\n\t{\n\t\tfriend class pool;\n\tprotected:\n\t\tpool *ptr;\n\t\tint index;\n\t\titerator(pool *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\titerator() { }\n\t\titerator operator++() { index--; return *this; }\n\t\tbool operator==(const iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const iterator &other) const { return index != other.index; }\n\t\tK &operator*() { return ptr->entries[index].udata; }\n\t\tK *operator->() { return &ptr->entries[index].udata; }\n\t\tconst K &operator*() const { return ptr->entries[index].udata; }\n\t\tconst K *operator->() const { return &ptr->entries[index].udata; }\n\t\toperator const_iterator() const { return const_iterator(ptr, index); }\n\t};\n\n\tconstexpr pool()\n\t{\n\t}\n\n\tpool(const pool &other)\n\t{\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t}\n\n\tpool(pool &&other)\n\t{\n\t\tswap(other);\n\t}\n\n\tpool &operator=(const pool &other) {\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t\treturn *this;\n\t}\n\n\tpool &operator=(pool &&other) {\n\t\tclear();\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tpool(const std::initializer_list<K> &list)\n\t{\n\t\tfor (auto &it : list)\n\t\t\tinsert(it);\n\t}\n\n\ttemplate<class InputIterator>\n\tpool(InputIterator first, InputIterator last)\n\t{\n\t\tinsert(first, last);\n\t}\n\n\ttemplate<class InputIterator>\n\tvoid insert(InputIterator first, InputIterator last)\n\t{\n\t\tfor (; first != last; ++first)\n\t\t\tinsert(*first);\n\t}\n\n\tstd::pair<iterator, bool> insert(const K &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(value);\n\t\tint i = do_lookup(value, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(value, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(K &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rvalue);\n\t\tint i = do_lookup(rvalue, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::forward<K>(rvalue), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\ttemplate<typename... Args>\n\tstd::pair<iterator, bool> emplace(Args&&... args)\n\t{\n\t\treturn insert(K(std::forward<Args>(args)...));\n\t}\n\n\tint erase(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint index = do_lookup(key, hash);\n\t\treturn do_erase(index, hash);\n\t}\n\n\titerator erase(iterator it)\n\t{\n\t\tHasher::hash_t hash = do_hash(*it);\n\t\tdo_erase(it.index, hash);\n\t\treturn ++it;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tint count(const K &key, const_iterator it) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i < 0 || i > it.index ? 0 : 1;\n\t}\n\n\titerator find(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn iterator(this, i);\n\t}\n\n\tconst_iterator find(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn const_iterator(this, i);\n\t}\n\n\tbool operator[](const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i >= 0;\n\t}\n\n\ttemplate<typename Compare = std::less<K>>\n\tvoid sort(Compare comp = Compare())\n\t{\n\t\tstd::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });\n\t\tdo_rehash();\n\t}\n\n\tK pop()\n\t{\n\t\titerator it = begin();\n\t\tK ret = *it;\n\t\terase(it);\n\t\treturn ret;\n\t}\n\n\tvoid swap(pool &other)\n\t{\n\t\thashtable.swap(other.hashtable);\n\t\tentries.swap(other.entries);\n\t}\n\n\tbool operator==(const pool &other) const {\n\t\tif (size() != other.size())\n\t\t\treturn false;\n\t\tfor (auto &it : entries)\n\t\t\tif (!other.count(it.udata))\n\t\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tbool operator!=(const pool &other) const {\n\t\treturn !operator==(other);\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\tfor (auto &it : entries) {\n\t\t\th.commutative_eat(ops.hash(it.udata).yield());\n\t\t}\n\t\th.eat(entries.size());\n\t\treturn h;\n\t}\n\n\tvoid reserve(size_t n) { entries.reserve(n); }\n\tsize_t size() const { return entries.size(); }\n\tbool empty() const { return entries.empty(); }\n\tvoid clear() { hashtable.clear(); entries.clear(); }\n\n\titerator begin() { return iterator(this, int(entries.size())-1); }\n\titerator element(int n) { return iterator(this, int(entries.size())-1-n); }\n\titerator end() { return iterator(nullptr, -1); }\n\n\tconst_iterator begin() const { return const_iterator(this, int(entries.size())-1); }\n\tconst_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }\n\tconst_iterator end() const { return const_iterator(nullptr, -1); }\n};\n\ntemplate<typename K, int offset, typename OPS>\nclass idict\n{\n\tpool<K, OPS> database;\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class idict;\n\tprotected:\n\t\tconst idict &container;\n\t\tint index;\n\t\tconst_iterator(const idict &container, int index) : container(container), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index++; return *this; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst K &operator*() const { return container[index]; }\n\t\tconst K *operator->() const { return &container[index]; }\n\t};\n\n\tconstexpr idict()\n\t{\n\t}\n\n\tint operator()(const K &key)\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\ti = database.do_insert(key, hash);\n\t\treturn i + offset;\n\t}\n\n\tint at(const K &key) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"idict::at()\");\n\t\treturn i + offset;\n\t}\n\n\tint at(const K &key, int defval) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn defval;\n\t\treturn i + offset;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tvoid expect(const K &key, int i)\n\t{\n\t\tint j = (*this)(key);\n\t\tif (i != j)\n\t\t\tthrow std::out_of_range(\"idict::expect()\");\n\t}\n\n\tconst K &operator[](int index) const\n\t{\n\t\treturn database.entries.at(index - offset).udata;\n\t}\n\n\tvoid swap(idict &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t}\n\n\tvoid reserve(size_t n) { database.reserve(n); }\n\tsize_t size() const { return database.size(); }\n\tbool empty() const { return database.empty(); }\n\tvoid clear() { database.clear(); }\n\n\tconst_iterator begin() const { return const_iterator(*this, offset); }\n\tconst_iterator element(int n) const { return const_iterator(*this, n); }\n\tconst_iterator end() const { return const_iterator(*this, offset + size()); }\n};\n\n/**\n * Union-find data structure with a promotion method\n * mfp stands for \"merge, find, promote\"\n * i-prefixed methods operate on indices in parents\n*/\ntemplate<typename K, typename OPS>\nclass mfp\n{\n\tmutable idict<K, 0, OPS> database;\n\tmutable std::vector<int> parents;\n\npublic:\n\ttypedef typename idict<K, 0>::const_iterator const_iterator;\n\n\tconstexpr mfp()\n\t{\n\t}\n\n\t// Finds a given element's index. If it isn't in the data structure,\n\t// it is added as its own set\n\tint operator()(const K &key) const\n\t{\n\t\tint i = database(key);\n\t\t// If the lookup caused the database to grow,\n\t\t// also add a corresponding entry in parents initialized to -1 (no parent)\n\t\tparents.resize(database.size(), -1);\n\t\treturn i;\n\t}\n\n\t// Finds an element at given index\n\tconst K &operator[](int index) const\n\t{\n\t\treturn database[index];\n\t}\n\n\tint ifind(int i) const\n\t{\n\t\tint p = i, k = i;\n\n\t\twhile (parents[p] != -1)\n\t\t\tp = parents[p];\n\n\t\t// p is now the representative of i\n\t\t// Now we traverse from i up to the representative again\n\t\t// and make p the parent of all the nodes along the way.\n\t\t// This is a side effect and doesn't affect the return value.\n\t\t// It speeds up future find operations\n\t\twhile (k != p) {\n\t\t\tint next_k = parents[k];\n\t\t\tparents[k] = p;\n\t\t\tk = next_k;\n\t\t}\n\n\t\treturn p;\n\t}\n\n\t// Merge sets if the given indices belong to different sets\n\tvoid imerge(int i, int j)\n\t{\n\t\ti = ifind(i);\n\t\tj = ifind(j);\n\n\t\tif (i != j)\n\t\t\tparents[i] = j;\n\t}\n\n\tvoid ipromote(int i)\n\t{\n\t\tint k = i;\n\n\t\twhile (k != -1) {\n\t\t\tint next_k = parents[k];\n\t\t\tparents[k] = i;\n\t\t\tk = next_k;\n\t\t}\n\n\t\tparents[i] = -1;\n\t}\n\n\tint lookup(const K &a) const\n\t{\n\t\treturn ifind((*this)(a));\n\t}\n\n\tconst K &find(const K &a) const\n\t{\n\t\tint i = database.at(a, -1);\n\t\tif (i < 0)\n\t\t\treturn a;\n\t\treturn (*this)[ifind(i)];\n\t}\n\n\tvoid merge(const K &a, const K &b)\n\t{\n\t\timerge((*this)(a), (*this)(b));\n\t}\n\n\tvoid promote(const K &a)\n\t{\n\t\tint i = database.at(a, -1);\n\t\tif (i >= 0)\n\t\t\tipromote(i);\n\t}\n\n\tvoid swap(mfp &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t\tparents.swap(other.parents);\n\t}\n\n\tvoid reserve(size_t n) { database.reserve(n); }\n\tsize_t size() const { return database.size(); }\n\tbool empty() const { return database.empty(); }\n\tvoid clear() { database.clear(); parents.clear(); }\n\n\tconst_iterator begin() const { return database.begin(); }\n\tconst_iterator element(int n) const { return database.element(n); }\n\tconst_iterator end() const { return database.end(); }\n};\n\n} /* namespace hashlib */\n\n#endif\n",
|
|
176
|
+
"hashlib.h": "// This is free and unencumbered software released into the public domain.\n//\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// -------------------------------------------------------\n// Written by Claire Xenia Wolf <claire@yosyshq.com> in 2014\n// -------------------------------------------------------\n\n#ifndef HASHLIB_H\n#define HASHLIB_H\n\n#include <stdexcept>\n#include <algorithm>\n#include <optional>\n#include <string>\n#include <variant>\n#include <vector>\n#include <type_traits>\n#include <stdint.h>\n\n#define YS_HASHING_VERSION 1\n\nnamespace hashlib {\n\n/**\n * HASHING\n *\n * Also refer to docs/source/yosys_internals/hashing.rst\n *\n * The Hasher knows how to hash 32 and 64-bit integers. That's it.\n * In the future, it could be expanded to do vectors with SIMD.\n *\n * The Hasher doesn't know how to hash common standard containers\n * and compositions. However, hashlib provides centralized wrappers.\n *\n * Hashlib doesn't know how to hash silly Yosys-specific types.\n * Hashlib doesn't depend on Yosys and can be used standalone.\n * Please don't use hashlib standalone for new projects.\n * Never directly include kernel/hashlib.h in Yosys code.\n * Instead include kernel/yosys_common.h\n *\n * The hash_ops type is now always left to its default value, derived\n * from templated functions through SFINAE. Providing custom ops is\n * still supported.\n *\n * HASH TABLES\n *\n * We implement associative data structures with separate chaining.\n * Linked lists use integers into the indirection hashtable array\n * instead of pointers.\n */\n\nconst int hashtable_size_trigger = 2;\nconst int hashtable_size_factor = 3;\n\nnamespace legacy {\n\tinline uint32_t djb2_add(uint32_t a, uint32_t b) {\n\t\treturn ((a << 5) + a) + b;\n\t}\n};\n\ntemplate<typename T>\nstruct hash_ops;\n\ninline unsigned int mkhash_xorshift(unsigned int a) {\n\tif (sizeof(a) == 4) {\n\t\ta ^= a << 13;\n\t\ta ^= a >> 17;\n\t\ta ^= a << 5;\n\t} else if (sizeof(a) == 8) {\n\t\ta ^= a << 13;\n\t\ta ^= a >> 7;\n\t\ta ^= a << 17;\n\t} else\n\t\tthrow std::runtime_error(\"mkhash_xorshift() only implemented for 32 bit and 64 bit ints\");\n\treturn a;\n}\n\nclass HasherDJB32 {\npublic:\n\tusing hash_t = uint32_t;\n\n\tHasherDJB32() {\n\t\t// traditionally 5381 is used as starting value for the djb2 hash\n\t\tstate = 5381;\n\t}\n\tstatic void set_fudge(hash_t f) {\n\t\tfudge = f;\n\t}\n\nprivate:\n\tuint32_t state;\n\tstatic uint32_t fudge;\n\t// The XOR version of DJB2\n\t[[nodiscard]]\n\tstatic uint32_t djb2_xor(uint32_t a, uint32_t b) {\n\t\tuint32_t hash = ((a << 5) + a) ^ b;\n\t\treturn hash;\n\t}\n\tpublic:\n\tvoid hash32(uint32_t i) {\n\t\tstate = djb2_xor(i, state);\n\t\tstate = mkhash_xorshift(fudge ^ state);\n\t\treturn;\n\t}\n\tvoid hash64(uint64_t i) {\n\t\tstate = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state);\n\t\tstate = djb2_xor((uint32_t)(i >> 32ULL), state);\n\t\tstate = mkhash_xorshift(fudge ^ state);\n\t\treturn;\n\t}\n\t[[nodiscard]]\n\thash_t yield() {\n\t\treturn (hash_t)state;\n\t}\n\n\ttemplate<typename T>\n\tvoid eat(T&& t) {\n\t\t*this = hash_ops<std::remove_cv_t<std::remove_reference_t<T>>>::hash_into(std::forward<T>(t), *this);\n\t}\n\n\ttemplate<typename T>\n\tvoid eat(const T& t) {\n\t\t*this = hash_ops<T>::hash_into(t, *this);\n\t}\n\n\tvoid commutative_eat(hash_t t) {\n\t\tstate ^= t;\n\t}\n\n\tvoid force(hash_t new_state) {\n\t\tstate = new_state;\n\t}\n};\n\nusing Hasher = HasherDJB32;\n\n// Boilerplate compressor for trivially implementing\n// top-level hash method with hash_into\n#define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash\n#define HASH_TOP_LOOP_SND { \\\n\tHasher h; \\\n\th = hash_into(a, h); \\\n\treturn h; \\\n}\n\ntemplate<typename T>\nstruct hash_ops {\n\tstatic inline bool cmp(const T &a, const T &b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const T &a, Hasher h) {\n\t\tif constexpr (std::is_integral_v<T>) {\n\t\t\tstatic_assert(sizeof(T) <= sizeof(uint64_t));\n\t\t\tif (sizeof(T) == sizeof(uint64_t))\n\t\t\t\th.hash64(a);\n\t\t\telse\n\t\t\t\th.hash32(a);\n\t\t\treturn h;\n\t\t} else if constexpr (std::is_enum_v<T>) {\n\t\t\tusing u_type = std::underlying_type_t<T>;\n\t\t\treturn hash_ops<u_type>::hash_into((u_type) a, h);\n\t\t} else if constexpr (std::is_pointer_v<T>) {\n\t\t\treturn hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);\n\t\t} else if constexpr (std::is_same_v<T, std::string>) {\n\t\t\tfor (auto c : a)\n\t\t\t\th.hash32(c);\n\t\t\treturn h;\n\t\t} else {\n\t\t\treturn a.hash_into(h);\n\t\t}\n\t}\n\tHASH_TOP_LOOP_FST (const T &a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {\n\tstatic inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {\n\t\th = hash_ops<P>::hash_into(a.first, h);\n\t\th = hash_ops<Q>::hash_into(a.second, h);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::pair<P, Q> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename... T> struct hash_ops<std::tuple<T...>> {\n\tstatic inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) {\n\t\treturn a == b;\n\t}\n\ttemplate<size_t I = 0>\n\tstatic inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {\n\t\treturn h;\n\t}\n\ttemplate<size_t I = 0>\n\tstatic inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {\n\t\ttypedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;\n\t\th = hash_into<I+1>(a, h);\n\t\th = element_ops_t::hash_into(std::get<I>(a), h);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::tuple<T...> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename T> struct hash_ops<std::vector<T>> {\n\tstatic inline bool cmp(std::vector<T> a, std::vector<T> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::vector<T> a, Hasher h) {\n\t\th.eat((uint32_t)a.size());\n\t\tfor (auto k : a)\n\t\t\th.eat(k);\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (std::vector<T> a) HASH_TOP_LOOP_SND\n};\n\ntemplate<typename T, size_t N> struct hash_ops<std::array<T, N>> {\n static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {\n return a == b;\n }\n [[nodiscard]] static inline Hasher hash_into(std::array<T, N> a, Hasher h) {\n for (const auto& k : a)\n h = hash_ops<T>::hash_into(k, h);\n return h;\n }\n\tHASH_TOP_LOOP_FST (std::array<T, N> a) HASH_TOP_LOOP_SND\n};\n\nstruct hash_cstr_ops {\n\tstatic inline bool cmp(const char *a, const char *b) {\n\t\treturn strcmp(a, b) == 0;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const char *a, Hasher h) {\n\t\twhile (*a)\n\t\t\th.hash32(*(a++));\n\t\treturn h;\n\t}\n\tHASH_TOP_LOOP_FST (const char *a) HASH_TOP_LOOP_SND\n};\n\ntemplate <> struct hash_ops<char*> : hash_cstr_ops {};\n\nstruct hash_ptr_ops {\n\tstatic inline bool cmp(const void *a, const void *b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) {\n\t\treturn hash_ops<uintptr_t>::hash_into((uintptr_t)a, h);\n\t}\n\tHASH_TOP_LOOP_FST (const void *a) HASH_TOP_LOOP_SND\n};\n\nstruct hash_obj_ops {\n\tstatic inline bool cmp(const void *a, const void *b) {\n\t\treturn a == b;\n\t}\n\ttemplate<typename T>\n\t[[nodiscard]] static inline Hasher hash_into(const T *a, Hasher h) {\n\t\tif (a)\n\t\t\th = a->hash_into(h);\n\t\telse\n\t\t\th.eat(0);\n\t\treturn h;\n\t}\n\ttemplate<typename T>\n\tHASH_TOP_LOOP_FST (const T *a) HASH_TOP_LOOP_SND\n};\n/**\n * If you find yourself using this function, think hard\n * about if it's the right thing to do. Mixing finalized\n * hashes together with XORs or worse can destroy\n * desirable qualities of the hash function\n */\ntemplate<typename T>\n[[nodiscard]]\nHasher::hash_t run_hash(const T& obj) {\n\treturn hash_ops<T>::hash(obj).yield();\n}\n\n/** Refer to docs/source/yosys_internals/hashing.rst */\ntemplate<typename T>\n[[nodiscard]]\n[[deprecated]]\ninline unsigned int mkhash(const T &v) {\n\treturn (unsigned int) run_hash<T>(v);\n}\n\ntemplate<> struct hash_ops<std::monostate> {\n\tstatic inline bool cmp(std::monostate a, std::monostate b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::monostate, Hasher h) {\n\t\treturn h;\n\t}\n};\n\ntemplate<typename... T> struct hash_ops<std::variant<T...>> {\n\tstatic inline bool cmp(std::variant<T...> a, std::variant<T...> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::variant<T...> a, Hasher h) {\n\t\tstd::visit([& h](const auto &v) { h.eat(v); }, a);\n\t\th.eat(a.index());\n\t\treturn h;\n\t}\n};\n\ntemplate<typename T> struct hash_ops<std::optional<T>> {\n\tstatic inline bool cmp(std::optional<T> a, std::optional<T> b) {\n\t\treturn a == b;\n\t}\n\t[[nodiscard]] static inline Hasher hash_into(std::optional<T> a, Hasher h) {\n\t\tif(a.has_value())\n\t\t\th.eat(*a);\n\t\telse\n\t\t\th.eat(0);\n\t\treturn h;\n\t}\n};\n\ninline unsigned int hashtable_size(unsigned int min_size)\n{\n\t// Primes as generated by https://oeis.org/A175953\n\tstatic std::vector<unsigned int> zero_and_some_primes = {\n\t\t0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,\n\t\t853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,\n\t\t12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,\n\t\t120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,\n\t\t897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,\n\t\t5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,\n\t\t25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,\n\t\t121590311, 151987889, 189984863, 237481091, 296851369, 371064217,\n\t\t463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113,\n\t\t1769372713, 2211715897, 2764644887, 3455806139\n\t};\n\n\tfor (auto p : zero_and_some_primes)\n\t\tif (p >= min_size) return p;\n\n\tif (sizeof(unsigned int) == 4)\n\t\tthrow std::length_error(\"hash table exceeded maximum size.\\nDesign is likely too large for yosys to handle, if possible try not to flatten the design.\");\n\n\tfor (auto p : zero_and_some_primes)\n\t\tif (100129 * p > min_size) return 100129 * p;\n\n\tthrow std::length_error(\"hash table exceeded maximum size.\");\n}\n\ntemplate<typename K, typename T, typename OPS = hash_ops<K>> class dict;\ntemplate<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;\ntemplate<typename K, typename OPS = hash_ops<K>> class pool;\ntemplate<typename K, typename OPS = hash_ops<K>> class mfp;\n\ntemplate<typename K, typename T, typename OPS>\nclass dict {\n\tstruct entry_t\n\t{\n\t\tstd::pair<K, T> udata;\n\t\tint next;\n\n\t\tentry_t() { }\n\t\tentry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }\n\t\tentry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }\n\t\tbool operator<(const entry_t &other) const { return udata.first < other.udata.first; }\n\t};\n\n\tstd::vector<int> hashtable;\n\tstd::vector<entry_t> entries;\n\tOPS ops;\n\n#ifdef NDEBUG\n\tstatic inline void do_assert(bool) { }\n#else\n\tstatic inline void do_assert(bool cond) {\n\t\tif (!cond) throw std::runtime_error(\"dict<> assert failed.\");\n\t}\n#endif\n\n\tHasher::hash_t do_hash(const K &key) const\n\t{\n\t\tHasher::hash_t hash = 0;\n\t\tif (!hashtable.empty())\n\t\t\thash = ops.hash(key).yield() % (unsigned int)(hashtable.size());\n\t\treturn hash;\n\t}\n\n\tvoid do_rehash()\n\t{\n\t\thashtable.clear();\n\t\thashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);\n\n\t\tfor (int i = 0; i < int(entries.size()); i++) {\n\t\t\tdo_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));\n\t\t\tHasher::hash_t hash = do_hash(entries[i].udata.first);\n\t\t\tentries[i].next = hashtable[hash];\n\t\t\thashtable[hash] = i;\n\t\t}\n\t}\n\n\tint do_erase(int index, Hasher::hash_t hash)\n\t{\n\t\tdo_assert(index < int(entries.size()));\n\t\tif (hashtable.empty() || index < 0)\n\t\t\treturn 0;\n\n\t\tint k = hashtable[hash];\n\t\tdo_assert(0 <= k && k < int(entries.size()));\n\n\t\tif (k == index) {\n\t\t\thashtable[hash] = entries[index].next;\n\t\t} else {\n\t\t\twhile (entries[k].next != index) {\n\t\t\t\tk = entries[k].next;\n\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t}\n\t\t\tentries[k].next = entries[index].next;\n\t\t}\n\n\t\tint back_idx = entries.size()-1;\n\n\t\tif (index != back_idx)\n\t\t{\n\t\t\tHasher::hash_t back_hash = do_hash(entries[back_idx].udata.first);\n\n\t\t\tk = hashtable[back_hash];\n\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\n\t\t\tif (k == back_idx) {\n\t\t\t\thashtable[back_hash] = index;\n\t\t\t} else {\n\t\t\t\twhile (entries[k].next != back_idx) {\n\t\t\t\t\tk = entries[k].next;\n\t\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t\t}\n\t\t\t\tentries[k].next = index;\n\t\t\t}\n\n\t\t\tentries[index] = std::move(entries[back_idx]);\n\t\t}\n\n\t\tentries.pop_back();\n\n\t\tif (entries.empty())\n\t\t\thashtable.clear();\n\n\t\treturn 1;\n\t}\n\n\tint do_lookup(const K &key, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\tif (entries.size() * hashtable_size_trigger > hashtable.size()) {\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t}\n\n\t\treturn do_lookup_internal(key, hash);\n\t}\n\n\tint do_lookup_internal(const K &key, Hasher::hash_t hash) const\n\t{\n\t\tint index = hashtable[hash];\n\n\t\twhile (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {\n\t\t\tindex = entries[index].next;\n\t\t\tdo_assert(-1 <= index && index < int(entries.size()));\n\t\t}\n\n\t\treturn index;\n\t}\n\n\tint do_lookup_no_rehash(const K &key, Hasher::hash_t hash) const\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\treturn do_lookup_internal(key, hash);\n\t}\n\n\tint do_insert(const K &key, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(std::pair<K, T>(key, T()), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t} else {\n\t\t\tentries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(const std::pair<K, T> &value, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(value, -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(value.first);\n\t\t} else {\n\t\t\tentries.emplace_back(value, hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(std::pair<K, T> &&rvalue, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tauto key = rvalue.first;\n\t\t\tentries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t} else {\n\t\t\tentries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class dict;\n\tprotected:\n\t\tconst dict *ptr;\n\t\tint index;\n\t\tconst_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef std::pair<K, T> value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef std::pair<K, T>* pointer;\n\t\ttypedef std::pair<K, T>& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index--; return *this; }\n\t\tconst_iterator operator+=(int amt) { index -= amt; return *this; }\n\t\tbool operator<(const const_iterator &other) const { return index > other.index; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }\n\t};\n\n\tclass iterator\n\t{\n\t\tfriend class dict;\n\tprotected:\n\t\tdict *ptr;\n\t\tint index;\n\t\titerator(dict *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef std::pair<K, T> value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef std::pair<K, T>* pointer;\n\t\ttypedef std::pair<K, T>& reference;\n\t\titerator() { }\n\t\titerator operator++() { index--; return *this; }\n\t\titerator operator+=(int amt) { index -= amt; return *this; }\n\t\tbool operator<(const iterator &other) const { return index > other.index; }\n\t\tbool operator==(const iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const iterator &other) const { return index != other.index; }\n\t\tstd::pair<K, T> &operator*() { return ptr->entries[index].udata; }\n\t\tstd::pair<K, T> *operator->() { return &ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }\n\t\tconst std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }\n\t\toperator const_iterator() const { return const_iterator(ptr, index); }\n\t};\n\n\tconstexpr dict()\n\t{\n\t}\n\n\tdict(const dict &other)\n\t{\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t}\n\n\tdict(dict &&other)\n\t{\n\t\tswap(other);\n\t}\n\n\tdict &operator=(const dict &other) {\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t\treturn *this;\n\t}\n\n\tdict &operator=(dict &&other) {\n\t\tclear();\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tdict(const std::initializer_list<std::pair<K, T>> &list)\n\t{\n\t\tfor (auto &it : list)\n\t\t\tinsert(it);\n\t}\n\n\ttemplate<class InputIterator>\n\tdict(InputIterator first, InputIterator last)\n\t{\n\t\tinsert(first, last);\n\t}\n\n\ttemplate<class InputIterator>\n\tvoid insert(InputIterator first, InputIterator last)\n\t{\n\t\tfor (; first != last; ++first)\n\t\t\tinsert(*first);\n\t}\n\n\tstd::pair<iterator, bool> insert(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(key, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(const std::pair<K, T> &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(value.first);\n\t\tint i = do_lookup(value.first, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(value, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rvalue.first);\n\t\tint i = do_lookup(rvalue.first, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K const &key, T const &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(key, value), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K const &key, T &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K &&rkey, T const &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(rkey);\n\t\tint i = do_lookup(rkey, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rkey);\n\t\tint i = do_lookup(rkey, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tint erase(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint index = do_lookup(key, hash);\n\t\treturn do_erase(index, hash);\n\t}\n\n\titerator erase(iterator it)\n\t{\n\t\tHasher::hash_t hash = do_hash(it->first);\n\t\tdo_erase(it.index, hash);\n\t\treturn ++it;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tint count(const K &key, const_iterator it) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\treturn i < 0 || i > it.index ? 0 : 1;\n\t}\n\n\titerator find(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn iterator(this, i);\n\t}\n\n\tconst_iterator find(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn const_iterator(this, i);\n\t}\n\n\tT& at(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"dict::at()\");\n\t\treturn entries[i].udata.second;\n\t}\n\n\tconst T& at(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"dict::at()\");\n\t\treturn entries[i].udata.second;\n\t}\n\n\tconst T& at(const K &key, const T &defval) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\treturn defval;\n\t\treturn entries[i].udata.second;\n\t}\n\n\tT& operator[](const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\ti = do_insert(std::pair<K, T>(key, T()), hash);\n\t\treturn entries[i].udata.second;\n\t}\n\n\ttemplate<typename Compare = std::less<K>>\n\tvoid sort(Compare comp = Compare())\n\t{\n\t\tstd::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });\n\t\tdo_rehash();\n\t}\n\n\tvoid swap(dict &other)\n\t{\n\t\thashtable.swap(other.hashtable);\n\t\tentries.swap(other.entries);\n\t}\n\n\tbool operator==(const dict &other) const {\n\t\tif (size() != other.size())\n\t\t\treturn false;\n\t\tfor (auto &it : entries) {\n\t\t\tauto oit = other.find(it.udata.first);\n\t\t\tif (oit == other.end() || !(oit->second == it.udata.second))\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool operator!=(const dict &other) const {\n\t\treturn !operator==(other);\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\tfor (auto &it : entries) {\n\t\t\tHasher entry_hash;\n\t\t\tentry_hash.eat(it.udata.first);\n\t\t\tentry_hash.eat(it.udata.second);\n\t\t\th.commutative_eat(entry_hash.yield());\n\t\t}\n\t\th.eat(entries.size());\n\t\treturn h;\n\t}\n\n\tvoid reserve(size_t n) { entries.reserve(n); }\n\tsize_t size() const { return entries.size(); }\n\tbool empty() const { return entries.empty(); }\n\tvoid clear() { hashtable.clear(); entries.clear(); }\n\n\titerator begin() { return iterator(this, int(entries.size())-1); }\n\titerator element(int n) { return iterator(this, int(entries.size())-1-n); }\n\titerator end() { return iterator(nullptr, -1); }\n\n\tconst_iterator begin() const { return const_iterator(this, int(entries.size())-1); }\n\tconst_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }\n\tconst_iterator end() const { return const_iterator(nullptr, -1); }\n};\n\ntemplate<typename K, typename OPS>\nclass pool\n{\n\ttemplate<typename, int, typename> friend class idict;\n\nprotected:\n\tstruct entry_t\n\t{\n\t\tK udata;\n\t\tint next;\n\n\t\tentry_t() { }\n\t\tentry_t(const K &udata, int next) : udata(udata), next(next) { }\n\t\tentry_t(K &&udata, int next) : udata(std::move(udata)), next(next) { }\n\t};\n\n\tstd::vector<int> hashtable;\n\tstd::vector<entry_t> entries;\n\tOPS ops;\n\n#ifdef NDEBUG\n\tstatic inline void do_assert(bool) { }\n#else\n\tstatic inline void do_assert(bool cond) {\n\t\tif (!cond) throw std::runtime_error(\"pool<> assert failed.\");\n\t}\n#endif\n\n\tHasher::hash_t do_hash(const K &key) const\n\t{\n\t\tHasher::hash_t hash = 0;\n\t\tif (!hashtable.empty())\n\t\t\thash = ops.hash(key).yield() % (unsigned int)(hashtable.size());\n\t\treturn hash;\n\t}\n\n\tvoid do_rehash()\n\t{\n\t\thashtable.clear();\n\t\thashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1);\n\n\t\tfor (int i = 0; i < int(entries.size()); i++) {\n\t\t\tdo_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));\n\t\t\tHasher::hash_t hash = do_hash(entries[i].udata);\n\t\t\tentries[i].next = hashtable[hash];\n\t\t\thashtable[hash] = i;\n\t\t}\n\t}\n\n\tint do_erase(int index, Hasher::hash_t hash)\n\t{\n\t\tdo_assert(index < int(entries.size()));\n\t\tif (hashtable.empty() || index < 0)\n\t\t\treturn 0;\n\n\t\tint k = hashtable[hash];\n\t\tif (k == index) {\n\t\t\thashtable[hash] = entries[index].next;\n\t\t} else {\n\t\t\twhile (entries[k].next != index) {\n\t\t\t\tk = entries[k].next;\n\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t}\n\t\t\tentries[k].next = entries[index].next;\n\t\t}\n\n\t\tint back_idx = entries.size()-1;\n\n\t\tif (index != back_idx)\n\t\t{\n\t\t\tHasher::hash_t back_hash = do_hash(entries[back_idx].udata);\n\n\t\t\tk = hashtable[back_hash];\n\t\t\tif (k == back_idx) {\n\t\t\t\thashtable[back_hash] = index;\n\t\t\t} else {\n\t\t\t\twhile (entries[k].next != back_idx) {\n\t\t\t\t\tk = entries[k].next;\n\t\t\t\t\tdo_assert(0 <= k && k < int(entries.size()));\n\t\t\t\t}\n\t\t\t\tentries[k].next = index;\n\t\t\t}\n\n\t\t\tentries[index] = std::move(entries[back_idx]);\n\t\t}\n\n\t\tentries.pop_back();\n\n\t\tif (entries.empty())\n\t\t\thashtable.clear();\n\n\t\treturn 1;\n\t}\n\n\tint do_lookup(const K &key, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\tif (entries.size() * hashtable_size_trigger > hashtable.size()) {\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(key);\n\t\t}\n\n\t\treturn do_lookup_internal(key, hash);\n\t}\n\n\tint do_lookup_internal(const K &key, Hasher::hash_t hash) const\n\t{\n\t\tint index = hashtable[hash];\n\n\t\twhile (index >= 0 && !ops.cmp(entries[index].udata, key)) {\n\t\t\tindex = entries[index].next;\n\t\t\tdo_assert(-1 <= index && index < int(entries.size()));\n\t\t}\n\n\t\treturn index;\n\t}\n\n\tint do_lookup_no_rehash(const K &key, Hasher::hash_t hash) const\n\t{\n\t\tif (hashtable.empty())\n\t\t\treturn -1;\n\n\t\treturn do_lookup_internal(key, hash);\n\t}\n\n\tint do_insert(const K &value, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(value, -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(value);\n\t\t} else {\n\t\t\tentries.emplace_back(value, hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\n\tint do_insert(K &&rvalue, Hasher::hash_t &hash)\n\t{\n\t\tif (hashtable.empty()) {\n\t\t\tentries.emplace_back(std::forward<K>(rvalue), -1);\n\t\t\tdo_rehash();\n\t\t\thash = do_hash(rvalue);\n\t\t} else {\n\t\t\tentries.emplace_back(std::forward<K>(rvalue), hashtable[hash]);\n\t\t\thashtable[hash] = entries.size() - 1;\n\t\t}\n\t\treturn entries.size() - 1;\n\t}\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class pool;\n\tprotected:\n\t\tconst pool *ptr;\n\t\tint index;\n\t\tconst_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index--; return *this; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst K &operator*() const { return ptr->entries[index].udata; }\n\t\tconst K *operator->() const { return &ptr->entries[index].udata; }\n\t};\n\n\tclass iterator\n\t{\n\t\tfriend class pool;\n\tprotected:\n\t\tpool *ptr;\n\t\tint index;\n\t\titerator(pool *ptr, int index) : ptr(ptr), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\titerator() { }\n\t\titerator operator++() { index--; return *this; }\n\t\tbool operator==(const iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const iterator &other) const { return index != other.index; }\n\t\tK &operator*() { return ptr->entries[index].udata; }\n\t\tK *operator->() { return &ptr->entries[index].udata; }\n\t\tconst K &operator*() const { return ptr->entries[index].udata; }\n\t\tconst K *operator->() const { return &ptr->entries[index].udata; }\n\t\toperator const_iterator() const { return const_iterator(ptr, index); }\n\t};\n\n\tconstexpr pool()\n\t{\n\t}\n\n\tpool(const pool &other)\n\t{\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t}\n\n\tpool(pool &&other)\n\t{\n\t\tswap(other);\n\t}\n\n\tpool &operator=(const pool &other) {\n\t\tentries = other.entries;\n\t\tdo_rehash();\n\t\treturn *this;\n\t}\n\n\tpool &operator=(pool &&other) {\n\t\tclear();\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tpool(const std::initializer_list<K> &list)\n\t{\n\t\tfor (auto &it : list)\n\t\t\tinsert(it);\n\t}\n\n\ttemplate<class InputIterator>\n\tpool(InputIterator first, InputIterator last)\n\t{\n\t\tinsert(first, last);\n\t}\n\n\ttemplate<class InputIterator>\n\tvoid insert(InputIterator first, InputIterator last)\n\t{\n\t\tfor (; first != last; ++first)\n\t\t\tinsert(*first);\n\t}\n\n\tstd::pair<iterator, bool> insert(const K &value)\n\t{\n\t\tHasher::hash_t hash = do_hash(value);\n\t\tint i = do_lookup(value, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(value, hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\tstd::pair<iterator, bool> insert(K &&rvalue)\n\t{\n\t\tHasher::hash_t hash = do_hash(rvalue);\n\t\tint i = do_lookup(rvalue, hash);\n\t\tif (i >= 0)\n\t\t\treturn std::pair<iterator, bool>(iterator(this, i), false);\n\t\ti = do_insert(std::forward<K>(rvalue), hash);\n\t\treturn std::pair<iterator, bool>(iterator(this, i), true);\n\t}\n\n\ttemplate<typename... Args>\n\tstd::pair<iterator, bool> emplace(Args&&... args)\n\t{\n\t\treturn insert(K(std::forward<Args>(args)...));\n\t}\n\n\tint erase(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint index = do_lookup(key, hash);\n\t\treturn do_erase(index, hash);\n\t}\n\n\titerator erase(iterator it)\n\t{\n\t\tHasher::hash_t hash = do_hash(*it);\n\t\tdo_erase(it.index, hash);\n\t\treturn ++it;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tint count(const K &key, const_iterator it) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\treturn i < 0 || i > it.index ? 0 : 1;\n\t}\n\n\titerator find(const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn iterator(this, i);\n\t}\n\n\tconst_iterator find(const K &key) const\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\treturn end();\n\t\treturn const_iterator(this, i);\n\t}\n\n\tbool operator[](const K &key)\n\t{\n\t\tHasher::hash_t hash = do_hash(key);\n\t\tint i = do_lookup(key, hash);\n\t\treturn i >= 0;\n\t}\n\n\ttemplate<typename Compare = std::less<K>>\n\tvoid sort(Compare comp = Compare())\n\t{\n\t\tstd::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });\n\t\tdo_rehash();\n\t}\n\n\tK pop()\n\t{\n\t\titerator it = begin();\n\t\tK ret = *it;\n\t\terase(it);\n\t\treturn ret;\n\t}\n\n\tvoid swap(pool &other)\n\t{\n\t\thashtable.swap(other.hashtable);\n\t\tentries.swap(other.entries);\n\t}\n\n\tbool operator==(const pool &other) const {\n\t\tif (size() != other.size())\n\t\t\treturn false;\n\t\tfor (auto &it : entries)\n\t\t\tif (!other.count(it.udata))\n\t\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tbool operator!=(const pool &other) const {\n\t\treturn !operator==(other);\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\tfor (auto &it : entries) {\n\t\t\th.commutative_eat(ops.hash(it.udata).yield());\n\t\t}\n\t\th.eat(entries.size());\n\t\treturn h;\n\t}\n\n\tvoid reserve(size_t n) { entries.reserve(n); }\n\tsize_t size() const { return entries.size(); }\n\tbool empty() const { return entries.empty(); }\n\tvoid clear() { hashtable.clear(); entries.clear(); }\n\n\titerator begin() { return iterator(this, int(entries.size())-1); }\n\titerator element(int n) { return iterator(this, int(entries.size())-1-n); }\n\titerator end() { return iterator(nullptr, -1); }\n\n\tconst_iterator begin() const { return const_iterator(this, int(entries.size())-1); }\n\tconst_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }\n\tconst_iterator end() const { return const_iterator(nullptr, -1); }\n};\n\ntemplate<typename K, int offset, typename OPS>\nclass idict\n{\n\tpool<K, OPS> database;\n\npublic:\n\tclass const_iterator\n\t{\n\t\tfriend class idict;\n\tprotected:\n\t\tconst idict &container;\n\t\tint index;\n\t\tconst_iterator(const idict &container, int index) : container(container), index(index) { }\n\tpublic:\n\t\ttypedef std::forward_iterator_tag iterator_category;\n\t\ttypedef K value_type;\n\t\ttypedef ptrdiff_t difference_type;\n\t\ttypedef K* pointer;\n\t\ttypedef K& reference;\n\t\tconst_iterator() { }\n\t\tconst_iterator operator++() { index++; return *this; }\n\t\tbool operator==(const const_iterator &other) const { return index == other.index; }\n\t\tbool operator!=(const const_iterator &other) const { return index != other.index; }\n\t\tconst K &operator*() const { return container[index]; }\n\t\tconst K *operator->() const { return &container[index]; }\n\t};\n\n\tconstexpr idict()\n\t{\n\t}\n\n\tint operator()(const K &key)\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup(key, hash);\n\t\tif (i < 0)\n\t\t\ti = database.do_insert(key, hash);\n\t\treturn i + offset;\n\t}\n\n\tint at(const K &key) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\tthrow std::out_of_range(\"idict::at()\");\n\t\treturn i + offset;\n\t}\n\n\tint at(const K &key, int defval) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup_no_rehash(key, hash);\n\t\tif (i < 0)\n\t\t\treturn defval;\n\t\treturn i + offset;\n\t}\n\n\tint count(const K &key) const\n\t{\n\t\tHasher::hash_t hash = database.do_hash(key);\n\t\tint i = database.do_lookup_no_rehash(key, hash);\n\t\treturn i < 0 ? 0 : 1;\n\t}\n\n\tvoid expect(const K &key, int i)\n\t{\n\t\tint j = (*this)(key);\n\t\tif (i != j)\n\t\t\tthrow std::out_of_range(\"idict::expect()\");\n\t}\n\n\tconst K &operator[](int index) const\n\t{\n\t\treturn database.entries.at(index - offset).udata;\n\t}\n\n\tvoid swap(idict &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t}\n\n\tvoid reserve(size_t n) { database.reserve(n); }\n\tsize_t size() const { return database.size(); }\n\tbool empty() const { return database.empty(); }\n\tvoid clear() { database.clear(); }\n\n\tconst_iterator begin() const { return const_iterator(*this, offset); }\n\tconst_iterator element(int n) const { return const_iterator(*this, n); }\n\tconst_iterator end() const { return const_iterator(*this, offset + size()); }\n};\n\n/**\n * Union-find data structure with a promotion method\n * mfp stands for \"merge, find, promote\"\n * i-prefixed methods operate on indices in parents\n*/\ntemplate<typename K, typename OPS>\nclass mfp\n{\n\tmutable idict<K, 0, OPS> database;\n\tmutable std::vector<int> parents;\n\npublic:\n\ttypedef typename idict<K, 0>::const_iterator const_iterator;\n\n\tconstexpr mfp()\n\t{\n\t}\n\n\t// Finds a given element's index. If it isn't in the data structure,\n\t// it is added as its own set\n\tint operator()(const K &key) const\n\t{\n\t\tint i = database(key);\n\t\t// If the lookup caused the database to grow,\n\t\t// also add a corresponding entry in parents initialized to -1 (no parent)\n\t\tparents.resize(database.size(), -1);\n\t\treturn i;\n\t}\n\n\t// Finds an element at given index\n\tconst K &operator[](int index) const\n\t{\n\t\treturn database[index];\n\t}\n\n\tint ifind(int i) const\n\t{\n\t\tint p = i, k = i;\n\n\t\twhile (parents[p] != -1)\n\t\t\tp = parents[p];\n\n\t\t// p is now the representative of i\n\t\t// Now we traverse from i up to the representative again\n\t\t// and make p the parent of all the nodes along the way.\n\t\t// This is a side effect and doesn't affect the return value.\n\t\t// It speeds up future find operations\n\t\twhile (k != p) {\n\t\t\tint next_k = parents[k];\n\t\t\tparents[k] = p;\n\t\t\tk = next_k;\n\t\t}\n\n\t\treturn p;\n\t}\n\n\t// Merge sets if the given indices belong to different sets.\n\t// Makes ifind(j) the root of the merged set.\n\tvoid imerge(int i, int j)\n\t{\n\t\ti = ifind(i);\n\t\tj = ifind(j);\n\n\t\tif (i != j)\n\t\t\tparents[i] = j;\n\t}\n\n\tvoid ipromote(int i)\n\t{\n\t\tint k = i;\n\n\t\twhile (k != -1) {\n\t\t\tint next_k = parents[k];\n\t\t\tparents[k] = i;\n\t\t\tk = next_k;\n\t\t}\n\n\t\tparents[i] = -1;\n\t}\n\n\tint lookup(const K &a) const\n\t{\n\t\treturn ifind((*this)(a));\n\t}\n\n\tconst K &find(const K &a) const\n\t{\n\t\tint i = database.at(a, -1);\n\t\tif (i < 0)\n\t\t\treturn a;\n\t\treturn (*this)[ifind(i)];\n\t}\n\n\tvoid merge(const K &a, const K &b)\n\t{\n\t\timerge((*this)(a), (*this)(b));\n\t}\n\n\tvoid promote(const K &a)\n\t{\n\t\tint i = database.at(a, -1);\n\t\tif (i >= 0)\n\t\t\tipromote(i);\n\t}\n\n\tvoid swap(mfp &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t\tparents.swap(other.parents);\n\t}\n\n\tvoid reserve(size_t n) { database.reserve(n); }\n\tsize_t size() const { return database.size(); }\n\tbool empty() const { return database.empty(); }\n\tvoid clear() { database.clear(); parents.clear(); }\n\n\tconst_iterator begin() const { return database.begin(); }\n\tconst_iterator element(int n) const { return database.element(n); }\n\tconst_iterator end() const { return database.end(); }\n};\n\n} /* namespace hashlib */\n\n#endif\n",
|
|
177
177
|
"io.h": "#include <string>\n#include <stdarg.h>\n#include <type_traits>\n#include \"kernel/yosys_common.h\"\n\n#ifndef YOSYS_IO_H\n#define YOSYS_IO_H\n\nYOSYS_NAMESPACE_BEGIN\n\ninline std::string vstringf(const char *fmt, va_list ap)\n{\n\t// For the common case of strings shorter than 128, save a heap\n\t// allocation by using a stack allocated buffer.\n\tconst int kBufSize = 128;\n\tchar buf[kBufSize];\n\tbuf[0] = '\\0';\n\tva_list apc;\n\tva_copy(apc, ap);\n\tint n = vsnprintf(buf, kBufSize, fmt, apc);\n\tva_end(apc);\n\tif (n < kBufSize)\n\t\treturn std::string(buf);\n\n\tstd::string string;\n\tchar *str = NULL;\n#if defined(_WIN32) || defined(__CYGWIN__)\n\tint sz = 2 * kBufSize, rc;\n\twhile (1) {\n\t\tva_copy(apc, ap);\n\t\tstr = (char *)realloc(str, sz);\n\t\trc = vsnprintf(str, sz, fmt, apc);\n\t\tva_end(apc);\n\t\tif (rc >= 0 && rc < sz)\n\t\t\tbreak;\n\t\tsz *= 2;\n\t}\n\tif (str != NULL) {\n\t\tstring = str;\n\t\tfree(str);\n\t}\n\treturn string;\n#else\n\tif (vasprintf(&str, fmt, ap) < 0)\n\t\tstr = NULL;\n\tif (str != NULL) {\n\t\tstring = str;\n\t\tfree(str);\n\t}\n\treturn string;\n#endif\n}\n\nenum ConversionSpecifier : uint8_t\n{\n\tCONVSPEC_NONE,\n\t// Specifier not understood/supported\n\tCONVSPEC_ERROR,\n\t// Consumes a \"long long\"\n\tCONVSPEC_SIGNED_INT,\n\t// Consumes a \"unsigned long long\"\n\tCONVSPEC_UNSIGNED_INT,\n\t// Consumes a \"double\"\n\tCONVSPEC_DOUBLE,\n\t// Consumes a \"const char*\" or other string type\n\tCONVSPEC_CHAR_PTR,\n\t// Consumes a \"void*\"\n\tCONVSPEC_VOID_PTR,\n};\n\nconstexpr ConversionSpecifier parse_conversion_specifier(char ch, char prev_ch)\n{\n\tswitch (ch) {\n\tcase 'd':\n\tcase 'i':\n\t\treturn CONVSPEC_SIGNED_INT;\n\tcase 'o':\n\tcase 'u':\n\tcase 'x':\n\tcase 'X':\n\tcase 'm':\n\t\treturn CONVSPEC_UNSIGNED_INT;\n\tcase 'c':\n\t\tif (prev_ch == 'l' || prev_ch == 'q' || prev_ch == 'L') {\n\t\t\t// wchar not supported\n\t\t\treturn CONVSPEC_ERROR;\n\t\t}\n\t\treturn CONVSPEC_UNSIGNED_INT;\n\tcase 'e':\n\tcase 'E':\n\tcase 'f':\n\tcase 'F':\n\tcase 'g':\n\tcase 'G':\n\tcase 'a':\n\tcase 'A':\n\t\treturn CONVSPEC_DOUBLE;\n\tcase 's':\n\t\tif (prev_ch == 'l' || prev_ch == 'q' || prev_ch == 'L') {\n\t\t\t// wchar not supported\n\t\t\treturn CONVSPEC_ERROR;\n\t\t}\n\t\treturn CONVSPEC_CHAR_PTR;\n\tcase 'p':\n\t\treturn CONVSPEC_VOID_PTR;\n\tcase '$': // positional parameters\n\tcase 'n':\n\tcase 'S':\n\t\treturn CONVSPEC_ERROR;\n\tdefault:\n\t\treturn CONVSPEC_NONE;\n\t}\n}\n\nenum class DynamicIntCount : uint8_t {\n\tNONE = 0,\n\tONE = 1,\n\tTWO = 2,\n};\n\n// Describes a printf-style format conversion specifier found in a format string.\nstruct FoundFormatSpec\n{\n\t// The start offset of the conversion spec in the format string.\n\tint start;\n\t// The end offset of the conversion spec in the format string.\n\tint end;\n\tConversionSpecifier spec;\n\t// Number of int args consumed by '*' dynamic width/precision args.\n\tDynamicIntCount num_dynamic_ints;\n};\n\n// Ensure there is no format spec.\nconstexpr void ensure_no_format_spec(std::string_view fmt, int index, bool *has_escapes)\n{\n\tint fmt_size = static_cast<int>(fmt.size());\n\t// A trailing '%' is not a format spec.\n\twhile (index + 1 < fmt_size) {\n\t\tif (fmt[index] != '%') {\n\t\t\t++index;\n\t\t\tcontinue;\n\t\t}\n\t\tif (fmt[index + 1] != '%') {\n\t\t\tYOSYS_ABORT(\"More format conversion specifiers than arguments\");\n\t\t}\n\t\t*has_escapes = true;\n\t\tindex += 2;\n\t}\n}\n\n// Returns the next format conversion specifier (starting with '%').\n// Returns CONVSPEC_NONE if there isn't a format conversion specifier.\nconstexpr FoundFormatSpec find_next_format_spec(std::string_view fmt, int fmt_start, bool *has_escapes)\n{\n\tint index = fmt_start;\n\tint fmt_size = static_cast<int>(fmt.size());\n\twhile (index < fmt_size) {\n\t\tif (fmt[index] != '%') {\n\t\t\t++index;\n\t\t\tcontinue;\n\t\t}\n\t\tint p = index + 1;\n\t\tuint8_t num_dynamic_ints = 0;\n\t\twhile (true) {\n\t\t\tif (p == fmt_size) {\n\t\t\t\treturn {0, 0, CONVSPEC_NONE, DynamicIntCount::NONE};\n\t\t\t}\n\t\t\tif (fmt[p] == '%') {\n\t\t\t\t*has_escapes = true;\n\t\t\t\tindex = p + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (fmt[p] == '*') {\n\t\t\t\tif (num_dynamic_ints >= 2) {\n\t\t\t\t\treturn {0, 0, CONVSPEC_ERROR, DynamicIntCount::NONE};\n\t\t\t\t}\n\t\t\t\t++num_dynamic_ints;\n\t\t\t}\n\t\t\tConversionSpecifier spec = parse_conversion_specifier(fmt[p], fmt[p - 1]);\n\t\t\tif (spec != CONVSPEC_NONE) {\n\t\t\t\treturn {index, p + 1, spec, static_cast<DynamicIntCount>(num_dynamic_ints)};\n\t\t\t}\n\t\t\t++p;\n\t\t}\n\t}\n\treturn {0, 0, CONVSPEC_NONE, DynamicIntCount::NONE};\n}\n\ntemplate <typename... Args>\nconstexpr typename std::enable_if<sizeof...(Args) == 0>::type\ncheck_format(std::string_view fmt, int fmt_start, bool *has_escapes, FoundFormatSpec*, DynamicIntCount)\n{\n\tensure_no_format_spec(fmt, fmt_start, has_escapes);\n}\n\n// Check that the format string `fmt.substr(fmt_start)` is valid for the given type arguments.\n// Fills `specs` with the FoundFormatSpecs found in the format string.\n// `int_args_consumed` is the number of int arguments already consumed to satisfy the\n// dynamic width/precision args for the next format conversion specifier.\ntemplate <typename Arg, typename... Args>\nconstexpr void check_format(std::string_view fmt, int fmt_start, bool *has_escapes, FoundFormatSpec* specs,\n DynamicIntCount int_args_consumed)\n{\n\tFoundFormatSpec found = find_next_format_spec(fmt, fmt_start, has_escapes);\n\tif (found.num_dynamic_ints > int_args_consumed) {\n\t\t// We need to consume at least one more int for the dynamic\n\t\t// width/precision of this format conversion specifier.\n\t\tif constexpr (!std::is_convertible_v<Arg, int>) {\n\t\t\tYOSYS_ABORT(\"Expected dynamic int argument\");\n\t\t}\n\t\tcheck_format<Args...>(fmt, fmt_start, has_escapes, specs,\n\t\t\tstatic_cast<DynamicIntCount>(static_cast<uint8_t>(int_args_consumed) + 1));\n\t\treturn;\n\t}\n\tswitch (found.spec) {\n\tcase CONVSPEC_NONE:\n\t\tYOSYS_ABORT(\"Expected format conversion specifier for argument\");\n\t\tbreak;\n\tcase CONVSPEC_ERROR:\n\t\tYOSYS_ABORT(\"Found unsupported format conversion specifier\");\n\t\tbreak;\n\tcase CONVSPEC_SIGNED_INT:\n\t\tif constexpr (!std::is_convertible_v<Arg, long long>) {\n\t\t\tYOSYS_ABORT(\"Expected type convertible to signed integer\");\n\t\t}\n\t\t*specs = found;\n\t\tbreak;\n\tcase CONVSPEC_UNSIGNED_INT:\n\t\tif constexpr (!std::is_convertible_v<Arg, unsigned long long>) {\n\t\t\tYOSYS_ABORT(\"Expected type convertible to unsigned integer\");\n\t\t}\n\t\t*specs = found;\n\t\tbreak;\n\tcase CONVSPEC_DOUBLE:\n\t\tif constexpr (!std::is_convertible_v<Arg, double>) {\n\t\t\tYOSYS_ABORT(\"Expected type convertible to double\");\n\t\t}\n\t\t*specs = found;\n\t\tbreak;\n\tcase CONVSPEC_CHAR_PTR:\n\t\tif constexpr (!std::is_convertible_v<Arg, const char *> &&\n\t\t !std::is_convertible_v<Arg, const std::string &> &&\n\t\t\t!std::is_convertible_v<Arg, const std::string_view &>) {\n\t\t\tYOSYS_ABORT(\"Expected type convertible to char *\");\n\t\t}\n\t\t*specs = found;\n\t\tbreak;\n\tcase CONVSPEC_VOID_PTR:\n\t\tif constexpr (!std::is_convertible_v<Arg, const void *>) {\n\t\t\tYOSYS_ABORT(\"Expected pointer type\");\n\t\t}\n\t\t*specs = found;\n\t\tbreak;\n\t}\n\tcheck_format<Args...>(fmt, found.end, has_escapes, specs + 1, DynamicIntCount::NONE);\n}\n\n// Emit the string representation of `arg` that has been converted to a `long long'.\nvoid format_emit_long_long(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, long long arg);\n\n// Emit the string representation of `arg` that has been converted to a `unsigned long long'.\nvoid format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, unsigned long long arg);\n\n// Emit the string representation of `arg` that has been converted to a `double'.\nvoid format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, double arg);\n\n// Emit the string representation of `arg` that has been converted to a `const char*'.\nvoid format_emit_char_ptr(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, const char *arg);\n\n// Emit the string representation of `arg` that has been converted to a `std::string'.\nvoid format_emit_string(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, const std::string &arg);\n\n// Emit the string representation of `arg` that has been converted to a `std::string_view'.\nvoid format_emit_string_view(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, std::string_view arg);\n\n// Emit the string representation of `arg` that has been converted to a `double'.\nvoid format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints,\n\tDynamicIntCount num_dynamic_ints, const void *arg);\n\n// Emit the string representation of `arg` according to the given `FoundFormatSpec`,\n// appending it to `result`.\ntemplate <typename Arg>\ninline void format_emit_one(std::string &result, std::string_view fmt, const FoundFormatSpec &ffspec,\n\tint *dynamic_ints, const Arg& arg)\n{\n\tstd::string_view spec = fmt.substr(ffspec.start, ffspec.end - ffspec.start);\n\tDynamicIntCount num_dynamic_ints = ffspec.num_dynamic_ints;\n\tswitch (ffspec.spec) {\n\tcase CONVSPEC_SIGNED_INT:\n\t\tif constexpr (std::is_convertible_v<Arg, long long>) {\n\t\t\tlong long s = arg;\n\t\t\tformat_emit_long_long(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\tcase CONVSPEC_UNSIGNED_INT:\n\t\tif constexpr (std::is_convertible_v<Arg, unsigned long long>) {\n\t\t\tunsigned long long s = arg;\n\t\t\tformat_emit_unsigned_long_long(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\tcase CONVSPEC_DOUBLE:\n\t\tif constexpr (std::is_convertible_v<Arg, double>) {\n\t\t\tdouble s = arg;\n\t\t\tformat_emit_double(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\tcase CONVSPEC_CHAR_PTR:\n\t\tif constexpr (std::is_convertible_v<Arg, const char *>) {\n\t\t\tconst char *s = arg;\n\t\t\tformat_emit_char_ptr(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tif constexpr (std::is_convertible_v<Arg, const std::string &>) {\n\t\t\tconst std::string &s = arg;\n\t\t\tformat_emit_string(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tif constexpr (std::is_convertible_v<Arg, const std::string_view &>) {\n\t\t\tconst std::string_view &s = arg;\n\t\t\tformat_emit_string_view(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\tcase CONVSPEC_VOID_PTR:\n\t\tif constexpr (std::is_convertible_v<Arg, const void *>) {\n\t\t\tconst void *s = arg;\n\t\t\tformat_emit_void_ptr(result, spec, dynamic_ints, num_dynamic_ints, s);\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\tYOSYS_ABORT(\"Internal error\");\n}\n\n// Append the format string `fmt` to `result`, assuming there are no format conversion\n// specifiers other than \"%%\" and therefore no arguments. Unescape \"%%\".\nvoid format_emit_unescaped(std::string &result, std::string_view fmt);\nstd::string unescape_format_string(std::string_view fmt);\n\ninline void format_emit(std::string &result, std::string_view fmt, int fmt_start,\n\tbool has_escapes, const FoundFormatSpec*, int*, DynamicIntCount)\n{\n\tfmt = fmt.substr(fmt_start);\n\tif (has_escapes) {\n\t\tformat_emit_unescaped(result, fmt);\n\t} else {\n\t\tresult += fmt;\n\t}\n}\n// Format `args` according to `fmt` (starting at `fmt_start`) and `specs` and append to `result`.\n// `num_dynamic_ints` in `dynamic_ints[]` have already been collected to provide as\n// dynamic width/precision args for the next format conversion specifier.\ntemplate <typename Arg, typename... Args>\ninline void format_emit(std::string &result, std::string_view fmt, int fmt_start, bool has_escapes,\n\tconst FoundFormatSpec* specs, int *dynamic_ints, DynamicIntCount num_dynamic_ints,\n\tconst Arg &arg, const Args &... args)\n{\n\tif (specs->num_dynamic_ints > num_dynamic_ints) {\n\t\t// Collect another int for the dynamic width precision/args\n\t\t// for the next format conversion specifier.\n\t\tif constexpr (std::is_convertible_v<Arg, int>) {\n\t\t\tdynamic_ints[static_cast<uint8_t>(num_dynamic_ints)] = arg;\n\t\t} else {\n\t\t\tYOSYS_ABORT(\"Internal error\");\n\t\t}\n\t\tformat_emit(result, fmt, fmt_start, has_escapes, specs, dynamic_ints,\n\t\t static_cast<DynamicIntCount>(static_cast<uint8_t>(num_dynamic_ints) + 1), args...);\n\t\treturn;\n\t}\n\tstd::string_view str = fmt.substr(fmt_start, specs->start - fmt_start);\n\tif (has_escapes) {\n\t\tformat_emit_unescaped(result, str);\n\t} else {\n\t\tresult += str;\n\t}\n\tformat_emit_one(result, fmt, *specs, dynamic_ints, arg);\n\tformat_emit(result, fmt, specs->end, has_escapes, specs + 1, dynamic_ints, DynamicIntCount::NONE, args...);\n}\n\ntemplate <typename... Args>\ninline std::string format_emit_toplevel(std::string_view fmt, bool has_escapes, const FoundFormatSpec* specs, const Args &... args)\n{\n\tstd::string result;\n\tint dynamic_ints[2] = { 0, 0 };\n\tformat_emit(result, fmt, 0, has_escapes, specs, dynamic_ints, DynamicIntCount::NONE, args...);\n\treturn result;\n}\ntemplate <>\ninline std::string format_emit_toplevel(std::string_view fmt, bool has_escapes, const FoundFormatSpec*)\n{\n\tif (!has_escapes) {\n\t\treturn std::string(fmt);\n\t}\n\treturn unescape_format_string(fmt);\n}\n\n// This class parses format strings to build a list of `FoundFormatSpecs` in `specs`.\n// When the compiler supports `consteval` (C++20), this parsing happens at compile time and\n// type errors will be reported at compile time. Otherwise the parsing happens at\n// runtime and type errors will trigger an `abort()` at runtime.\ntemplate <typename... Args>\nclass FmtString\n{\npublic:\n\t// Implicit conversion from const char * means that users can pass\n\t// C string constants which are automatically parsed.\n\tYOSYS_CONSTEVAL FmtString(const char *p) : fmt(p)\n\t{\n\t\tcheck_format<Args...>(fmt, 0, &has_escapes, specs, DynamicIntCount::NONE);\n\t}\n\tstd::string format(const Args &... args)\n\t{\n\t\treturn format_emit_toplevel(fmt, has_escapes, specs, args...);\n\t}\nprivate:\n\tstd::string_view fmt;\n\tbool has_escapes = false;\n\tFoundFormatSpec specs[sizeof...(Args)] = {};\n};\n\ntemplate <typename T> struct WrapType { using type = T; };\ntemplate <typename T> using TypeIdentity = typename WrapType<T>::type;\n\ntemplate <typename... Args>\ninline std::string stringf(FmtString<TypeIdentity<Args>...> fmt, Args... args)\n{\n\treturn fmt.format(args...);\n}\n\nint readsome(std::istream &f, char *s, int n);\nstd::string next_token(std::string &text, const char *sep = \" \\t\\r\\n\", bool long_strings = false);\nstd::vector<std::string> split_tokens(const std::string &text, const char *sep = \" \\t\\r\\n\");\nbool patmatch(const char *pattern, const char *string);\n#if !defined(YOSYS_DISABLE_SPAWN)\nint run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());\n#endif\nstd::string get_base_tmpdir();\nstd::string make_temp_file(std::string template_str = get_base_tmpdir() + \"/yosys_XXXXXX\");\nstd::string make_temp_dir(std::string template_str = get_base_tmpdir() + \"/yosys_XXXXXX\");\nbool check_file_exists(const std::string& filename, bool is_exec = false);\nbool check_directory_exists(const std::string& dirname, bool is_exec = false);\nbool is_absolute_path(std::string filename);\nvoid remove_directory(std::string dirname);\nbool create_directory(const std::string& dirname);\nstd::string escape_filename_spaces(const std::string& filename);\n\nYOSYS_NAMESPACE_END\n\n#endif // YOSYS_IO_H\n",
|
|
178
178
|
"json.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef JSON_H\n#define JSON_H\n\n#include \"kernel/yosys.h\"\n#include \"libs/json11/json11.hpp\"\n#include <functional>\n\nYOSYS_NAMESPACE_BEGIN\n\nusing json11::Json;\n\nclass PrettyJson\n{\n enum Scope {\n VALUE,\n OBJECT_FIRST,\n OBJECT,\n ARRAY_FIRST,\n ARRAY,\n };\n\n struct Target {\n virtual void emit(const char *data) = 0;\n virtual void flush() {};\n virtual ~Target() {};\n };\n\n std::string newline_indent = \"\\n\";\n std::vector<std::unique_ptr<Target>> targets;\n std::vector<Scope> state = {VALUE};\n int compact_depth = INT_MAX;\npublic:\n\n void emit_to_log();\n void append_to_string(std::string &target);\n bool write_to_file(const std::string &path);\n\n bool active() { return !targets.empty(); }\n\n void compact() { compact_depth = GetSize(state); }\n\n void line(bool space_if_inline = true);\n void raw(const char *raw_json);\n void flush();\n void begin_object();\n void begin_array();\n void end_object();\n void end_array();\n void name(const char *name);\n void begin_value();\n void end_value();\n void value_json(const Json &value);\n void value(unsigned int value) { value_json(Json((int)value)); }\n template<typename T>\n void value(T &&value) { value_json(Json(std::forward<T>(value))); };\n\n void entry_json(const char *name, const Json &value);\n void entry(const char *name, unsigned int value) { entry_json(name, Json((int)value)); }\n template<typename T>\n void entry(const char *name, T &&value) { entry_json(name, Json(std::forward<T>(value))); };\n\n template<typename T>\n void object(const T &&values)\n {\n begin_object();\n for (auto &item : values)\n entry(item.first, item.second);\n end_object();\n }\n\n template<typename T>\n void array(const T &&values)\n {\n begin_array();\n for (auto &item : values)\n value(item);\n end_array();\n }\n};\n\n\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
179
|
-
"log.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef LOG_H\n#define LOG_H\n\n#include \"kernel/yosys_common.h\"\n\n#include <time.h>\n\n#include <regex>\n#define YS_REGEX_COMPILE(param) std::regex(param, \\\n\t\t\t\tstd::regex_constants::nosubs | \\\n\t\t\t\tstd::regex_constants::optimize | \\\n\t\t\t\tstd::regex_constants::egrep)\n#define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \\\n\t\t\t\tstd::regex_constants::optimize | \\\n\t\t\t\tstd::regex_constants::egrep)\n\n#if defined(_WIN32)\n# include <intrin.h>\n#else\n# include <sys/time.h>\n# include <sys/resource.h>\n# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n# include <signal.h>\n# endif\n#endif\n\n#if defined(_MSC_VER)\n// At least this is not in MSVC++ 2013.\n# define __PRETTY_FUNCTION__ __FUNCTION__\n#endif\n\n// from libs/sha1/sha1.h\nclass SHA1;\n\nYOSYS_NAMESPACE_BEGIN\n\n#define S__LINE__sub2(x) #x\n#define S__LINE__sub1(x) S__LINE__sub2(x)\n#define S__LINE__ S__LINE__sub1(__LINE__)\n\n// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint\n// if the platform provides such functionality, and does nothing otherwise.\n// If no debugger is attached, it starts a just-in-time debugger if available,\n// and crashes the process otherwise.\n#if defined(_WIN32)\n# define YS_DEBUGTRAP __debugbreak()\n#else\n# ifndef __has_builtin\n// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang)\n// that does not have it, using __has_builtin(...) is a syntax error.\n# define __has_builtin(x) 0\n# endif\n# if __has_builtin(__builtin_debugtrap)\n# define YS_DEBUGTRAP __builtin_debugtrap()\n# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n# define YS_DEBUGTRAP raise(SIGTRAP)\n# else\n# define YS_DEBUGTRAP do {} while(0)\n# endif\n#endif\n\n// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint\n// if a debugger is attached, and does nothing otherwise.\n#if defined(_WIN32)\n# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0)\n# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However,\n// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.\n# define YS_DEBUGTRAP_IF_DEBUGGING do { \\\n\t\tauto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \\\n\t} while(0)\n#else\n# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)\n#endif\n\nstruct log_cmd_error_exception { };\n\nextern std::vector<FILE*> log_files;\nextern std::vector<std::ostream*> log_streams;\nextern std::vector<std::string> log_scratchpads;\nextern std::map<std::string, std::set<std::string>> log_hdump;\nextern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;\nextern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;\nextern int log_warnings_count;\nextern int log_warnings_count_noexpect;\nextern bool log_expect_no_warnings;\nextern bool log_hdump_all;\nextern FILE *log_errfile;\nextern SHA1 *log_hasher;\n\nextern bool log_time;\nextern bool log_error_stderr;\nextern bool log_cmd_error_throw;\nextern bool log_quiet_warnings;\nextern int log_verbose_level;\nextern string log_last_error;\nextern void (*log_error_atexit)();\n\nextern int log_make_debug;\nextern int log_force_debug;\nextern int log_debug_suppressed;\n\nvoid logv(const char *format, va_list ap);\nvoid logv_header(RTLIL::Design *design, const char *format, va_list ap);\nvoid logv_warning(const char *format, va_list ap);\nvoid logv_warning_noprefix(const char *format, va_list ap);\n[[noreturn]] void logv_error(const char *format, va_list ap);\n[[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap);\n\nvoid log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\nvoid log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));\nvoid log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\nvoid log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n\nvoid set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg));\nextern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg);\n\n// Log with filename to report a problem in a source file.\nvoid log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\nvoid log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\n\nvoid log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n[[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n[[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\n[[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n\n#ifndef NDEBUG\nstatic inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }\n#else\nstatic inline bool ys_debug(int = 0) { return false; }\n#endif\n# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)\n\nstatic inline void log_suppressed() {\n\tif (log_debug_suppressed && !log_make_debug) {\n\t\tlog(\"<suppressed ~%d debug messages>\\n\", log_debug_suppressed);\n\t\tlog_debug_suppressed = 0;\n\t}\n}\n\nstruct LogMakeDebugHdl {\n\tbool status = false;\n\tLogMakeDebugHdl(bool start_on = false) {\n\t\tif (start_on)\n\t\t\ton();\n\t}\n\t~LogMakeDebugHdl() {\n\t\toff();\n\t}\n\tvoid on() {\n\t\tif (status) return;\n\t\tstatus=true;\n\t\tlog_make_debug++;\n\t}\n\tvoid off_silent() {\n\t\tif (!status) return;\n\t\tstatus=false;\n\t\tlog_make_debug--;\n\t}\n\tvoid off() {\n\t\toff_silent();\n\t}\n};\n\nvoid log_spacer();\nvoid log_push();\nvoid log_pop();\n\nvoid log_backtrace(const char *prefix, int levels);\nvoid log_reset_stack();\nvoid log_flush();\n\nstruct LogExpectedItem\n{\n\tLogExpectedItem(const std::regex &pat, int expected) :\n\t\t\tpattern(pat), expected_count(expected), current_count(0) {}\n\tLogExpectedItem() : expected_count(0), current_count(0) {}\n\n\tstd::regex pattern;\n\tint expected_count;\n\tint current_count;\n};\n\nextern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;\nvoid log_check_expected();\n\nconst char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);\nconst char *log_const(const RTLIL::Const &value, bool autoint = true);\nconst char *log_id(const RTLIL::IdString &id);\nconst char *log_str(const char *str);\nconst char *log_str(std::string const &str);\n\ntemplate<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {\n\tif (nullstr && obj == nullptr)\n\t\treturn nullstr;\n\treturn log_id(obj->name);\n}\n\nvoid log_module(RTLIL::Module *module, std::string indent = \"\");\nvoid log_cell(RTLIL::Cell *cell, std::string indent = \"\");\nvoid log_wire(RTLIL::Wire *wire, std::string indent = \"\");\n\n#ifndef NDEBUG\nstatic inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {\n\tif (!cond) log_error(\"Assert `%s' failed in %s:%d.\\n\", expr, file, line);\n}\n# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)\n#else\n# define log_assert(_assert_expr_) do { if (0) { (void)(_assert_expr_); } } while(0)\n#endif\n\n#define log_abort() YOSYS_NAMESPACE_PREFIX log_error(\"Abort in %s:%d.\\n\", __FILE__, __LINE__)\n#define log_ping() YOSYS_NAMESPACE_PREFIX log(\"-- %s:%d %s --\\n\", __FILE__, __LINE__, __PRETTY_FUNCTION__)\n\n\n// ---------------------------------------------------\n// This is the magic behind the code coverage counters\n// ---------------------------------------------------\n\n#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))\n\n#define cover(_id) do { \\\n static CoverData __d __attribute__((section(\"yosys_cover_list\"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \\\n __d.counter++; \\\n} while (0)\n\nstruct CoverData {\n\tconst char *file, *func, *id;\n\tint line, counter;\n} YS_ATTRIBUTE(packed);\n\n// this two symbols are created by the linker for the \"yosys_cover_list\" ELF section\nextern \"C\" struct CoverData __start_yosys_cover_list[];\nextern \"C\" struct CoverData __stop_yosys_cover_list[];\n\nextern dict<std::string, std::pair<std::string, int>> extra_coverage_data;\n\nvoid cover_extra(std::string parent, std::string id, bool increment = true);\ndict<std::string, std::pair<std::string, int>> get_coverage_data();\n\n#define cover_list(_id, ...) do { cover(_id); \\\n\tstd::string r = cover_list_worker(_id, __VA_ARGS__); \\\n\tlog_assert(r.empty()); \\\n} while (0)\n\nstatic inline std::string cover_list_worker(std::string, std::string last) {\n\treturn last;\n}\n\ntemplate<typename... T>\nstd::string cover_list_worker(std::string prefix, std::string first, T... rest) {\n\tstd::string selected = cover_list_worker(prefix, rest...);\n\tcover_extra(prefix, prefix + \".\" + first, first == selected);\n\treturn first == selected ? \"\" : selected;\n}\n\n#else\n# define cover(...) do { } while (0)\n# define cover_list(...) do { } while (0)\n#endif\n\n\n// ------------------------------------------------------------\n// everything below this line are utilities for troubleshooting\n// ------------------------------------------------------------\n\n// simple timer for performance measurements\n// toggle the '#if 1' to get a baseline for the performance penalty added by the measurement\nstruct PerformanceTimer\n{\n#if 1\n\tint64_t total_ns;\n\n\tPerformanceTimer() {\n\t\ttotal_ns = 0;\n\t}\n\n\tstatic int64_t query() {\n# ifdef _WIN32\n\t\treturn 0;\n# elif defined(RUSAGE_SELF)\n\t\tstruct rusage rusage;\n\t\tint64_t t = 0;\n\t\tfor (int who : {RUSAGE_SELF, RUSAGE_CHILDREN}) {\n\t\t\tif (getrusage(who, &rusage) == -1) {\n\t\t\t\tlog_cmd_error(\"getrusage failed!\\n\");\n\t\t\t\tlog_abort();\n\t\t\t}\n\t\t\tt += 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;\n\t\t\tt += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;\n\t\t}\n\t\treturn t;\n# else\n# error \"Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).\"\n# endif\n\t}\n\n\tvoid reset() {\n\t\ttotal_ns = 0;\n\t}\n\n\tvoid begin() {\n\t\ttotal_ns -= query();\n\t}\n\n\tvoid end() {\n\t\ttotal_ns += query();\n\t}\n\n\tfloat sec() const {\n\t\treturn total_ns * 1e-9f;\n\t}\n#else\n\tstatic int64_t query() { return 0; }\n\tvoid reset() { }\n\tvoid begin() { }\n\tvoid end() { }\n\tfloat sec() const { return 0; }\n#endif\n};\n\n// simple API for quickly dumping values when debugging\n\nstatic inline void log_dump_val_worker(short v) { log(\"%d\", v); }\nstatic inline void log_dump_val_worker(unsigned short v) { log(\"%u\", v); }\nstatic inline void log_dump_val_worker(int v) { log(\"%d\", v); }\nstatic inline void log_dump_val_worker(unsigned int v) { log(\"%u\", v); }\nstatic inline void log_dump_val_worker(long int v) { log(\"%ld\", v); }\nstatic inline void log_dump_val_worker(unsigned long int v) { log(\"%lu\", v); }\n#ifndef _WIN32\nstatic inline void log_dump_val_worker(long long int v) { log(\"%lld\", v); }\nstatic inline void log_dump_val_worker(unsigned long long int v) { log(\"%lld\", v); }\n#endif\nstatic inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? \"'%c'\" : \"'\\\\x%02x'\", c); }\nstatic inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? \"'%c'\" : \"'\\\\x%02x'\", c); }\nstatic inline void log_dump_val_worker(bool v) { log(\"%s\", v ? \"true\" : \"false\"); }\nstatic inline void log_dump_val_worker(double v) { log(\"%f\", v); }\nstatic inline void log_dump_val_worker(char *v) { log(\"%s\", v); }\nstatic inline void log_dump_val_worker(const char *v) { log(\"%s\", v); }\nstatic inline void log_dump_val_worker(std::string v) { log(\"%s\", v.c_str()); }\nstatic inline void log_dump_val_worker(PerformanceTimer p) { log(\"%f seconds\", p.sec()); }\nstatic inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }\nvoid log_dump_val_worker(RTLIL::IdString v);\nvoid log_dump_val_worker(RTLIL::SigSpec v);\nvoid log_dump_val_worker(RTLIL::State v);\n\ntemplate<typename K, typename T> static inline void log_dump_val_worker(dict<K, T> &v);\ntemplate<typename K> static inline void log_dump_val_worker(pool<K> &v);\ntemplate<typename K> static inline void log_dump_val_worker(std::vector<K> &v);\ntemplate<typename T> static inline void log_dump_val_worker(T *ptr);\n\ntemplate<typename K, typename T>\nstatic inline void log_dump_val_worker(dict<K, T> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it.first);\n\t\tlog(\": \");\n\t\tlog_dump_val_worker(it.second);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename K>\nstatic inline void log_dump_val_worker(pool<K> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename K>\nstatic inline void log_dump_val_worker(std::vector<K> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename T>\nstatic inline void log_dump_val_worker(T *ptr) { log(\"%p\", ptr); }\n\ntemplate<typename T, typename ... Args>\nvoid log_dump_args_worker(const char *p, T first, Args ... args)\n{\n\tint next_p_state = 0;\n\tconst char *next_p = p;\n\twhile (*next_p && (next_p_state != 0 || *next_p != ',')) {\n\t\tif (*next_p == '\"')\n\t\t\tdo {\n\t\t\t\tnext_p++;\n\t\t\t\twhile (*next_p == '\\\\' && *(next_p + 1))\n\t\t\t\t\tnext_p += 2;\n\t\t\t} while (*next_p && *next_p != '\"');\n\t\tif (*next_p == '\\'') {\n\t\t\tnext_p++;\n\t\t\tif (*next_p == '\\\\')\n\t\t\t\tnext_p++;\n\t\t\tif (*next_p)\n\t\t\t\tnext_p++;\n\t\t}\n\t\tif (*next_p == '(' || *next_p == '[' || *next_p == '{')\n\t\t\tnext_p_state++;\n\t\tif ((*next_p == ')' || *next_p == ']' || *next_p == '}') && next_p_state > 0)\n\t\t\tnext_p_state--;\n\t\tnext_p++;\n\t}\n\tlog(\"\\n\\t%.*s => \", int(next_p - p), p);\n\tif (*next_p == ',')\n\t\tnext_p++;\n\twhile (*next_p == ' ' || *next_p == '\\t' || *next_p == '\\r' || *next_p == '\\n')\n\t\tnext_p++;\n\tlog_dump_val_worker(first);\n\tlog_dump_args_worker(next_p, args ...);\n}\n\n#define log_dump(...) do { \\\n\tlog(\"DEBUG DUMP IN %s AT %s:%d:\", __PRETTY_FUNCTION__, __FILE__, __LINE__); \\\n\tlog_dump_args_worker(#__VA_ARGS__, __VA_ARGS__); \\\n\tlog(\"\\n\"); \\\n} while (0)\n\nYOSYS_NAMESPACE_END\n\n#include \"kernel/yosys.h\"\n\n#endif\n",
|
|
179
|
+
"log.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef LOG_H\n#define LOG_H\n\n#include \"kernel/yosys_common.h\"\n\n#include <time.h>\n\n#include <regex>\n#define YS_REGEX_COMPILE(param) std::regex(param, \\\n\t\t\t\tstd::regex_constants::nosubs | \\\n\t\t\t\tstd::regex_constants::optimize | \\\n\t\t\t\tstd::regex_constants::egrep)\n#define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \\\n\t\t\t\tstd::regex_constants::optimize | \\\n\t\t\t\tstd::regex_constants::egrep)\n\n#if defined(_WIN32)\n# include <intrin.h>\n#else\n# include <sys/time.h>\n# include <sys/resource.h>\n# if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n# include <signal.h>\n# endif\n#endif\n\n#if defined(_MSC_VER)\n// At least this is not in MSVC++ 2013.\n# define __PRETTY_FUNCTION__ __FUNCTION__\n#endif\n\n// from libs/sha1/sha1.h\nclass SHA1;\n\nYOSYS_NAMESPACE_BEGIN\n\n#define S__LINE__sub2(x) #x\n#define S__LINE__sub1(x) S__LINE__sub2(x)\n#define S__LINE__ S__LINE__sub1(__LINE__)\n\n// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint\n// if the platform provides such functionality, and does nothing otherwise.\n// If no debugger is attached, it starts a just-in-time debugger if available,\n// and crashes the process otherwise.\n#if defined(_WIN32)\n# define YS_DEBUGTRAP __debugbreak()\n#else\n# ifndef __has_builtin\n// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang)\n// that does not have it, using __has_builtin(...) is a syntax error.\n# define __has_builtin(x) 0\n# endif\n# if __has_builtin(__builtin_debugtrap)\n# define YS_DEBUGTRAP __builtin_debugtrap()\n# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n# define YS_DEBUGTRAP raise(SIGTRAP)\n# else\n# define YS_DEBUGTRAP do {} while(0)\n# endif\n#endif\n\n// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint\n// if a debugger is attached, and does nothing otherwise.\n#if defined(_WIN32)\n# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0)\n# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))\n// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However,\n// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore.\n# define YS_DEBUGTRAP_IF_DEBUGGING do { \\\n\t\tauto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \\\n\t} while(0)\n#else\n# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0)\n#endif\n\nstruct log_cmd_error_exception { };\n\nextern std::vector<FILE*> log_files;\nextern std::vector<std::ostream*> log_streams;\nextern std::vector<std::string> log_scratchpads;\nextern std::map<std::string, std::set<std::string>> log_hdump;\nextern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;\nextern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;\nextern int log_warnings_count;\nextern int log_warnings_count_noexpect;\nextern bool log_expect_no_warnings;\nextern bool log_hdump_all;\nextern FILE *log_errfile;\nextern SHA1 *log_hasher;\n\nextern bool log_time;\nextern bool log_error_stderr;\nextern bool log_cmd_error_throw;\nextern bool log_quiet_warnings;\nextern int log_verbose_level;\nextern string log_last_error;\nextern void (*log_error_atexit)();\n\nextern int log_make_debug;\nextern int log_force_debug;\nextern int log_debug_suppressed;\n\nvoid logv(const char *format, va_list ap);\nvoid logv_header(RTLIL::Design *design, const char *format, va_list ap);\nvoid logv_warning(const char *format, va_list ap);\nvoid logv_warning_noprefix(const char *format, va_list ap);\n[[noreturn]] void logv_error(const char *format, va_list ap);\n[[noreturn]] void logv_file_error(const string &filename, int lineno, const char *format, va_list ap);\n\nvoid log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\nvoid log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));\nvoid log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\nvoid log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n\nvoid set_verific_logging(void (*cb)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg));\nextern void (*log_verific_callback)(int msg_type, const char *message_id, const char* file_path, unsigned int left_line, unsigned int left_col, unsigned int right_line, unsigned int right_col, const char *msg);\n\n// Log with filename to report a problem in a source file.\nvoid log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\nvoid log_file_info(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\n\nvoid log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n[[noreturn]] void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n[[noreturn]] void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));\n[[noreturn]] void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));\n\n#ifndef NDEBUG\nstatic inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }\n#else\nstatic inline bool ys_debug(int = 0) { return false; }\n#endif\n# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)\n\nstatic inline void log_suppressed() {\n\tif (log_debug_suppressed && !log_make_debug) {\n\t\tlog(\"<suppressed ~%d debug messages>\\n\", log_debug_suppressed);\n\t\tlog_debug_suppressed = 0;\n\t}\n}\n\nstruct LogMakeDebugHdl {\n\tbool status = false;\n\tLogMakeDebugHdl(bool start_on = false) {\n\t\tif (start_on)\n\t\t\ton();\n\t}\n\t~LogMakeDebugHdl() {\n\t\toff();\n\t}\n\tvoid on() {\n\t\tif (status) return;\n\t\tstatus=true;\n\t\tlog_make_debug++;\n\t}\n\tvoid off_silent() {\n\t\tif (!status) return;\n\t\tstatus=false;\n\t\tlog_make_debug--;\n\t}\n\tvoid off() {\n\t\toff_silent();\n\t}\n};\n\nvoid log_spacer();\nvoid log_push();\nvoid log_pop();\n\nvoid log_backtrace(const char *prefix, int levels);\nvoid log_reset_stack();\nvoid log_flush();\n\nstruct LogExpectedItem\n{\n\tLogExpectedItem(const std::regex &pat, int expected) :\n\t\t\tpattern(pat), expected_count(expected), current_count(0) {}\n\tLogExpectedItem() : expected_count(0), current_count(0) {}\n\n\tstd::regex pattern;\n\tint expected_count;\n\tint current_count;\n};\n\nextern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;\nextern dict<std::string, LogExpectedItem> log_expect_prefix_log, log_expect_prefix_warning, log_expect_prefix_error;\nvoid log_check_expected();\n\nconst char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);\nconst char *log_const(const RTLIL::Const &value, bool autoint = true);\nconst char *log_id(const RTLIL::IdString &id);\nconst char *log_str(const char *str);\nconst char *log_str(std::string const &str);\n\ntemplate<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {\n\tif (nullstr && obj == nullptr)\n\t\treturn nullstr;\n\treturn log_id(obj->name);\n}\n\nvoid log_module(RTLIL::Module *module, std::string indent = \"\");\nvoid log_cell(RTLIL::Cell *cell, std::string indent = \"\");\nvoid log_wire(RTLIL::Wire *wire, std::string indent = \"\");\n\n#ifndef NDEBUG\nstatic inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {\n\tif (!cond) log_error(\"Assert `%s' failed in %s:%d.\\n\", expr, file, line);\n}\n# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)\n#else\n# define log_assert(_assert_expr_) do { if (0) { (void)(_assert_expr_); } } while(0)\n#endif\n\n#define log_abort() YOSYS_NAMESPACE_PREFIX log_error(\"Abort in %s:%d.\\n\", __FILE__, __LINE__)\n#define log_ping() YOSYS_NAMESPACE_PREFIX log(\"-- %s:%d %s --\\n\", __FILE__, __LINE__, __PRETTY_FUNCTION__)\n\n\n// ---------------------------------------------------\n// This is the magic behind the code coverage counters\n// ---------------------------------------------------\n\n#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))\n\n#define cover(_id) do { \\\n static CoverData __d __attribute__((section(\"yosys_cover_list\"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \\\n __d.counter++; \\\n} while (0)\n\nstruct CoverData {\n\tconst char *file, *func, *id;\n\tint line, counter;\n} YS_ATTRIBUTE(packed);\n\n// this two symbols are created by the linker for the \"yosys_cover_list\" ELF section\nextern \"C\" struct CoverData __start_yosys_cover_list[];\nextern \"C\" struct CoverData __stop_yosys_cover_list[];\n\nextern dict<std::string, std::pair<std::string, int>> extra_coverage_data;\n\nvoid cover_extra(std::string parent, std::string id, bool increment = true);\ndict<std::string, std::pair<std::string, int>> get_coverage_data();\n\n#define cover_list(_id, ...) do { cover(_id); \\\n\tstd::string r = cover_list_worker(_id, __VA_ARGS__); \\\n\tlog_assert(r.empty()); \\\n} while (0)\n\nstatic inline std::string cover_list_worker(std::string, std::string last) {\n\treturn last;\n}\n\ntemplate<typename... T>\nstd::string cover_list_worker(std::string prefix, std::string first, T... rest) {\n\tstd::string selected = cover_list_worker(prefix, rest...);\n\tcover_extra(prefix, prefix + \".\" + first, first == selected);\n\treturn first == selected ? \"\" : selected;\n}\n\n#else\n# define cover(...) do { } while (0)\n# define cover_list(...) do { } while (0)\n#endif\n\n\n// ------------------------------------------------------------\n// everything below this line are utilities for troubleshooting\n// ------------------------------------------------------------\n\n// simple timer for performance measurements\n// toggle the '#if 1' to get a baseline for the performance penalty added by the measurement\nstruct PerformanceTimer\n{\n#if 1\n\tint64_t total_ns;\n\n\tPerformanceTimer() {\n\t\ttotal_ns = 0;\n\t}\n\n\tstatic int64_t query() {\n# ifdef _WIN32\n\t\treturn 0;\n# elif defined(RUSAGE_SELF)\n\t\tstruct rusage rusage;\n\t\tint64_t t = 0;\n\t\tfor (int who : {RUSAGE_SELF, RUSAGE_CHILDREN}) {\n\t\t\tif (getrusage(who, &rusage) == -1) {\n\t\t\t\tlog_cmd_error(\"getrusage failed!\\n\");\n\t\t\t\tlog_abort();\n\t\t\t}\n\t\t\tt += 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;\n\t\t\tt += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;\n\t\t}\n\t\treturn t;\n# else\n# error \"Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).\"\n# endif\n\t}\n\n\tvoid reset() {\n\t\ttotal_ns = 0;\n\t}\n\n\tvoid begin() {\n\t\ttotal_ns -= query();\n\t}\n\n\tvoid end() {\n\t\ttotal_ns += query();\n\t}\n\n\tfloat sec() const {\n\t\treturn total_ns * 1e-9f;\n\t}\n#else\n\tstatic int64_t query() { return 0; }\n\tvoid reset() { }\n\tvoid begin() { }\n\tvoid end() { }\n\tfloat sec() const { return 0; }\n#endif\n};\n\n// simple API for quickly dumping values when debugging\n\nstatic inline void log_dump_val_worker(short v) { log(\"%d\", v); }\nstatic inline void log_dump_val_worker(unsigned short v) { log(\"%u\", v); }\nstatic inline void log_dump_val_worker(int v) { log(\"%d\", v); }\nstatic inline void log_dump_val_worker(unsigned int v) { log(\"%u\", v); }\nstatic inline void log_dump_val_worker(long int v) { log(\"%ld\", v); }\nstatic inline void log_dump_val_worker(unsigned long int v) { log(\"%lu\", v); }\n#ifndef _WIN32\nstatic inline void log_dump_val_worker(long long int v) { log(\"%lld\", v); }\nstatic inline void log_dump_val_worker(unsigned long long int v) { log(\"%lld\", v); }\n#endif\nstatic inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? \"'%c'\" : \"'\\\\x%02x'\", c); }\nstatic inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? \"'%c'\" : \"'\\\\x%02x'\", c); }\nstatic inline void log_dump_val_worker(bool v) { log(\"%s\", v ? \"true\" : \"false\"); }\nstatic inline void log_dump_val_worker(double v) { log(\"%f\", v); }\nstatic inline void log_dump_val_worker(char *v) { log(\"%s\", v); }\nstatic inline void log_dump_val_worker(const char *v) { log(\"%s\", v); }\nstatic inline void log_dump_val_worker(std::string v) { log(\"%s\", v.c_str()); }\nstatic inline void log_dump_val_worker(PerformanceTimer p) { log(\"%f seconds\", p.sec()); }\nstatic inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }\nvoid log_dump_val_worker(RTLIL::IdString v);\nvoid log_dump_val_worker(RTLIL::SigSpec v);\nvoid log_dump_val_worker(RTLIL::State v);\n\ntemplate<typename K, typename T> static inline void log_dump_val_worker(dict<K, T> &v);\ntemplate<typename K> static inline void log_dump_val_worker(pool<K> &v);\ntemplate<typename K> static inline void log_dump_val_worker(std::vector<K> &v);\ntemplate<typename T> static inline void log_dump_val_worker(T *ptr);\n\ntemplate<typename K, typename T>\nstatic inline void log_dump_val_worker(dict<K, T> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it.first);\n\t\tlog(\": \");\n\t\tlog_dump_val_worker(it.second);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename K>\nstatic inline void log_dump_val_worker(pool<K> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename K>\nstatic inline void log_dump_val_worker(std::vector<K> &v) {\n\tlog(\"{\");\n\tbool first = true;\n\tfor (auto &it : v) {\n\t\tlog(first ? \" \" : \", \");\n\t\tlog_dump_val_worker(it);\n\t\tfirst = false;\n\t}\n\tlog(\" }\");\n}\n\ntemplate<typename T>\nstatic inline void log_dump_val_worker(T *ptr) { log(\"%p\", ptr); }\n\ntemplate<typename T, typename ... Args>\nvoid log_dump_args_worker(const char *p, T first, Args ... args)\n{\n\tint next_p_state = 0;\n\tconst char *next_p = p;\n\twhile (*next_p && (next_p_state != 0 || *next_p != ',')) {\n\t\tif (*next_p == '\"')\n\t\t\tdo {\n\t\t\t\tnext_p++;\n\t\t\t\twhile (*next_p == '\\\\' && *(next_p + 1))\n\t\t\t\t\tnext_p += 2;\n\t\t\t} while (*next_p && *next_p != '\"');\n\t\tif (*next_p == '\\'') {\n\t\t\tnext_p++;\n\t\t\tif (*next_p == '\\\\')\n\t\t\t\tnext_p++;\n\t\t\tif (*next_p)\n\t\t\t\tnext_p++;\n\t\t}\n\t\tif (*next_p == '(' || *next_p == '[' || *next_p == '{')\n\t\t\tnext_p_state++;\n\t\tif ((*next_p == ')' || *next_p == ']' || *next_p == '}') && next_p_state > 0)\n\t\t\tnext_p_state--;\n\t\tnext_p++;\n\t}\n\tlog(\"\\n\\t%.*s => \", int(next_p - p), p);\n\tif (*next_p == ',')\n\t\tnext_p++;\n\twhile (*next_p == ' ' || *next_p == '\\t' || *next_p == '\\r' || *next_p == '\\n')\n\t\tnext_p++;\n\tlog_dump_val_worker(first);\n\tlog_dump_args_worker(next_p, args ...);\n}\n\n#define log_dump(...) do { \\\n\tlog(\"DEBUG DUMP IN %s AT %s:%d:\", __PRETTY_FUNCTION__, __FILE__, __LINE__); \\\n\tlog_dump_args_worker(#__VA_ARGS__, __VA_ARGS__); \\\n\tlog(\"\\n\"); \\\n} while (0)\n\nYOSYS_NAMESPACE_END\n\n#include \"kernel/yosys.h\"\n\n#endif\n",
|
|
180
180
|
"macc.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef MACC_H\n#define MACC_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct Macc\n{\n\tstruct term_t {\n\t\tRTLIL::SigSpec in_a, in_b;\n\t\tbool is_signed, do_subtract;\n\t};\n\tstd::vector<term_t> terms;\n\n\tvoid optimize(int width)\n\t{\n\t\tstd::vector<term_t> new_terms;\n\t\tRTLIL::Const off(0, width);\n\n\t\tfor (auto &port : terms)\n\t\t{\n\t\t\tif (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tif (GetSize(port.in_a) < GetSize(port.in_b))\n\t\t\t\tstd::swap(port.in_a, port.in_b);\n\n\t\t\tif (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {\n\t\t\t\tRTLIL::Const v = port.in_a.as_const();\n\t\t\t\tif (GetSize(port.in_b))\n\t\t\t\t\tv = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width);\n\t\t\t\tif (port.do_subtract)\n\t\t\t\t\toff = const_sub(off, v, port.is_signed, port.is_signed, width);\n\t\t\t\telse\n\t\t\t\t\toff = const_add(off, v, port.is_signed, port.is_signed, width);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (port.is_signed) {\n\t\t\t\twhile (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2])\n\t\t\t\t\tport.in_a.remove(GetSize(port.in_a)-1);\n\t\t\t\twhile (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2])\n\t\t\t\t\tport.in_b.remove(GetSize(port.in_b)-1);\n\t\t\t} else {\n\t\t\t\twhile (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == State::S0)\n\t\t\t\t\tport.in_a.remove(GetSize(port.in_a)-1);\n\t\t\t\twhile (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == State::S0)\n\t\t\t\t\tport.in_b.remove(GetSize(port.in_b)-1);\n\t\t\t}\n\n\t\t\tnew_terms.push_back(port);\n\t\t}\n\n\t\tif (off.as_bool()) {\n\t\t\tterm_t port;\n\t\t\tport.in_a = off;\n\t\t\tport.is_signed = false;\n\t\t\tport.do_subtract = false;\n\t\t\tnew_terms.push_back(port);\n\t\t}\n\n\t\tnew_terms.swap(terms);\n\t}\n\n\tvoid from_cell_v1(RTLIL::Cell *cell)\n\t{\n\t\tRTLIL::SigSpec port_a = cell->getPort(ID::A);\n\n\t\tterms.clear();\n\n\t\tauto config_bits = cell->getParam(ID::CONFIG);\n\t\tint config_cursor = 0;\n\n\t\tint config_width = cell->getParam(ID::CONFIG_WIDTH).as_int();\n\t\tlog_assert(GetSize(config_bits) >= config_width);\n\n\t\tint num_bits = 0;\n\t\tif (config_bits[config_cursor++] == State::S1) num_bits |= 1;\n\t\tif (config_bits[config_cursor++] == State::S1) num_bits |= 2;\n\t\tif (config_bits[config_cursor++] == State::S1) num_bits |= 4;\n\t\tif (config_bits[config_cursor++] == State::S1) num_bits |= 8;\n\n\t\tint port_a_cursor = 0;\n\t\twhile (port_a_cursor < GetSize(port_a))\n\t\t{\n\t\t\tlog_assert(config_cursor + 2 + 2*num_bits <= config_width);\n\n\t\t\tterm_t this_port;\n\t\t\tthis_port.is_signed = config_bits[config_cursor++] == State::S1;\n\t\t\tthis_port.do_subtract = config_bits[config_cursor++] == State::S1;\n\n\t\t\tint size_a = 0;\n\t\t\tfor (int i = 0; i < num_bits; i++)\n\t\t\t\tif (config_bits[config_cursor++] == State::S1)\n\t\t\t\t\tsize_a |= 1 << i;\n\n\t\t\tthis_port.in_a = port_a.extract(port_a_cursor, size_a);\n\t\t\tport_a_cursor += size_a;\n\n\t\t\tint size_b = 0;\n\t\t\tfor (int i = 0; i < num_bits; i++)\n\t\t\t\tif (config_bits[config_cursor++] == State::S1)\n\t\t\t\t\tsize_b |= 1 << i;\n\n\t\t\tthis_port.in_b = port_a.extract(port_a_cursor, size_b);\n\t\t\tport_a_cursor += size_b;\n\n\t\t\tif (size_a || size_b)\n\t\t\t\tterms.push_back(this_port);\n\t\t}\n\n\t\tfor (auto bit : cell->getPort(ID::B))\n\t\t\tterms.push_back(term_t{{bit}, {}, false, false});\n\n\t\tlog_assert(config_cursor == config_width);\n\t\tlog_assert(port_a_cursor == GetSize(port_a));\n\t}\n\n\tvoid from_cell(RTLIL::Cell *cell)\n\t{\n\t\tif (cell->type == ID($macc)) {\n\t\t\tfrom_cell_v1(cell);\n\t\t\treturn;\n\t\t}\n\t\tlog_assert(cell->type == ID($macc_v2));\n\n\t\tRTLIL::SigSpec port_a = cell->getPort(ID::A);\n\t\tRTLIL::SigSpec port_b = cell->getPort(ID::B);\n\t\tRTLIL::SigSpec port_c = cell->getPort(ID::C);\n\n\t\tterms.clear();\n\n\t\tint nproducts = cell->getParam(ID::NPRODUCTS).as_int();\n\t\tconst Const &product_neg = cell->getParam(ID::PRODUCT_NEGATED);\n\t\tconst Const &a_widths = cell->getParam(ID::A_WIDTHS);\n\t\tconst Const &b_widths = cell->getParam(ID::B_WIDTHS);\n\t\tconst Const &a_signed = cell->getParam(ID::A_SIGNED);\n\t\tconst Const &b_signed = cell->getParam(ID::B_SIGNED);\n\t\tint ai = 0, bi = 0;\n\t\tfor (int i = 0; i < nproducts; i++) {\n\t\t\tterm_t term;\n\n\t\t\tlog_assert(a_signed[i] == b_signed[i]);\n\t\t\tterm.is_signed = (a_signed[i] == State::S1);\n\t\t\tint a_width = a_widths.extract(16 * i, 16).as_int(false);\n\t\t\tint b_width = b_widths.extract(16 * i, 16).as_int(false);\n\n\t\t\tterm.in_a = port_a.extract(ai, a_width);\n\t\t\tai += a_width;\n\t\t\tterm.in_b = port_b.extract(bi, b_width);\n\t\t\tbi += b_width;\n\t\t\tterm.do_subtract = (product_neg[i] == State::S1);\n\n\t\t\tterms.push_back(term);\n\t\t}\n\t\tlog_assert(port_a.size() == ai);\n\t\tlog_assert(port_b.size() == bi);\n\n\t\tint naddends = cell->getParam(ID::NADDENDS).as_int();\n\t\tconst Const &addend_neg = cell->getParam(ID::ADDEND_NEGATED);\n\t\tconst Const &c_widths = cell->getParam(ID::C_WIDTHS);\n\t\tconst Const &c_signed = cell->getParam(ID::C_SIGNED);\n\t\tint ci = 0;\n\t\tfor (int i = 0; i < naddends; i++) {\n\t\t\tterm_t term;\n\n\t\t\tterm.is_signed = (c_signed[i] == State::S1);\n\t\t\tint c_width = c_widths.extract(16 * i, 16).as_int(false);\n\n\t\t\tterm.in_a = port_c.extract(ci, c_width);\n\t\t\tci += c_width;\n\t\t\tterm.do_subtract = (addend_neg[i] == State::S1);\n\n\t\t\tterms.push_back(term);\n\t\t}\n\t\tlog_assert(port_c.size() == ci);\n\t}\n\n\tvoid to_cell(RTLIL::Cell *cell)\n\t{\n\t\tcell->type = ID($macc_v2);\n\n\t\tint nproducts = 0, naddends = 0;\n\t\tConst a_signed, b_signed, a_widths, b_widths, product_negated;\n\t\tConst c_signed, c_widths, addend_negated;\n\t\tSigSpec a, b, c;\n\n\t\tfor (int i = 0; i < (int) terms.size(); i++) {\n\t\t\tSigSpec term_a = terms[i].in_a, term_b = terms[i].in_b;\n\n\t\t\tif (term_b.empty()) {\n\t\t\t\t// addend\n\t\t\t\tc_widths.append(Const(term_a.size(), 16));\n\t\t\t\tc_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);\n\t\t\t\taddend_negated.append(terms[i].do_subtract ? RTLIL::S1 : RTLIL::S0);\n\t\t\t\tc.append(term_a);\n\t\t\t\tnaddends++;\n\t\t\t} else {\n\t\t\t\t// product\n\t\t\t\ta_widths.append(Const(term_a.size(), 16));\n\t\t\t\tb_widths.append(Const(term_b.size(), 16));\n\t\t\t\ta_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);\n\t\t\t\tb_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);\n\t\t\t\tproduct_negated.append(terms[i].do_subtract ? RTLIL::S1 : RTLIL::S0);\n\t\t\t\ta.append(term_a);\n\t\t\t\tb.append(term_b);\n\t\t\t\tnproducts++;\n\t\t\t}\n\t\t}\n\n\t\tif (a_signed.empty())\n\t\t\ta_signed = {RTLIL::Sx};\n\t\tif (b_signed.empty())\n\t\t\tb_signed = {RTLIL::Sx};\n\t\tif (c_signed.empty())\n\t\t\tc_signed = {RTLIL::Sx};\n\t\tif (a_widths.empty())\n\t\t\ta_widths = {RTLIL::Sx};\n\t\tif (b_widths.empty())\n\t\t\tb_widths = {RTLIL::Sx};\n\t\tif (c_widths.empty())\n\t\t\tc_widths = {RTLIL::Sx};\n\t\tif (product_negated.empty())\n\t\t\tproduct_negated = {RTLIL::Sx};\n\t\tif (addend_negated.empty())\n\t\t\taddend_negated = {RTLIL::Sx};\n\n\t\tcell->setParam(ID::NPRODUCTS, nproducts);\n\t\tcell->setParam(ID::PRODUCT_NEGATED, product_negated);\n\t\tcell->setParam(ID::NADDENDS, naddends);\n\t\tcell->setParam(ID::ADDEND_NEGATED, addend_negated);\n\t\tcell->setParam(ID::A_SIGNED, a_signed);\n\t\tcell->setParam(ID::B_SIGNED, b_signed);\n\t\tcell->setParam(ID::C_SIGNED, c_signed);\n\t\tcell->setParam(ID::A_WIDTHS, a_widths);\n\t\tcell->setParam(ID::B_WIDTHS, b_widths);\n\t\tcell->setParam(ID::C_WIDTHS, c_widths);\n\t\tcell->setPort(ID::A, a);\n\t\tcell->setPort(ID::B, b);\n\t\tcell->setPort(ID::C, c);\n\t}\n\n\tbool eval(RTLIL::Const &result) const\n\t{\n\t\tfor (auto &bit : result.bits())\n\t\t\tbit = State::S0;\n\n\t\tfor (auto &port : terms)\n\t\t{\n\t\t\tif (!port.in_a.is_fully_const() || !port.in_b.is_fully_const())\n\t\t\t\treturn false;\n\n\t\t\tRTLIL::Const summand;\n\t\t\tif (GetSize(port.in_b) == 0)\n\t\t\t\tsummand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));\n\t\t\telse\n\t\t\t\tsummand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));\n\n\t\t\tif (port.do_subtract)\n\t\t\t\tresult = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result));\n\t\t\telse\n\t\t\t\tresult = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result));\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool is_simple_product()\n\t{\n\t\treturn terms.size() == 1 &&\n\t\t\t\t!terms[0].in_b.empty() &&\n\t\t\t\t!terms[0].do_subtract;\n\t}\n\n\tMacc(RTLIL::Cell *cell = nullptr)\n\t{\n\t\tif (cell != nullptr)\n\t\t\tfrom_cell(cell);\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
181
181
|
"mem.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef MEM_H\n#define MEM_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/ffinit.h\"\n#include \"kernel/utils.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct MemRd : RTLIL::AttrObject {\n\tbool removed;\n\tCell *cell;\n\tint wide_log2;\n\tbool clk_enable, clk_polarity, ce_over_srst;\n\tConst arst_value, srst_value, init_value;\n\t// One bit for every write port, true iff simultanous read on this\n\t// port and write on the other port will bypass the written data\n\t// to this port's output (default behavior is to read old value).\n\t// Can only be set for write ports that have the same clock domain.\n\tstd::vector<bool> transparency_mask;\n\t// One bit for every write port, true iff simultanous read on this\n\t// port and write on the other port will return an all-X (don't care)\n\t// value. Mutually exclusive with transparency_mask.\n\t// Can only be set for write ports that have the same clock domain.\n\t// For optimization purposes, this will also be set if we can\n\t// determine that the two ports can never be active simultanously\n\t// (making the above vacuously true).\n\tstd::vector<bool> collision_x_mask;\n\tSigSpec clk, en, arst, srst, addr, data;\n\n\tMemRd() : removed(false), cell(nullptr), wide_log2(0), clk_enable(false), clk_polarity(true), ce_over_srst(false), clk(State::Sx), en(State::S1), arst(State::S0), srst(State::S0) {}\n\n\t// Returns the address of given subword index accessed by this port.\n\tSigSpec sub_addr(int sub) {\n\t\tSigSpec res = addr;\n\t\tfor (int i = 0; i < wide_log2; i++)\n\t\t\tres[i] = State(sub >> i & 1);\n\t\treturn res;\n\t}\n};\n\nstruct MemWr : RTLIL::AttrObject {\n\tbool removed;\n\tCell *cell;\n\tint wide_log2;\n\tbool clk_enable, clk_polarity;\n\tstd::vector<bool> priority_mask;\n\tSigSpec clk, en, addr, data;\n\n\tMemWr() : removed(false), cell(nullptr) {}\n\n\t// Returns the address of given subword index accessed by this port.\n\tSigSpec sub_addr(int sub) {\n\t\tSigSpec res = addr;\n\t\tfor (int i = 0; i < wide_log2; i++)\n\t\t\tres[i] = State(sub >> i & 1);\n\t\treturn res;\n\t}\n\n\tstd::pair<SigSpec, std::vector<int>> compress_en();\n\tSigSpec decompress_en(const std::vector<int> &swizzle, SigSpec sig);\n};\n\nstruct MemInit : RTLIL::AttrObject {\n\tbool removed;\n\tCell *cell;\n\tConst addr;\n\tConst data;\n\tConst en;\n\tMemInit() : removed(false), cell(nullptr) {}\n};\n\nstruct Mem : RTLIL::AttrObject {\n\tModule *module;\n\tIdString memid;\n\tbool packed;\n\tRTLIL::Memory *mem;\n\tCell *cell;\n\tint width, start_offset, size;\n\tstd::vector<MemInit> inits;\n\tstd::vector<MemRd> rd_ports;\n\tstd::vector<MemWr> wr_ports;\n\n\t// Removes this memory from the module. The data in helper structures\n\t// is unaffected except for the cell/mem fields.\n\tvoid remove();\n\n\t// Commits all changes in helper structures into the module — ports and\n\t// inits marked as removed are actually removed, new ports/inits create\n\t// new cells, modified port/inits are commited into their existing\n\t// cells. Note that this reindexes the ports and inits array (actually\n\t// removing the ports/inits marked as removed).\n\tvoid emit();\n\n\t// Marks all inits as removed.\n\tvoid clear_inits();\n\n\t// Coalesces inits: whenever two inits have overlapping or touching\n\t// address ranges, they are combined into one, with the higher-priority\n\t// one's data overwriting the other. Running this results in\n\t// an inits list equivalent to the original, in which all entries\n\t// cover disjoint (and non-touching) address ranges, and all enable\n\t// masks are all-1.\n\tvoid coalesce_inits();\n\n\t// Checks consistency of this memory and all its ports/inits, using\n\t// log_assert.\n\tvoid check();\n\n\t// Gathers all initialization data into a single big const covering\n\t// the whole memory. For all non-initialized bits, Sx will be returned.\n\tConst get_init_data() const;\n\n\t// Constructs and returns the helper structures for all memories\n\t// in a module.\n\tstatic std::vector<Mem> get_all_memories(Module *module);\n\n\t// Constructs and returns the helper structures for all selected\n\t// memories in a module.\n\tstatic std::vector<Mem> get_selected_memories(Module *module);\n\n\t// Converts a synchronous read port into an asynchronous one by\n\t// extracting the data (or, in some rare cases, address) register\n\t// into a separate cell, together with any soft-transparency\n\t// logic necessary to preserve its semantics. Returns the created\n\t// register cell, if any. Note that in some rare cases this function\n\t// may succeed and perform a conversion without creating a new\n\t// register — a nullptr result doesn't imply nothing was done.\n\tCell *extract_rdff(int idx, FfInitVals *initvals);\n\n\t// Splits all wide ports in this memory into equivalent narrow ones.\n\t// This function performs no modifications at all to the actual\n\t// netlist unless and until emit() is called.\n\tvoid narrow();\n\n\t// If write port idx2 currently has priority over write port idx1,\n\t// inserts extra logic on idx1's enable signal to disable writes\n\t// when idx2 is writing to the same address, then removes the priority\n\t// from the priority mask. If there is a memory port that is\n\t// transparent with idx1, but not with idx2, that port is converted\n\t// to use soft transparency logic.\n\tvoid emulate_priority(int idx1, int idx2, FfInitVals *initvals);\n\n\t// Creates soft-transparency logic on read port ridx, bypassing the\n\t// data from write port widx. Should only be called when ridx is\n\t// transparent wrt widx in the first place. Once we're done, the\n\t// transparency_mask bit will be cleared, and the collision_x_mask\n\t// bit will be set instead (since whatever value is read will be\n\t// replaced by the soft transparency logic).\n\tvoid emulate_transparency(int widx, int ridx, FfInitVals *initvals);\n\n\t// Prepares for merging write port idx2 into idx1 (where idx1 < idx2).\n\t// Specifically, takes care of priority masks: any priority relations\n\t// that idx2 had are replicated onto idx1, unless they conflict with\n\t// priorities already present on idx1, in which case emulate_priority\n\t// is called. Likewise, ensures transparency and undefined collision\n\t// masks of all read ports have the same values for both ports,\n\t// calling emulate_transparency if necessary.\n\tvoid prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals);\n\n\t// Prepares for merging read port idx2 into idx1.\n\t// Specifically, makes sure the transparency and undefined collision\n\t// masks of both ports are equal, by changing undefined behavior\n\t// of one port to the other's defined behavior, or by calling\n\t// emulate_transparency if necessary.\n\tvoid prepare_rd_merge(int idx1, int idx2, FfInitVals *initvals);\n\n\t// Prepares the memory for widening a port to a given width. This\n\t// involves ensuring that start_offset and size are aligned to the\n\t// target width.\n\tvoid widen_prep(int wide_log2);\n\n\t// Widens a write port up to a given width. The newly port is\n\t// equivalent to the original, made by replicating enable/data bits\n\t// and masking enable bits with decoders on the low part of the\n\t// original address.\n\tvoid widen_wr_port(int idx, int wide_log2);\n\n\t// Emulates a sync read port's enable functionality in soft logic,\n\t// changing the actual read port's enable to be always-on.\n\tvoid emulate_rden(int idx, FfInitVals *initvals);\n\n\t// Emulates a sync read port's initial/reset value functionality in\n\t// soft logic, removing it from the actual read port.\n\tvoid emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals);\n\n\t// Given a read port with ce_over_srst set, converts it to a port\n\t// with ce_over_srst unset without changing its behavior by adding\n\t// emulation logic.\n\tvoid emulate_rd_ce_over_srst(int idx);\n\n\t// Given a read port with ce_over_srst unset, converts it to a port\n\t// with ce_over_srst set without changing its behavior by adding\n\t// emulation logic.\n\tvoid emulate_rd_srst_over_ce(int idx);\n\n\t// Returns true iff emulate_read_first makes sense to call.\n\tbool emulate_read_first_ok();\n\n\t// Emulates all read-first read-write port relationships in terms of\n\t// all-transparent ports, by delaying all write ports by one cycle.\n\t// This can only be used when all read ports and all write ports are\n\t// in the same clock domain.\n\tvoid emulate_read_first(FfInitVals *initvals);\n\n\tMem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}\n};\n\n// MemContents efficiently represents the contents of a potentially sparse memory by storing only those segments that are actually defined\nclass MemContents {\npublic:\n\tclass range; class iterator;\n\tusing addr_t = uint32_t;\nprivate:\n\t// we ban _addr_width == sizeof(addr_t) * 8 because it adds too many cornercases\n\tint _addr_width;\n\tint _data_width;\n\tRTLIL::Const _default_value;\n\t// for each range, store the concatenation of the words at the start address\n\t// invariants:\n\t// - no overlapping or adjacent ranges\n\t// - no empty ranges\n\t// - all Consts are a multiple of the word size\n\tstd::map<addr_t, RTLIL::Const> _values;\n\t// returns an iterator to the range containing addr, if it exists, or the first range past addr\n\tstd::map<addr_t, RTLIL::Const>::iterator _range_at(addr_t addr) const;\n\taddr_t _range_size(std::map<addr_t, RTLIL::Const>::iterator it) const { return it->second.size() / _data_width; }\n\taddr_t _range_begin(std::map<addr_t, RTLIL::Const>::iterator it) const { return it->first; }\n\taddr_t _range_end(std::map<addr_t, RTLIL::Const>::iterator it) const { return _range_begin(it) + _range_size(it); }\n\t// check if the iterator points to a range containing addr\n\tbool _range_contains(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) const;\n\t// check if the iterator points to a range containing [begin_addr, end_addr). assumes end_addr >= begin_addr.\n\tbool _range_contains(std::map<addr_t, RTLIL::Const>::iterator it, addr_t begin_addr, addr_t end_addr) const;\n\t// check if the iterator points to a range overlapping with [begin_addr, end_addr)\n\tbool _range_overlaps(std::map<addr_t, RTLIL::Const>::iterator it, addr_t begin_addr, addr_t end_addr) const;\n\t// return the offset the addr would have in the range at `it`\n\tsize_t _range_offset(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) const { return (addr - it->first) * _data_width; }\n\t// assuming _range_contains(it, addr), return an iterator pointing to the data at addr\n\tstd::vector<State>::iterator _range_data(std::map<addr_t, RTLIL::Const>::iterator it, addr_t addr) { return it->second.bits().begin() + _range_offset(it, addr); }\n\t// internal version of reserve_range that returns an iterator to the range\n\tstd::map<addr_t, RTLIL::Const>::iterator _reserve_range(addr_t begin_addr, addr_t end_addr);\n\t// write a single word at addr, return iterator to next word\n\tstd::vector<State>::iterator _range_write(std::vector<State>::iterator it, RTLIL::Const const &data);\npublic:\n\tclass range {\n\t\tint _data_width;\n\t\taddr_t _base;\n\t\tRTLIL::Const const &_values;\n\t\tfriend class iterator;\n\t\trange(int data_width, addr_t base, RTLIL::Const const &values)\n\t\t: _data_width(data_width), _base(base), _values(values) {}\n\tpublic:\n\t\taddr_t base() const { return _base; }\n\t\taddr_t size() const { return ((addr_t) _values.size()) / _data_width; }\n\t\taddr_t limit() const { return _base + size(); }\n\t\tRTLIL::Const const &concatenated() const { return _values; }\n\t\tRTLIL::Const operator[](addr_t addr) const {\n\t\t\tlog_assert(addr - _base < size());\n\t\t\treturn _values.extract((addr - _base) * _data_width, _data_width);\n\t\t}\n\t\tRTLIL::Const at_offset(addr_t offset) const { return (*this)[_base + offset]; }\n\t};\n\tclass iterator {\n\t\tMemContents const *_memory;\n\t\t// storing addr instead of an iterator gives more well-defined behaviour under insertions/deletions\n\t\t// use ~0 for end so that all end iterators compare the same\n\t\taddr_t _addr;\n\t\tfriend class MemContents;\n\t\titerator(MemContents const *memory, addr_t addr) : _memory(memory), _addr(addr) {}\n\tpublic:\n\t\tusing iterator_category = std::input_iterator_tag;\n\t\tusing value_type = range;\n\t\tusing pointer = arrow_proxy<range>;\n\t\tusing reference = range;\n\t\tusing difference_type = addr_t;\n\t\treference operator *() const { return range(_memory->_data_width, _addr, _memory->_values.at(_addr)); }\n\t\tpointer operator->() const { return arrow_proxy<range>(**this); }\n\t\tbool operator !=(iterator const &other) const { return _memory != other._memory || _addr != other._addr; }\n\t\tbool operator ==(iterator const &other) const { return !(*this != other); }\n\t\titerator &operator++();\n\t};\n\tMemContents(int addr_width, int data_width, RTLIL::Const default_value)\n\t\t: _addr_width(addr_width), _data_width(data_width)\n\t\t, _default_value((default_value.extu(data_width), std::move(default_value)))\n\t{ log_assert(_addr_width > 0 && _addr_width < (int)sizeof(addr_t) * 8); log_assert(_data_width > 0); }\n\tMemContents(int addr_width, int data_width) : MemContents(addr_width, data_width, RTLIL::Const(State::Sx, data_width)) {}\n\texplicit MemContents(Mem *mem);\n\tint addr_width() const { return _addr_width; }\n\tint data_width() const { return _data_width; }\n\tRTLIL::Const const &default_value() const { return _default_value; }\n\t// return the value at the address if it exists, the default_value of the memory otherwise. address must not exceed 2**addr_width.\n\tRTLIL::Const operator [](addr_t addr) const;\n\t// return the number of defined words in the range [begin_addr, end_addr)\n\taddr_t count_range(addr_t begin_addr, addr_t end_addr) const;\n\t// allocate memory for the range [begin_addr, end_addr), but leave the contents undefined.\n\tvoid reserve_range(addr_t begin_addr, addr_t end_addr) { _reserve_range(begin_addr, end_addr); }\n\t// insert multiple words (provided as a single concatenated RTLIL::Const) at the given address, overriding any previous assignment.\n\tvoid insert_concatenated(addr_t addr, RTLIL::Const const &values);\n\t// insert multiple words at the given address, overriding any previous assignment.\n\ttemplate<typename Iterator> void insert_range(addr_t addr, Iterator begin, Iterator end) {\n\t\tauto words = end - begin;\n\t\tlog_assert(addr < (addr_t)(1<<_addr_width)); log_assert(words <= (addr_t)(1<<_addr_width) - addr);\n\t\tauto range = _reserve_range(addr, addr + words);\n\t\tauto it = _range_data(range, addr);\n\t\tfor(; begin != end; ++begin)\n\t\t\tit = _range_write(it, *begin);\n\t}\n\t// undefine all words in the range [begin_addr, end_addr)\n\tvoid clear_range(addr_t begin_addr, addr_t end_addr);\n\t// check invariants, abort if invariants failed\n\tvoid check();\n\titerator end() const { return iterator(nullptr, ~(addr_t) 0); }\n\titerator begin() const { return _values.empty() ? end() : iterator(this, _values.begin()->first); }\n\tbool empty() const { return _values.empty(); }\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
182
182
|
"modtools.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef MODTOOLS_H\n#define MODTOOLS_H\n\n#include \"kernel/yosys.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct ModIndex : public RTLIL::Monitor\n{\n\tstruct PortInfo {\n\t\tRTLIL::Cell* cell;\n\t\tRTLIL::IdString port;\n\t\tint offset;\n\n\t\tPortInfo() : cell(), port(), offset() { }\n\t\tPortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }\n\n\t\tbool operator<(const PortInfo &other) const {\n\t\t\tif (cell != other.cell)\n\t\t\t\treturn cell < other.cell;\n\t\t\tif (offset != other.offset)\n\t\t\t\treturn offset < other.offset;\n\t\t\treturn port < other.port;\n\t\t}\n\n\t\tbool operator==(const PortInfo &other) const {\n\t\t\treturn cell == other.cell && port == other.port && offset == other.offset;\n\t\t}\n\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(cell->name);\n\t\t\th.eat(port);\n\t\t\th.eat(offset);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tstruct SigBitInfo\n\t{\n\t\tbool is_input, is_output;\n\t\tpool<PortInfo> ports;\n\n\t\tSigBitInfo() : is_input(false), is_output(false) { }\n\n\t\tbool operator==(const SigBitInfo &other) const {\n\t\t\treturn is_input == other.is_input && is_output == other.is_output && ports == other.ports;\n\t\t}\n\n\t\tvoid merge(const SigBitInfo &other)\n\t\t{\n\t\t\tis_input = is_input || other.is_input;\n\t\t\tis_output = is_output || other.is_output;\n\t\t\tports.insert(other.ports.begin(), other.ports.end());\n\t\t}\n\t};\n\n\tSigMap sigmap;\n\tRTLIL::Module *module;\n\tstd::map<RTLIL::SigBit, SigBitInfo> database;\n\tint auto_reload_counter;\n\tbool auto_reload_module;\n\n\tvoid port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (int i = 0; i < GetSize(sig); i++) {\n\t\t\tRTLIL::SigBit bit = sigmap(sig[i]);\n\t\t\tif (bit.wire)\n\t\t\t\tdatabase[bit].ports.insert(PortInfo(cell, port, i));\n\t\t}\n\t}\n\n\tvoid port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (int i = 0; i < GetSize(sig); i++) {\n\t\t\tRTLIL::SigBit bit = sigmap(sig[i]);\n\t\t\tif (bit.wire)\n\t\t\t\tdatabase[bit].ports.erase(PortInfo(cell, port, i));\n\t\t}\n\t}\n\n\tconst SigBitInfo &info(RTLIL::SigBit bit)\n\t{\n\t\treturn database[sigmap(bit)];\n\t}\n\n\tvoid reload_module(bool reset_sigmap = true)\n\t{\n\t\tif (reset_sigmap) {\n\t\t\tsigmap.clear();\n\t\t\tsigmap.set(module);\n\t\t}\n\n\t\tdatabase.clear();\n\t\tfor (auto wire : module->wires())\n\t\t\tif (wire->port_input || wire->port_output)\n\t\t\t\tfor (int i = 0; i < GetSize(wire); i++) {\n\t\t\t\t\tRTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));\n\t\t\t\t\tif (bit.wire && wire->port_input)\n\t\t\t\t\t\tdatabase[bit].is_input = true;\n\t\t\t\t\tif (bit.wire && wire->port_output)\n\t\t\t\t\t\tdatabase[bit].is_output = true;\n\t\t\t\t}\n\t\tfor (auto cell : module->cells())\n\t\t\tfor (auto &conn : cell->connections())\n\t\t\t\tport_add(cell, conn.first, conn.second);\n\n\t\tif (auto_reload_module) {\n\t\t\tif (++auto_reload_counter > 2)\n\t\t\t\tlog_warning(\"Auto-reload in ModIndex -- possible performance bug!\\n\");\n\t\t\tauto_reload_module = false;\n\t\t}\n\t}\n\n\tvoid check()\n\t{\n#ifndef NDEBUG\n\t\tif (auto_reload_module)\n\t\t\treturn;\n\n\t\tfor (auto it : database)\n\t\t\tlog_assert(it.first == sigmap(it.first));\n\n\t\tauto database_bak = std::move(database);\n\t\treload_module(false);\n\n\t\tif (!(database == database_bak))\n\t\t{\n\t\t\tfor (auto &it : database_bak)\n\t\t\t\tif (!database.count(it.first))\n\t\t\t\t\tlog(\"ModuleIndex::check(): Only in database_bak, not database: %s\\n\", log_signal(it.first));\n\n\t\t\tfor (auto &it : database)\n\t\t\t\tif (!database_bak.count(it.first))\n\t\t\t\t\tlog(\"ModuleIndex::check(): Only in database, not database_bak: %s\\n\", log_signal(it.first));\n\t\t\t\telse if (!(it.second == database_bak.at(it.first)))\n\t\t\t\t\tlog(\"ModuleIndex::check(): Different content for database[%s].\\n\", log_signal(it.first));\n\n\t\t\tlog_assert(database == database_bak);\n\t\t}\n#endif\n\t}\n\n\tvoid notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override\n\t{\n\t\tlog_assert(module == cell->module);\n\n\t\tif (auto_reload_module)\n\t\t\treturn;\n\n\t\tport_del(cell, port, old_sig);\n\t\tport_add(cell, port, sig);\n\t}\n\n\tvoid notify_connect(RTLIL::Module *mod, const RTLIL::SigSig &sigsig) override\n\t{\n\t\tlog_assert(module == mod);\n\n\t\tif (auto_reload_module)\n\t\t\treturn;\n\n\t\tfor (int i = 0; i < GetSize(sigsig.first); i++)\n\t\t{\n\t\t\tRTLIL::SigBit lhs = sigmap(sigsig.first[i]);\n\t\t\tRTLIL::SigBit rhs = sigmap(sigsig.second[i]);\n\t\t\tbool has_lhs = database.count(lhs) != 0;\n\t\t\tbool has_rhs = database.count(rhs) != 0;\n\n\t\t\tif (!has_lhs && !has_rhs) {\n\t\t\t\tsigmap.add(lhs, rhs);\n\t\t\t} else\n\t\t\tif (!has_rhs) {\n\t\t\t\tSigBitInfo new_info = database.at(lhs);\n\t\t\t\tdatabase.erase(lhs);\n\t\t\t\tsigmap.add(lhs, rhs);\n\t\t\t\tlhs = sigmap(lhs);\n\t\t\t\tif (lhs.wire)\n\t\t\t\t\tdatabase[lhs] = new_info;\n\t\t\t} else\n\t\t\tif (!has_lhs) {\n\t\t\t\tSigBitInfo new_info = database.at(rhs);\n\t\t\t\tdatabase.erase(rhs);\n\t\t\t\tsigmap.add(lhs, rhs);\n\t\t\t\trhs = sigmap(rhs);\n\t\t\t\tif (rhs.wire)\n\t\t\t\t\tdatabase[rhs] = new_info;\n\t\t\t} else {\n\t\t\t\tSigBitInfo new_info = database.at(lhs);\n\t\t\t\tnew_info.merge(database.at(rhs));\n\t\t\t\tdatabase.erase(lhs);\n\t\t\t\tdatabase.erase(rhs);\n\t\t\t\tsigmap.add(lhs, rhs);\n\t\t\t\trhs = sigmap(rhs);\n\t\t\t\tif (rhs.wire)\n\t\t\t\t\tdatabase[rhs] = new_info;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&) override\n\t{\n\t\tlog_assert(module == mod);\n\t\tauto_reload_module = true;\n\t}\n\n\tvoid notify_blackout(RTLIL::Module *mod) override\n\t{\n\t\tlog_assert(module == mod);\n\t\tauto_reload_module = true;\n\t}\n\n\tModIndex(RTLIL::Module *_m) : sigmap(_m), module(_m)\n\t{\n\t\tauto_reload_counter = 0;\n\t\tauto_reload_module = true;\n\t\tmodule->monitors.insert(this);\n\t}\n\n\t~ModIndex()\n\t{\n\t\tmodule->monitors.erase(this);\n\t}\n\n\tSigBitInfo *query(RTLIL::SigBit bit)\n\t{\n\t\tif (auto_reload_module)\n\t\t\treload_module();\n\n\t\tauto it = database.find(sigmap(bit));\n\t\tif (it == database.end())\n\t\t\treturn nullptr;\n\t\telse\n\t\t\treturn &it->second;\n\t}\n\n\tbool query_is_input(RTLIL::SigBit bit)\n\t{\n\t\tconst SigBitInfo *info = query(bit);\n\t\tif (info == nullptr)\n\t\t\treturn false;\n\t\treturn info->is_input;\n\t}\n\n\tbool query_is_output(RTLIL::SigBit bit)\n\t{\n\t\tconst SigBitInfo *info = query(bit);\n\t\tif (info == nullptr)\n\t\t\treturn false;\n\t\treturn info->is_output;\n\t}\n\n\tpool<PortInfo> &query_ports(RTLIL::SigBit bit)\n\t{\n\t\tstatic pool<PortInfo> empty_result_set;\n\t\tSigBitInfo *info = query(bit);\n\t\tif (info == nullptr)\n\t\t\treturn empty_result_set;\n\t\treturn info->ports;\n\t}\n\n\tvoid dump_db()\n\t{\n\t\tlog(\"--- ModIndex Dump ---\\n\");\n\n\t\tif (auto_reload_module) {\n\t\t\tlog(\"AUTO-RELOAD\\n\");\n\t\t\treload_module();\n\t\t}\n\n\t\tfor (auto &it : database) {\n\t\t\tlog(\"BIT %s:\\n\", log_signal(it.first));\n\t\t\tif (it.second.is_input)\n\t\t\t\tlog(\" PRIMARY INPUT\\n\");\n\t\t\tif (it.second.is_output)\n\t\t\t\tlog(\" PRIMARY OUTPUT\\n\");\n\t\t\tfor (auto &port : it.second.ports)\n\t\t\t\tlog(\" PORT: %s.%s[%d] (%s)\\n\", log_id(port.cell),\n\t\t\t\t\t\tlog_id(port.port), port.offset, log_id(port.cell->type));\n\t\t}\n\t}\n};\n\nstruct ModWalker\n{\n\tstruct PortBit\n\t{\n\t\tRTLIL::Cell *cell;\n\t\tRTLIL::IdString port;\n\t\tint offset;\n\t\tPortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {}\n\n\t\tbool operator<(const PortBit &other) const {\n\t\t\tif (cell != other.cell)\n\t\t\t\treturn cell < other.cell;\n\t\t\tif (port != other.port)\n\t\t\t\treturn port < other.port;\n\t\t\treturn offset < other.offset;\n\t\t}\n\n\t\tbool operator==(const PortBit &other) const {\n\t\t\treturn cell == other.cell && port == other.port && offset == other.offset;\n\t\t}\n\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(cell->name);\n\t\t\th.eat(port);\n\t\t\th.eat(offset);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tRTLIL::Design *design;\n\tRTLIL::Module *module;\n\n\tCellTypes ct;\n\tSigMap sigmap;\n\n\tdict<RTLIL::SigBit, pool<PortBit>> signal_drivers;\n\tdict<RTLIL::SigBit, pool<PortBit>> signal_consumers;\n\tpool<RTLIL::SigBit> signal_inputs, signal_outputs;\n\n\tdict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_outputs, cell_inputs;\n\n\tvoid add_wire(RTLIL::Wire *wire)\n\t{\n\t\tif (wire->port_input) {\n\t\t\tstd::vector<RTLIL::SigBit> bits = sigmap(wire);\n\t\t\tfor (auto bit : bits)\n\t\t\t\tif (bit.wire != NULL)\n\t\t\t\t\tsignal_inputs.insert(bit);\n\t\t}\n\n\t\tif (wire->port_output) {\n\t\t\tstd::vector<RTLIL::SigBit> bits = sigmap(wire);\n\t\t\tfor (auto bit : bits)\n\t\t\t\tif (bit.wire != NULL)\n\t\t\t\t\tsignal_outputs.insert(bit);\n\t\t}\n\t}\n\n\tvoid add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector<RTLIL::SigBit> bits, bool is_output, bool is_input)\n\t{\n\t\tfor (int i = 0; i < int(bits.size()); i++)\n\t\t\tif (bits[i].wire != NULL) {\n\t\t\t\tPortBit pbit {cell, port, i};\n\t\t\t\tif (is_output) {\n\t\t\t\t\tsignal_drivers[bits[i]].insert(pbit);\n\t\t\t\t\tcell_outputs[cell].insert(bits[i]);\n\t\t\t\t}\n\t\t\t\tif (is_input) {\n\t\t\t\t\tsignal_consumers[bits[i]].insert(pbit);\n\t\t\t\t\tcell_inputs[cell].insert(bits[i]);\n\t\t\t\t}\n\t\t\t}\n\t}\n\n\tvoid add_cell(RTLIL::Cell *cell)\n\t{\n\t\tif (ct.cell_known(cell->type)) {\n\t\t\tfor (auto &conn : cell->connections())\n\t\t\t\tadd_cell_port(cell, conn.first, sigmap(conn.second),\n\t\t\t\t\t\tct.cell_output(cell->type, conn.first),\n\t\t\t\t\t\tct.cell_input(cell->type, conn.first));\n\t\t} else {\n\t\t\tfor (auto &conn : cell->connections())\n\t\t\t\tadd_cell_port(cell, conn.first, sigmap(conn.second), true, true);\n\t\t}\n\t}\n\n\tModWalker(RTLIL::Design *design, RTLIL::Module *module = nullptr) : design(design), module(NULL)\n\t{\n\t\tct.setup(design);\n\t\tif (module)\n\t\t\tsetup(module);\n\t}\n\n\tvoid setup(RTLIL::Module *module, CellTypes *filter_ct = NULL)\n\t{\n\t\tthis->module = module;\n\n\t\tsigmap.set(module);\n\n\t\tsignal_drivers.clear();\n\t\tsignal_consumers.clear();\n\t\tsignal_inputs.clear();\n\t\tsignal_outputs.clear();\n\t\tcell_inputs.clear();\n\t\tcell_outputs.clear();\n\n\t\tfor (auto &it : module->wires_)\n\t\t\tadd_wire(it.second);\n\t\tfor (auto &it : module->cells_)\n\t\t\tif (filter_ct == NULL || filter_ct->cell_known(it.second->type))\n\t\t\t\tadd_cell(it.second);\n\t}\n\n\t// get_* methods -- single RTLIL::SigBit\n\n\tinline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const\n\t{\n\t\tbool found = false;\n\t\tif (signal_drivers.count(bit)) {\n\t\t\tconst pool<PortBit> &r = signal_drivers.at(bit);\n\t\t\tresult.insert(r.begin(), r.end());\n\t\t\tfound = true;\n\t\t}\n\t\treturn found;\n\t}\n\n\tinline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const\n\t{\n\t\tbool found = false;\n\t\tif (signal_consumers.count(bit)) {\n\t\t\tconst pool<PortBit> &r = signal_consumers.at(bit);\n\t\t\tresult.insert(r.begin(), r.end());\n\t\t\tfound = true;\n\t\t}\n\t\treturn found;\n\t}\n\n\tinline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const\n\t{\n\t\tbool found = false;\n\t\tif (signal_inputs.count(bit))\n\t\t\tresult.insert(bit), found = true;\n\t\treturn found;\n\t}\n\n\tinline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const\n\t{\n\t\tbool found = false;\n\t\tif (signal_outputs.count(bit))\n\t\t\tresult.insert(bit), found = true;\n\t\treturn found;\n\t}\n\n\t// get_* methods -- container of RTLIL::SigBit's (always by reference)\n\n\ttemplate<typename T>\n\tinline bool get_drivers(pool<PortBit> &result, const T &bits) const\n\t{\n\t\tbool found = false;\n\t\tfor (RTLIL::SigBit bit : bits)\n\t\t\tif (signal_drivers.count(bit)) {\n\t\t\t\tconst pool<PortBit> &r = signal_drivers.at(bit);\n\t\t\t\tresult.insert(r.begin(), r.end());\n\t\t\t\tfound = true;\n\t\t\t}\n\t\treturn found;\n\t}\n\n\ttemplate<typename T>\n\tinline bool get_consumers(pool<PortBit> &result, const T &bits) const\n\t{\n\t\tbool found = false;\n\t\tfor (RTLIL::SigBit bit : bits)\n\t\t\tif (signal_consumers.count(bit)) {\n\t\t\t\tconst pool<PortBit> &r = signal_consumers.at(bit);\n\t\t\t\tresult.insert(r.begin(), r.end());\n\t\t\t\tfound = true;\n\t\t\t}\n\t\treturn found;\n\t}\n\n\ttemplate<typename T>\n\tinline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const\n\t{\n\t\tbool found = false;\n\t\tfor (RTLIL::SigBit bit : bits)\n\t\t\tif (signal_inputs.count(bit))\n\t\t\t\tresult.insert(bit), found = true;\n\t\treturn found;\n\t}\n\n\ttemplate<typename T>\n\tinline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const\n\t{\n\t\tbool found = false;\n\t\tfor (RTLIL::SigBit bit : bits)\n\t\t\tif (signal_outputs.count(bit))\n\t\t\t\tresult.insert(bit), found = true;\n\t\treturn found;\n\t}\n\n\t// get_* methods -- call by RTLIL::SigSpec (always by value)\n\n\tbool get_drivers(pool<PortBit> &result, RTLIL::SigSpec signal) const\n\t{\n\t\tstd::vector<RTLIL::SigBit> bits = sigmap(signal);\n\t\treturn get_drivers(result, bits);\n\t}\n\n\tbool get_consumers(pool<PortBit> &result, RTLIL::SigSpec signal) const\n\t{\n\t\tstd::vector<RTLIL::SigBit> bits = sigmap(signal);\n\t\treturn get_consumers(result, bits);\n\t}\n\n\tbool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const\n\t{\n\t\tstd::vector<RTLIL::SigBit> bits = sigmap(signal);\n\t\treturn get_inputs(result, bits);\n\t}\n\n\tbool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const\n\t{\n\t\tstd::vector<RTLIL::SigBit> bits = sigmap(signal);\n\t\treturn get_outputs(result, bits);\n\t}\n\n\t// has_* methods -- call by reference\n\n\ttemplate<typename T>\n\tinline bool has_drivers(const T &sig) const {\n\t\tpool<PortBit> result;\n\t\treturn get_drivers(result, sig);\n\t}\n\n\ttemplate<typename T>\n\tinline bool has_consumers(const T &sig) const {\n\t\tpool<PortBit> result;\n\t\treturn get_consumers(result, sig);\n\t}\n\n\ttemplate<typename T>\n\tinline bool has_inputs(const T &sig) const {\n\t\tpool<RTLIL::SigBit> result;\n\t\treturn get_inputs(result, sig);\n\t}\n\n\ttemplate<typename T>\n\tinline bool has_outputs(const T &sig) const {\n\t\tpool<RTLIL::SigBit> result;\n\t\treturn get_outputs(result, sig);\n\t}\n\n\t// has_* methods -- call by value\n\n\tinline bool has_drivers(RTLIL::SigSpec sig) const {\n\t\tpool<PortBit> result;\n\t\treturn get_drivers(result, sig);\n\t}\n\n\tinline bool has_consumers(RTLIL::SigSpec sig) const {\n\t\tpool<PortBit> result;\n\t\treturn get_consumers(result, sig);\n\t}\n\n\tinline bool has_inputs(RTLIL::SigSpec sig) const {\n\t\tpool<RTLIL::SigBit> result;\n\t\treturn get_inputs(result, sig);\n\t}\n\n\tinline bool has_outputs(RTLIL::SigSpec sig) const {\n\t\tpool<RTLIL::SigBit> result;\n\t\treturn get_outputs(result, sig);\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
183
183
|
"qcsat.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2021 Marcelina Kościelnicka <mwk@0x04.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef QCSAT_H\n#define QCSAT_H\n\n#include \"kernel/satgen.h\"\n#include \"kernel/modtools.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// This is a helper class meant for easy construction of quick SAT queries\n// to a combinatorial input cone of some set of signals, meant for SAT-based\n// optimizations. Various knobs are provided to set just how much of the\n// cone should be included in the model — since this class is meant for\n// optimization, it should not be a correctness problem when some cells are\n// skipped and the solver spuriously returns SAT with a solution that\n// cannot exist in reality due to skipped constraints (ie. only UNSAT results\n// from this class should be considered binding).\nstruct QuickConeSat {\n\tModWalker &modwalker;\n\tezSatPtr ez;\n\tSatGen satgen;\n\n\t// The effort level knobs.\n\n\t// The maximum \"complexity level\" of cells that will be imported.\n\t// - 1: bitwise operations, muxes, equality comparisons, lut, sop, fa\n\t// - 2: addition, subtraction, greater/less than comparisons, lcu\n\t// - 3: shifts\n\t// - 4: multiplication, division, power\n\tint max_cell_complexity = 2;\n\t// The maximum number of cells to import, or 0 for no limit.\n\tint max_cell_count = 0;\n\t// If non-0, skip importing cells with more than this number of output bits.\n\tint max_cell_outs = 0;\n\n\t// Internal state.\n\tpool<RTLIL::Cell*> imported_cells;\n\tpool<RTLIL::Wire*> imported_onehot;\n\tpool<RTLIL::SigBit> bits_queue;\n\n\tQuickConeSat(ModWalker &modwalker) : modwalker(modwalker), ez(), satgen(ez.get(), &modwalker.sigmap) {}\n\n\t// Imports a signal into the SAT solver, queues its input cone to be\n\t// imported in the next prepare() call.\n\tstd::vector<int> importSig(SigSpec sig);\n\tint importSigBit(SigBit bit);\n\n\t// Imports the input cones of all previously importSig'd signals into\n\t// the SAT solver.\n\tvoid prepare();\n\n\t// Returns the \"complexity level\" of a given cell.\n\tstatic int cell_complexity(RTLIL::Cell *cell);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
184
184
|
"register.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef REGISTER_H\n#define REGISTER_H\n\n#include \"kernel/yosys_common.h\"\n#include \"kernel/yosys.h\"\n\n#ifdef YOSYS_ENABLE_HELP_SOURCE\n\t#include <version>\n#\tif __cpp_lib_source_location == 201907L\n\t\t#include <source_location>\n\t\tusing std::source_location;\n\t\t#define HAS_SOURCE_LOCATION\n#\telif defined(__has_include)\n#\t\tif __has_include(<experimental/source_location>)\n\t\t\t#include <experimental/source_location>\n\t\t\tusing std::experimental::source_location;\n\t\t\t#define HAS_SOURCE_LOCATION\n#\t\tendif\n#\tendif\n#endif\n\n#ifndef HAS_SOURCE_LOCATION\nstruct source_location { // dummy placeholder\n\tint line() const { return 0; }\n\tint column() const { return 0; }\n\tconst char* file_name() const { return \"unknown\"; }\n\tconst char* function_name() const { return \"unknown\"; }\n\tstatic const source_location current(...) { return source_location(); }\n};\n#endif\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct Pass\n{\n\tstd::string pass_name, short_help;\n\tsource_location location;\n\tPass(std::string name, std::string short_help = \"** document me **\",\n\t\tsource_location location = source_location::current());\n\t// Prefer overriding 'Pass::on_shutdown()' if possible\n\tvirtual ~Pass();\n\n\t// Makes calls to log() to generate help message\n\tvirtual void help();\n\t// Uses PrettyHelp::get_current() to produce a more portable formatted help message\n\tvirtual bool formatted_help();\n\tvirtual void clear_flags();\n\tvirtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;\n\n\tint call_counter;\n\tint64_t runtime_ns;\n\tbool experimental_flag = false;\n\tbool internal_flag = false;\n\n\tvoid experimental() {\n\t\texperimental_flag = true;\n\t}\n\n\tvoid internal() {\n\t\tinternal_flag = true;\n\t}\n\n\tstruct pre_post_exec_state_t {\n\t\tPass *parent_pass;\n\t\tint64_t begin_ns;\n\t};\n\n\tpre_post_exec_state_t pre_execute();\n\tvoid post_execute(pre_post_exec_state_t state);\n\n\tvoid cmd_log_args(const std::vector<std::string> &args);\n\tvoid cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg);\n\tvoid extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design, bool select = true);\n\n\tstatic void call(RTLIL::Design *design, std::string command);\n\tstatic void call(RTLIL::Design *design, std::vector<std::string> args);\n\n\tstatic void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command);\n\tstatic void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args);\n\n\tstatic void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command);\n\tstatic void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args);\n\n\tPass *next_queued_pass;\n\tvirtual void run_register();\n\tstatic void init_register();\n\tstatic void done_register();\n\n\tvirtual void on_register();\n\tvirtual void on_shutdown();\n\tvirtual bool replace_existing_pass() const { return false; }\n};\n\nstruct ScriptPass : Pass\n{\n\tbool block_active, help_mode;\n\tRTLIL::Design *active_design;\n\tstd::string active_run_from, active_run_to;\n\n\tScriptPass(std::string name, std::string short_help = \"** document me **\", source_location location = source_location::current()) :\n\t\tPass(name, short_help, location) { }\n\n\tvirtual void script() = 0;\n\n\tbool check_label(std::string label, std::string info = std::string());\n\tvoid run(std::string command, std::string info = std::string());\n\tvoid run_nocheck(std::string command, std::string info = std::string());\n\tvoid run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string());\n\tvoid help_script();\n};\n\nstruct Frontend : Pass\n{\n\t// for reading of here documents\n\tstatic FILE *current_script_file;\n\tstatic std::string last_here_document;\n\n\tstd::string frontend_name;\n\tFrontend(std::string name, std::string short_help = \"** document me **\",\n\t\tsource_location location = source_location::current());\n\tvoid run_register() override;\n\t~Frontend() override;\n\tvoid execute(std::vector<std::string> args, RTLIL::Design *design) override final;\n\tvirtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;\n\n\tstatic std::vector<std::string> next_args;\n\tvoid extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx, bool bin_input = false);\n\n\tstatic void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command);\n\tstatic void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args);\n};\n\nstruct Backend : Pass\n{\n\tstd::string backend_name;\n\tBackend(std::string name, std::string short_help = \"** document me **\",\n\t\tsource_location location = source_location::current());\n\tvoid run_register() override;\n\t~Backend() override;\n\tvoid execute(std::vector<std::string> args, RTLIL::Design *design) override final;\n\tvirtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;\n\n\tvoid extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx, bool bin_output = false);\n\n\tstatic void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command);\n\tstatic void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args);\n};\n\n// implemented in passes/cmds/select.cc\nextern void handle_extra_select_args(Pass *pass, const std::vector<std::string> &args, size_t argidx, size_t args_size, RTLIL::Design *design);\nextern RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design);\nextern void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design);\n\nextern std::map<std::string, Pass*> pass_register;\nextern std::map<std::string, Frontend*> frontend_register;\nextern std::map<std::string, Backend*> backend_register;\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
185
|
-
"rtlil.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef RTLIL_H\n#define RTLIL_H\n\n#include \"kernel/yosys_common.h\"\n#include \"kernel/yosys.h\"\n\n#include <string_view>\n#include <unordered_map>\n\nYOSYS_NAMESPACE_BEGIN\n\nnamespace RTLIL\n{\n\tenum State : unsigned char {\n\t\tS0 = 0,\n\t\tS1 = 1,\n\t\tSx = 2, // undefined value or conflict\n\t\tSz = 3, // high-impedance / not-connected\n\t\tSa = 4, // don't care (used only in cases)\n\t\tSm = 5 // marker (used internally by some passes)\n\t};\n\n\tenum SyncType : unsigned char {\n\t\tST0 = 0, // level sensitive: 0\n\t\tST1 = 1, // level sensitive: 1\n\t\tSTp = 2, // edge sensitive: posedge\n\t\tSTn = 3, // edge sensitive: negedge\n\t\tSTe = 4, // edge sensitive: both edges\n\t\tSTa = 5, // always active\n\t\tSTg = 6, // global clock\n\t\tSTi = 7 // init\n\t};\n\n\t// Semantic metadata - how can this constant be interpreted?\n\t// Values may be generally non-exclusive\n\tenum ConstFlags : unsigned char {\n\t\tCONST_FLAG_NONE = 0,\n\t\tCONST_FLAG_STRING = 1,\n\t\tCONST_FLAG_SIGNED = 2, // only used for parameters\n\t\tCONST_FLAG_REAL = 4 // only used for parameters\n\t};\n\n\tenum SelectPartials : unsigned char {\n\t\tSELECT_ALL = 0, // include partial modules\n\t\tSELECT_WHOLE_ONLY = 1, // ignore partial modules\n\t\tSELECT_WHOLE_WARN = 2, // call log_warning on partial module\n\t\tSELECT_WHOLE_ERR = 3, // call log_error on partial module\n\t\tSELECT_WHOLE_CMDERR = 4 // call log_cmd_error on partial module\n\t};\n\n\tenum SelectBoxes : unsigned char {\n\t\tSB_ALL = 0, // include boxed modules\n\t\tSB_WARN = 1, // helper for log_warning (not for direct use)\n\t\tSB_ERR = 2, // helper for log_error (not for direct use)\n\t\tSB_CMDERR = 3, // helper for log_cmd_error (not for direct use)\n\t\tSB_UNBOXED_ONLY = 4, // ignore boxed modules\n\t\tSB_UNBOXED_WARN = 5, // call log_warning on boxed module\n\t\tSB_UNBOXED_ERR = 6, // call log_error on boxed module\n\t\tSB_UNBOXED_CMDERR = 7, // call log_cmd_error on boxed module\n\t\tSB_INCL_WB = 8, // helper for white boxes (not for direct use)\n\t\tSB_EXCL_BB_ONLY = 12, // ignore black boxes, but not white boxes\n\t\tSB_EXCL_BB_WARN = 13, // call log_warning on black boxed module\n\t\tSB_EXCL_BB_ERR = 14, // call log_error on black boxed module\n\t\tSB_EXCL_BB_CMDERR = 15 // call log_cmd_error on black boxed module\n\t};\n\n\tstruct Const;\n\tstruct AttrObject;\n\tstruct NamedObject;\n\tstruct Selection;\n\tstruct Monitor;\n\tstruct Design;\n\tstruct Module;\n\tstruct Wire;\n\tstruct Memory;\n\tstruct Cell;\n\tstruct SigChunk;\n\tstruct SigBit;\n\tstruct SigSpecIterator;\n\tstruct SigSpecConstIterator;\n\tstruct SigSpec;\n\tstruct CaseRule;\n\tstruct SwitchRule;\n\tstruct MemWriteAction;\n\tstruct SyncRule;\n\tstruct Process;\n\tstruct Binding;\n\tstruct IdString;\n\n\ttypedef std::pair<SigSpec, SigSpec> SigSig;\n};\n\nstruct RTLIL::IdString\n{\n\t#undef YOSYS_XTRACE_GET_PUT\n\t#undef YOSYS_SORT_ID_FREE_LIST\n\t#undef YOSYS_USE_STICKY_IDS\n\t#undef YOSYS_NO_IDS_REFCNT\n\n\t// the global id string cache\n\n\tstatic bool destruct_guard_ok; // POD, will be initialized to zero\n\tstatic struct destruct_guard_t {\n\t\tdestruct_guard_t() { destruct_guard_ok = true; }\n\t\t~destruct_guard_t() { destruct_guard_ok = false; }\n\t} destruct_guard;\n\n\tstatic std::vector<char*> global_id_storage_;\n\tstatic std::unordered_map<std::string_view, int> global_id_index_;\n#ifndef YOSYS_NO_IDS_REFCNT\n\tstatic std::vector<int> global_refcount_storage_;\n\tstatic std::vector<int> global_free_idx_list_;\n#endif\n\n#ifdef YOSYS_USE_STICKY_IDS\n\tstatic int last_created_idx_ptr_;\n\tstatic int last_created_idx_[8];\n#endif\n\n\tstatic inline void xtrace_db_dump()\n\t{\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tfor (int idx = 0; idx < GetSize(global_id_storage_); idx++)\n\t\t{\n\t\t\tif (global_id_storage_.at(idx) == nullptr)\n\t\t\t\tlog(\"#X# DB-DUMP index %d: FREE\\n\", idx);\n\t\t\telse\n\t\t\t\tlog(\"#X# DB-DUMP index %d: '%s' (ref %d)\\n\", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));\n\t\t}\n\t#endif\n\t}\n\n\tstatic inline void checkpoint()\n\t{\n\t#ifdef YOSYS_USE_STICKY_IDS\n\t\tlast_created_idx_ptr_ = 0;\n\t\tfor (int i = 0; i < 8; i++) {\n\t\t\tif (last_created_idx_[i])\n\t\t\t\tput_reference(last_created_idx_[i]);\n\t\t\tlast_created_idx_[i] = 0;\n\t\t}\n\t#endif\n\t#ifdef YOSYS_SORT_ID_FREE_LIST\n\t\tstd::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());\n\t#endif\n\t}\n\n\tstatic inline int get_reference(int idx)\n\t{\n\t\tif (idx) {\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\t\tglobal_refcount_storage_[idx]++;\n\t#endif\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\t\tif (yosys_xtrace)\n\t\t\t\tlog(\"#X# GET-BY-INDEX '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t#endif\n\t\t}\n\t\treturn idx;\n\t}\n\n\tstatic int get_reference(const char *p)\n\t{\n\t\tlog_assert(destruct_guard_ok);\n\n\t\tif (!p[0])\n\t\t\treturn 0;\n\n\t\tauto it = global_id_index_.find((char*)p);\n\t\tif (it != global_id_index_.end()) {\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\t\tglobal_refcount_storage_.at(it->second)++;\n\t#endif\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\t\tif (yosys_xtrace)\n\t\t\t\tlog(\"#X# GET-BY-NAME '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));\n\t#endif\n\t\t\treturn it->second;\n\t\t}\n\n\t\tlog_assert(p[0] == '$' || p[0] == '\\\\');\n\t\tlog_assert(p[1] != 0);\n\t\tfor (const char *c = p; *c; c++)\n\t\t\tif ((unsigned)*c <= (unsigned)' ')\n\t\t\t\tlog_error(\"Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\\n\", *c, p);\n\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\tif (global_free_idx_list_.empty()) {\n\t\t\tif (global_id_storage_.empty()) {\n\t\t\t\tglobal_refcount_storage_.push_back(0);\n\t\t\t\tglobal_id_storage_.push_back((char*)\"\");\n\t\t\t\tglobal_id_index_[global_id_storage_.back()] = 0;\n\t\t\t}\n\t\t\tlog_assert(global_id_storage_.size() < 0x40000000);\n\t\t\tglobal_free_idx_list_.push_back(global_id_storage_.size());\n\t\t\tglobal_id_storage_.push_back(nullptr);\n\t\t\tglobal_refcount_storage_.push_back(0);\n\t\t}\n\n\t\tint idx = global_free_idx_list_.back();\n\t\tglobal_free_idx_list_.pop_back();\n\t\tglobal_id_storage_.at(idx) = strdup(p);\n\t\tglobal_id_index_[global_id_storage_.at(idx)] = idx;\n\t\tglobal_refcount_storage_.at(idx)++;\n\t#else\n\t\tif (global_id_storage_.empty()) {\n\t\t\tglobal_id_storage_.push_back((char*)\"\");\n\t\t\tglobal_id_index_[global_id_storage_.back()] = 0;\n\t\t}\n\t\tint idx = global_id_storage_.size();\n\t\tglobal_id_storage_.push_back(strdup(p));\n\t\tglobal_id_index_[global_id_storage_.back()] = idx;\n\t#endif\n\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# New IdString '%s' with index %d.\\n\", p, idx);\n\t\t\tlog_backtrace(\"-X- \", yosys_xtrace-1);\n\t\t}\n\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tif (yosys_xtrace)\n\t\t\tlog(\"#X# GET-BY-NAME '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t#endif\n\n\t#ifdef YOSYS_USE_STICKY_IDS\n\t\t// Avoid Create->Delete->Create pattern\n\t\tif (last_created_idx_[last_created_idx_ptr_])\n\t\t\tput_reference(last_created_idx_[last_created_idx_ptr_]);\n\t\tlast_created_idx_[last_created_idx_ptr_] = idx;\n\t\tget_reference(last_created_idx_[last_created_idx_ptr_]);\n\t\tlast_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;\n\t#endif\n\n\t\treturn idx;\n\t}\n\n#ifndef YOSYS_NO_IDS_REFCNT\n\tstatic inline void put_reference(int idx)\n\t{\n\t\t// put_reference() may be called from destructors after the destructor of\n\t\t// global_refcount_storage_ has been run. in this case we simply do nothing.\n\t\tif (!destruct_guard_ok || !idx)\n\t\t\treturn;\n\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# PUT '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t\t}\n\t#endif\n\n\t\tint &refcount = global_refcount_storage_[idx];\n\n\t\tif (--refcount > 0)\n\t\t\treturn;\n\n\t\tlog_assert(refcount == 0);\n\t\tfree_reference(idx);\n\t}\n\tstatic inline void free_reference(int idx)\n\t{\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# Removed IdString '%s' with index %d.\\n\", global_id_storage_.at(idx), idx);\n\t\t\tlog_backtrace(\"-X- \", yosys_xtrace-1);\n\t\t}\n\n\t\tglobal_id_index_.erase(global_id_storage_.at(idx));\n\t\tfree(global_id_storage_.at(idx));\n\t\tglobal_id_storage_.at(idx) = nullptr;\n\t\tglobal_free_idx_list_.push_back(idx);\n\t}\n#else\n\tstatic inline void put_reference(int) { }\n#endif\n\n\t// the actual IdString object is just is a single int\n\n\tint index_;\n\n\tinline IdString() : index_(0) { }\n\tinline IdString(const char *str) : index_(get_reference(str)) { }\n\tinline IdString(const IdString &str) : index_(get_reference(str.index_)) { }\n\tinline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }\n\tinline IdString(const std::string &str) : index_(get_reference(str.c_str())) { }\n\tinline ~IdString() { put_reference(index_); }\n\n\tinline void operator=(const IdString &rhs) {\n\t\tput_reference(index_);\n\t\tindex_ = get_reference(rhs.index_);\n\t}\n\n\tinline void operator=(const char *rhs) {\n\t\tIdString id(rhs);\n\t\t*this = id;\n\t}\n\n\tinline void operator=(const std::string &rhs) {\n\t\tIdString id(rhs);\n\t\t*this = id;\n\t}\n\n\tinline const char *c_str() const {\n\t\treturn global_id_storage_.at(index_);\n\t}\n\n\tinline std::string str() const {\n\t\treturn std::string(global_id_storage_.at(index_));\n\t}\n\n\tinline bool operator<(const IdString &rhs) const {\n\t\treturn index_ < rhs.index_;\n\t}\n\n\tinline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }\n\tinline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }\n\n\t// The methods below are just convenience functions for better compatibility with std::string.\n\n\tbool operator==(const std::string &rhs) const { return c_str() == rhs; }\n\tbool operator!=(const std::string &rhs) const { return c_str() != rhs; }\n\n\tbool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }\n\tbool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }\n\n\tchar operator[](size_t i) const {\n\t\t\t\t\tconst char *p = c_str();\n#ifndef NDEBUG\n\t\tfor (; i != 0; i--, p++)\n\t\t\tlog_assert(*p != 0);\n\t\treturn *p;\n#else\n\t\treturn *(p + i);\n#endif\n\t}\n\n\tstd::string substr(size_t pos = 0, size_t len = std::string::npos) const {\n\t\tif (len == std::string::npos || len >= strlen(c_str() + pos))\n\t\t\treturn std::string(c_str() + pos);\n\t\telse\n\t\t\treturn std::string(c_str() + pos, len);\n\t}\n\n\tint compare(size_t pos, size_t len, const char* s) const {\n\t\treturn strncmp(c_str()+pos, s, len);\n\t}\n\n\tbool begins_with(const char* prefix) const {\n\t\tsize_t len = strlen(prefix);\n\t\tif (size() < len) return false;\n\t\treturn compare(0, len, prefix) == 0;\n\t}\n\n\tbool ends_with(const char* suffix) const {\n\t\tsize_t len = strlen(suffix);\n\t\tif (size() < len) return false;\n\t\treturn compare(size()-len, len, suffix) == 0;\n\t}\n\n\tbool contains(const char* str) const {\n\t\treturn strstr(c_str(), str);\n\t}\n\n\tsize_t size() const {\n\t\treturn strlen(c_str());\n\t}\n\n\tbool empty() const {\n\t\treturn c_str()[0] == 0;\n\t}\n\n\tvoid clear() {\n\t\t*this = IdString();\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { return hash_ops<int>::hash_into(index_, h); }\n\n\t[[nodiscard]] Hasher hash_top() const {\n\t\tHasher h;\n\t\th.force((Hasher::hash_t) index_);\n\t\treturn h;\n\t}\n\n\t// The following is a helper key_compare class. Instead of for example std::set<Cell*>\n\t// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the\n\t// set has an influence on the algorithm.\n\n\ttemplate<typename T> struct compare_ptr_by_name {\n\t\tbool operator()(const T *a, const T *b) const {\n\t\t\treturn (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);\n\t\t}\n\t};\n\n\t// often one needs to check if a given IdString is part of a list (for example a list\n\t// of cell types). the following functions helps with that.\n\ttemplate<typename... Args>\n\tbool in(Args... args) const {\n\t\treturn (... || in(args));\n\t}\n\n\tbool in(const IdString &rhs) const { return *this == rhs; }\n\tbool in(const char *rhs) const { return *this == rhs; }\n\tbool in(const std::string &rhs) const { return *this == rhs; }\n\tinline bool in(const pool<IdString> &rhs) const;\n\tinline bool in(const pool<IdString> &&rhs) const;\n\n\tbool isPublic() const { return begins_with(\"\\\\\"); }\n};\n\nnamespace hashlib {\n\ttemplate <>\n\tstruct hash_ops<RTLIL::IdString> {\n\t\tstatic inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) {\n\t\t\treturn a == b;\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash(const RTLIL::IdString id) {\n\t\t\treturn id.hash_top();\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString id, Hasher h) {\n\t\t\treturn id.hash_into(h);\n\t\t}\n\t};\n};\n\n/**\n * How to not use these methods:\n * 1. if(celltype.in({...})) -> if(celltype.in(...))\n * 2. pool<IdString> p; ... a.in(p) -> (bool)p.count(a)\n */\n[[deprecated]]\ninline bool RTLIL::IdString::in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }\n[[deprecated]]\ninline bool RTLIL::IdString::in(const pool<IdString> &&rhs) const { return rhs.count(*this) != 0; }\n\nnamespace RTLIL {\n\tnamespace ID {\n#define X(_id) extern IdString _id;\n#include \"kernel/constids.inc\"\n#undef X\n\t};\n\textern dict<std::string, std::string> constpad;\n\n\tconst pool<IdString> &builtin_ff_cell_types();\n\n\tstatic inline std::string escape_id(const std::string &str) {\n\t\tif (str.size() > 0 && str[0] != '\\\\' && str[0] != '$')\n\t\t\treturn \"\\\\\" + str;\n\t\treturn str;\n\t}\n\n\tstatic inline std::string unescape_id(const std::string &str) {\n\t\tif (str.size() < 2)\n\t\t\treturn str;\n\t\tif (str[0] != '\\\\')\n\t\t\treturn str;\n\t\tif (str[1] == '$' || str[1] == '\\\\')\n\t\t\treturn str;\n\t\tif (str[1] >= '0' && str[1] <= '9')\n\t\t\treturn str;\n\t\treturn str.substr(1);\n\t}\n\n\tstatic inline std::string unescape_id(const RTLIL::IdString &str) {\n\t\treturn unescape_id(str.str());\n\t}\n\n\tstatic inline const char *id2cstr(const RTLIL::IdString &str) {\n\t\treturn log_id(str);\n\t}\n\n\ttemplate <typename T> struct sort_by_name_id {\n\t\tbool operator()(T *a, T *b) const {\n\t\t\treturn a->name < b->name;\n\t\t}\n\t};\n\n\ttemplate <typename T> struct sort_by_name_str {\n\t\tbool operator()(T *a, T *b) const {\n\t\t\treturn strcmp(a->name.c_str(), b->name.c_str()) < 0;\n\t\t}\n\t};\n\n\tstruct sort_by_id_str {\n\t\tbool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {\n\t\t\treturn strcmp(a.c_str(), b.c_str()) < 0;\n\t\t}\n\t};\n\n\tstatic inline std::string encode_filename(const std::string &filename)\n\t{\n\t\tstd::stringstream val;\n\t\tif (!std::any_of(filename.begin(), filename.end(), [](char c) {\n\t\t\treturn static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126;\n\t\t})) return filename;\n\t\tfor (unsigned char const c : filename) {\n\t\t\tif (c < 33 || c > 126)\n\t\t\t\tval << stringf(\"$%02x\", c);\n\t\t\telse\n\t\t\t\tval << c;\n\t\t}\n\t\treturn val.str();\n\t}\n\n\t// see calc.cc for the implementation of this functions\n\tRTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shift (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shiftx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_eqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_nex (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_buf (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\tRTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\tRTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\tRTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\n\tRTLIL::Const const_bweqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\tRTLIL::Const const_bwmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\n\n\t// This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().\n\t// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.\n\n\ttemplate<typename T>\n\tstruct ObjIterator {\n\t\tusing iterator_category = std::forward_iterator_tag;\n\t\tusing value_type = T;\n\t\tusing difference_type = ptrdiff_t;\n\t\tusing pointer = T*;\n\t\tusing reference = T&;\n\t\ttypename dict<RTLIL::IdString, T>::iterator it;\n\t\tdict<RTLIL::IdString, T> *list_p;\n\t\tint *refcount_p;\n\n\t\tObjIterator() : list_p(nullptr), refcount_p(nullptr) {\n\t\t}\n\n\t\tObjIterator(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) {\n\t\t\tif (list_p->empty()) {\n\t\t\t\tthis->list_p = nullptr;\n\t\t\t\tthis->refcount_p = nullptr;\n\t\t\t} else {\n\t\t\t\tit = list_p->begin();\n\t\t\t\t(*refcount_p)++;\n\t\t\t}\n\t\t}\n\n\t\tObjIterator(const RTLIL::ObjIterator<T> &other) {\n\t\t\tit = other.it;\n\t\t\tlist_p = other.list_p;\n\t\t\trefcount_p = other.refcount_p;\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)++;\n\t\t}\n\n\t\tObjIterator &operator=(const RTLIL::ObjIterator<T> &other) {\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)--;\n\t\t\tit = other.it;\n\t\t\tlist_p = other.list_p;\n\t\t\trefcount_p = other.refcount_p;\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)++;\n\t\t\treturn *this;\n\t\t}\n\n\t\t~ObjIterator() {\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)--;\n\t\t}\n\n\t\tinline T operator*() const {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\treturn it->second;\n\t\t}\n\n\t\tinline bool operator!=(const RTLIL::ObjIterator<T> &other) const {\n\t\t\tif (list_p == nullptr || other.list_p == nullptr)\n\t\t\t\treturn list_p != other.list_p;\n\t\t\treturn it != other.it;\n\t\t}\n\n\n\t\tinline bool operator==(const RTLIL::ObjIterator<T> &other) const {\n\t\t\treturn !(*this != other);\n\t\t}\n\n\t\tinline ObjIterator<T>& operator++() {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tif (++it == list_p->end()) {\n\t\t\t\t(*refcount_p)--;\n\t\t\t\tlist_p = nullptr;\n\t\t\t\trefcount_p = nullptr;\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\t\tinline ObjIterator<T>& operator+=(int amt) {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tit += amt;\n\t\t\tif (it == list_p->end()) {\n\t\t\t\t(*refcount_p)--;\n\t\t\t\tlist_p = nullptr;\n\t\t\t\trefcount_p = nullptr;\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\t\tinline ObjIterator<T> operator+(int amt) {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tObjIterator<T> new_obj(*this);\n\t\t\tnew_obj.it += amt;\n\t\t\tif (new_obj.it == list_p->end()) {\n\t\t\t\t(*(new_obj.refcount_p))--;\n\t\t\t\tnew_obj.list_p = nullptr;\n\t\t\t\tnew_obj.refcount_p = nullptr;\n\t\t\t}\n\t\t\treturn new_obj;\n\t\t}\n\n\t\tinline const ObjIterator<T> operator++(int) {\n\t\t\tObjIterator<T> result(*this);\n\t\t\t++(*this);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<typename T>\n\tstruct ObjRange\n\t{\n\t\tdict<RTLIL::IdString, T> *list_p;\n\t\tint *refcount_p;\n\n\t\tObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }\n\t\tRTLIL::ObjIterator<T> begin() { return RTLIL::ObjIterator<T>(list_p, refcount_p); }\n\t\tRTLIL::ObjIterator<T> end() { return RTLIL::ObjIterator<T>(); }\n\n\t\tsize_t size() const {\n\t\t\treturn list_p->size();\n\t\t}\n\n\t\toperator pool<T>() const {\n\t\t\tpool<T> result;\n\t\t\tfor (auto &it : *list_p)\n\t\t\t\tresult.insert(it.second);\n\t\t\treturn result;\n\t\t}\n\n\t\toperator std::vector<T>() const {\n\t\t\tstd::vector<T> result;\n\t\t\tresult.reserve(list_p->size());\n\t\t\tfor (auto &it : *list_p)\n\t\t\t\tresult.push_back(it.second);\n\t\t\treturn result;\n\t\t}\n\n\t\tpool<T> to_pool() const { return *this; }\n\t\tstd::vector<T> to_vector() const { return *this; }\n\t};\n};\n\nstruct RTLIL::Const\n{\n\tshort int flags;\nprivate:\n\tfriend class KernelRtlilTest;\n\tFRIEND_TEST(KernelRtlilTest, ConstStr);\n\tusing bitvectype = std::vector<RTLIL::State>;\n\tenum class backing_tag: bool { bits, string };\n\t// Do not access the union or tag even in Const methods unless necessary\n\tmutable backing_tag tag;\n\tunion {\n\t\tmutable bitvectype bits_;\n\t\tmutable std::string str_;\n\t};\n\n\t// Use these private utilities instead\n\tbool is_bits() const { return tag == backing_tag::bits; }\n\tbool is_str() const { return tag == backing_tag::string; }\n\n\tbitvectype* get_if_bits() const { return is_bits() ? &bits_ : NULL; }\n\tstd::string* get_if_str() const { return is_str() ? &str_ : NULL; }\n\n\tbitvectype& get_bits() const;\n\tstd::string& get_str() const;\npublic:\n\tConst() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector<RTLIL::State>()) {}\n\tConst(const std::string &str);\n\tConst(long long val, int width = 32);\n\tConst(RTLIL::State bit, int width = 1);\n\tConst(const std::vector<RTLIL::State> &bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(bits) {}\n\tConst(const std::vector<bool> &bits);\n\tConst(const RTLIL::Const &other);\n\tConst(RTLIL::Const &&other);\n\tRTLIL::Const &operator =(const RTLIL::Const &other);\n\t~Const();\n\n\tbool operator <(const RTLIL::Const &other) const;\n\tbool operator ==(const RTLIL::Const &other) const;\n\tbool operator !=(const RTLIL::Const &other) const;\n\n\tstd::vector<RTLIL::State>& bits();\n\tbool as_bool() const;\n\n\t// Convert the constant value to a C++ int.\n\t// NOTE: If the constant is too wide to fit in int (32 bits) this will\n\t// truncate any higher bits, potentially over/underflowing. Consider using\n\t// try_as_int, as_int_saturating, or guarding behind convertible_to_int\n\t// instead.\n\tint as_int(bool is_signed = false) const;\n\n\t// Returns true iff the constant can be converted to an int without\n\t// over/underflow.\n\tbool convertible_to_int(bool is_signed = false) const;\n\n\t// Returns the constant's value as an int if it can be represented without\n\t// over/underflow, or std::nullopt otherwise.\n\tstd::optional<int> try_as_int(bool is_signed = false) const;\n\n\t// Returns the constant's value as an int if it can be represented without\n\t// over/underflow, otherwise the max/min value for int depending on the sign.\n\tint as_int_saturating(bool is_signed = false) const;\n\n\tstd::string as_string(const char* any = \"-\") const;\n\tstatic Const from_string(const std::string &str);\n\tstd::vector<RTLIL::State> to_bits() const;\n\n\tstd::string decode_string() const;\n\tint size() const;\n\tbool empty() const;\n\tvoid bitvectorize() const;\n\n\tvoid append(const RTLIL::Const &other);\n\n\tclass const_iterator {\n\tprivate:\n\t\tconst Const& parent;\n\t\tsize_t idx;\n\n\tpublic:\n\t\tusing iterator_category = std::input_iterator_tag;\n\t\tusing value_type = State;\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing pointer = const State*;\n\t\tusing reference = const State&;\n\n\t\tconst_iterator(const Const& c, size_t i) : parent(c), idx(i) {}\n\n\t\tState operator*() const;\n\n\t\tconst_iterator& operator++() { ++idx; return *this; }\n\t\tconst_iterator& operator--() { --idx; return *this; }\n\t\tconst_iterator& operator++(int) { ++idx; return *this; }\n\t\tconst_iterator& operator--(int) { --idx; return *this; }\n\t\tconst_iterator& operator+=(int i) { idx += i; return *this; }\n\n\t\tconst_iterator operator+(int add) {\n\t\t\treturn const_iterator(parent, idx + add);\n\t\t}\n\t\tconst_iterator operator-(int sub) {\n\t\t\treturn const_iterator(parent, idx - sub);\n\t\t}\n\t\tint operator-(const const_iterator& other) {\n\t\t\treturn idx - other.idx;\n\t\t}\n\n\t\tbool operator==(const const_iterator& other) const {\n\t\t\treturn idx == other.idx;\n\t\t}\n\n\t\tbool operator!=(const const_iterator& other) const {\n\t\t\treturn !(*this == other);\n\t\t}\n\t};\n\n\tconst_iterator begin() const {\n\t\treturn const_iterator(*this, 0);\n\t}\n\tconst_iterator end() const {\n\t\treturn const_iterator(*this, size());\n\t}\n\tState back() const {\n\t\treturn *(end() - 1);\n\t}\n\tState front() const {\n\t\treturn *begin();\n\t}\n\tState at(size_t i) const {\n\t\treturn *const_iterator(*this, i);\n\t}\n\tState operator[](size_t i) const {\n\t\treturn *const_iterator(*this, i);\n\t}\n\n\tbool is_fully_zero() const;\n\tbool is_fully_ones() const;\n\tbool is_fully_def() const;\n\tbool is_fully_undef() const;\n\tbool is_fully_undef_x_only() const;\n\tbool is_onehot(int *pos = nullptr) const;\n\n\tRTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const;\n\n\t// find the MSB without redundant leading bits\n\tint get_min_size(bool is_signed) const;\n\n\t// compress representation to the minimum required bits\n\tvoid compress(bool is_signed = false);\n\n\tstd::optional<int> as_int_compress(bool is_signed) const;\n\n\tvoid extu(int width) {\n\t\tbits().resize(width, RTLIL::State::S0);\n\t}\n\n\tvoid exts(int width) {\n\t\tbitvectype& bv = bits();\n\t\tbv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\th.eat(size());\n\t\tfor (auto b : *this)\n\t\t\th.eat(b);\n\t\treturn h;\n\t}\n};\n\nstruct RTLIL::AttrObject\n{\n\tdict<RTLIL::IdString, RTLIL::Const> attributes;\n\n\tbool has_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_bool_attribute(const RTLIL::IdString &id, bool value=true);\n\tbool get_bool_attribute(const RTLIL::IdString &id) const;\n\n\t[[deprecated(\"Use Module::get_blackbox_attribute() instead.\")]]\n\tbool get_blackbox_attribute(bool ignore_wb=false) const {\n\t\treturn get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));\n\t}\n\n\tvoid set_string_attribute(const RTLIL::IdString& id, string value);\n\tstring get_string_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);\n\tvoid add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);\n\tpool<string> get_strpool_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_src_attribute(const std::string &src) {\n\t\tset_string_attribute(ID::src, src);\n\t}\n\tstd::string get_src_attribute() const {\n\t\treturn get_string_attribute(ID::src);\n\t}\n\n\tvoid set_hdlname_attribute(const vector<string> &hierarchy);\n\tvector<string> get_hdlname_attribute() const;\n\n\tvoid set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data);\n\tvector<int> get_intvec_attribute(const RTLIL::IdString &id) const;\n};\n\nstruct RTLIL::NamedObject : public RTLIL::AttrObject\n{\n\tRTLIL::IdString name;\n};\n\nstruct RTLIL::SigChunk\n{\n\tRTLIL::Wire *wire;\n\tstd::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0\n\tint width, offset;\n\n\tSigChunk() : wire(nullptr), width(0), offset(0) {}\n\tSigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.to_bits()), width(GetSize(data)), offset(0) {}\n\tSigChunk(RTLIL::Const &&value) : wire(nullptr), data(value.to_bits()), width(GetSize(data)), offset(0) {}\n\tSigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {}\n\tSigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {}\n\tSigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {}\n\tSigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {}\n\tSigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {}\n\tSigChunk(const RTLIL::SigBit &bit);\n\n\tRTLIL::SigChunk extract(int offset, int length) const;\n\tRTLIL::SigBit operator[](int offset) const;\n\tinline int size() const { return width; }\n\tinline bool is_wire() const { return wire != NULL; }\n\n\tbool operator <(const RTLIL::SigChunk &other) const;\n\tbool operator ==(const RTLIL::SigChunk &other) const;\n\tbool operator !=(const RTLIL::SigChunk &other) const;\n};\n\nstruct RTLIL::SigBit\n{\n\tRTLIL::Wire *wire;\n\tunion {\n\t\tRTLIL::State data; // used if wire == NULL\n\t\tint offset; // used if wire != NULL\n\t};\n\n\tSigBit();\n\tSigBit(RTLIL::State bit);\n\texplicit SigBit(bool bit);\n\tSigBit(RTLIL::Wire *wire);\n\tSigBit(RTLIL::Wire *wire, int offset);\n\tSigBit(const RTLIL::SigChunk &chunk);\n\tSigBit(const RTLIL::SigChunk &chunk, int index);\n\tSigBit(const RTLIL::SigSpec &sig);\n\tSigBit(const RTLIL::SigBit &sigbit) = default;\n\tRTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;\n\n\tinline bool is_wire() const { return wire != NULL; }\n\n\tbool operator <(const RTLIL::SigBit &other) const;\n\tbool operator ==(const RTLIL::SigBit &other) const;\n\tbool operator !=(const RTLIL::SigBit &other) const;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\t[[nodiscard]] Hasher hash_top() const;\n};\n\nnamespace hashlib {\n\ttemplate <>\n\tstruct hash_ops<RTLIL::SigBit> {\n\t\tstatic inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) {\n\t\t\treturn a == b;\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash(const RTLIL::SigBit sb) {\n\t\t\treturn sb.hash_top();\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash_into(const RTLIL::SigBit sb, Hasher h) {\n\t\t\treturn sb.hash_into(h);\n\t\t}\n\t};\n};\n\nstruct RTLIL::SigSpecIterator\n{\n\ttypedef std::input_iterator_tag iterator_category;\n\ttypedef RTLIL::SigBit value_type;\n\ttypedef ptrdiff_t difference_type;\n\ttypedef RTLIL::SigBit* pointer;\n\ttypedef RTLIL::SigBit& reference;\n\n\tRTLIL::SigSpec *sig_p;\n\tint index;\n\n\tinline RTLIL::SigBit &operator*() const;\n\tinline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }\n\tinline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }\n\tinline void operator++() { index++; }\n};\n\nstruct RTLIL::SigSpecConstIterator\n{\n\ttypedef std::input_iterator_tag iterator_category;\n\ttypedef RTLIL::SigBit value_type;\n\ttypedef ptrdiff_t difference_type;\n\ttypedef RTLIL::SigBit* pointer;\n\ttypedef RTLIL::SigBit& reference;\n\n\tconst RTLIL::SigSpec *sig_p;\n\tint index;\n\n\tinline const RTLIL::SigBit &operator*() const;\n\tinline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }\n\tinline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }\n\tinline void operator++() { index++; }\n};\n\nstruct RTLIL::SigSpec\n{\nprivate:\n\tint width_;\n\tHasher::hash_t hash_;\n\tstd::vector<RTLIL::SigChunk> chunks_; // LSB at index 0\n\tstd::vector<RTLIL::SigBit> bits_; // LSB at index 0\n\n\tvoid pack() const;\n\tvoid unpack() const;\n\tvoid updhash() const;\n\n\tinline bool packed() const {\n\t\treturn bits_.empty();\n\t}\n\n\tinline void inline_unpack() const {\n\t\tif (!chunks_.empty())\n\t\t\tunpack();\n\t}\n\n\t// Only used by Module::remove(const pool<Wire*> &wires)\n\t// but cannot be more specific as it isn't yet declared\n\tfriend struct RTLIL::Module;\n\npublic:\n\tSigSpec() : width_(0), hash_(0) {}\n\tSigSpec(std::initializer_list<RTLIL::SigSpec> parts);\n\n\tSigSpec(const RTLIL::Const &value);\n\tSigSpec(RTLIL::Const &&value);\n\tSigSpec(const RTLIL::SigChunk &chunk);\n\tSigSpec(RTLIL::SigChunk &&chunk);\n\tSigSpec(RTLIL::Wire *wire);\n\tSigSpec(RTLIL::Wire *wire, int offset, int width = 1);\n\tSigSpec(const std::string &str);\n\tSigSpec(int val, int width = 32);\n\tSigSpec(RTLIL::State bit, int width = 1);\n\tSigSpec(const RTLIL::SigBit &bit, int width = 1);\n\tSigSpec(const std::vector<RTLIL::SigChunk> &chunks);\n\tSigSpec(const std::vector<RTLIL::SigBit> &bits);\n\tSigSpec(const pool<RTLIL::SigBit> &bits);\n\tSigSpec(const std::set<RTLIL::SigBit> &bits);\n\texplicit SigSpec(bool bit);\n\n\tinline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }\n\tinline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }\n\n\tinline int size() const { return width_; }\n\tinline bool empty() const { return width_ == 0; }\n\n\tinline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }\n\tinline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }\n\n\tinline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }\n\tinline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }\n\n\tinline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }\n\tinline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }\n\n\tvoid sort();\n\tvoid sort_and_unify();\n\n\tvoid replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);\n\tvoid replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;\n\n\tvoid replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules);\n\tvoid replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;\n\n\tvoid replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);\n\tvoid replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;\n\n\tvoid replace(int offset, const RTLIL::SigSpec &with);\n\n\tvoid remove(const RTLIL::SigSpec &pattern);\n\tvoid remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;\n\tvoid remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);\n\n\tvoid remove(const pool<RTLIL::SigBit> &pattern);\n\tvoid remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;\n\tvoid remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);\n\tvoid remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);\n\tvoid remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *other);\n\n\tvoid remove(int offset, int length = 1);\n\tvoid remove_const();\n\n\tRTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;\n\tRTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;\n\tRTLIL::SigSpec extract(int offset, int length = 1) const;\n\tRTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }\n\n\tRTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; };\n\tRTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; };\n\n\tvoid append(const RTLIL::SigSpec &signal);\n\tinline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); }\n\tinline void append(const RTLIL::SigChunk &chunk) { append(RTLIL::SigSpec(chunk)); }\n\tinline void append(const RTLIL::Const &const_) { append(RTLIL::SigSpec(const_)); }\n\n\tvoid append(const RTLIL::SigBit &bit);\n\tinline void append(RTLIL::State state) { append(RTLIL::SigBit(state)); }\n\tinline void append(bool bool_) { append(RTLIL::SigBit(bool_)); }\n\n\tvoid extend_u0(int width, bool is_signed = false);\n\n\tRTLIL::SigSpec repeat(int num) const;\n\n\tvoid reverse() { inline_unpack(); std::reverse(bits_.begin(), bits_.end()); }\n\n\tbool operator <(const RTLIL::SigSpec &other) const;\n\tbool operator ==(const RTLIL::SigSpec &other) const;\n\tinline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }\n\n\tbool is_wire() const;\n\tbool is_chunk() const;\n\tinline bool is_bit() const { return width_ == 1; }\n\n\tbool is_fully_const() const;\n\tbool is_fully_zero() const;\n\tbool is_fully_ones() const;\n\tbool is_fully_def() const;\n\tbool is_fully_undef() const;\n\tbool has_const() const;\n\tbool has_marked_bits() const;\n\tbool is_onehot(int *pos = nullptr) const;\n\n\tbool as_bool() const;\n\n\t// Convert the SigSpec to a C++ int, assuming all bits are constant.\n\t// NOTE: If the value is too wide to fit in int (32 bits) this will\n\t// truncate any higher bits, potentially over/underflowing. Consider using\n\t// try_as_int, as_int_saturating, or guarding behind convertible_to_int\n\t// instead.\n\tint as_int(bool is_signed = false) const;\n\n\t// Returns true iff the SigSpec is constant and can be converted to an int\n\t// without over/underflow.\n\tbool convertible_to_int(bool is_signed = false) const;\n\n\t// Returns the SigSpec's value as an int if it is a constant and can be\n\t// represented without over/underflow, or std::nullopt otherwise.\n\tstd::optional<int> try_as_int(bool is_signed = false) const;\n\n\t// Returns an all constant SigSpec's value as an int if it can be represented\n\t// without over/underflow, otherwise the max/min value for int depending on\n\t// the sign.\n\tint as_int_saturating(bool is_signed = false) const;\n\n\tstd::string as_string() const;\n\tRTLIL::Const as_const() const;\n\tRTLIL::Wire *as_wire() const;\n\tRTLIL::SigChunk as_chunk() const;\n\tRTLIL::SigBit as_bit() const;\n\n\tbool match(const char* pattern) const;\n\n\tstd::set<RTLIL::SigBit> to_sigbit_set() const;\n\tpool<RTLIL::SigBit> to_sigbit_pool() const;\n\tstd::vector<RTLIL::SigBit> to_sigbit_vector() const;\n\tstd::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;\n\tdict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;\n\n\tstatic bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);\n\tstatic bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);\n\tstatic bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);\n\n\toperator std::vector<RTLIL::SigChunk>() const { return chunks(); }\n\toperator std::vector<RTLIL::SigBit>() const { return bits(); }\n\tconst RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }\n\n#ifndef NDEBUG\n\tvoid check(Module *mod = nullptr) const;\n#else\n\tvoid check(Module *mod = nullptr) const { (void)mod; }\n#endif\n};\n\nstruct RTLIL::Selection\n{\n\t// selection includes boxed modules\n\tbool selects_boxes;\n\t// selection covers full design, including boxed modules\n\tbool complete_selection;\n\t// selection covers full design, not including boxed modules\n\tbool full_selection;\n\tpool<RTLIL::IdString> selected_modules;\n\tdict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;\n\tRTLIL::Design *current_design;\n\n\t// create a new selection\n\tSelection(\n\t\t// should the selection cover the full design\n\t\tbool full = true,\n\t\t// should the selection include boxed modules\n\t\tbool boxes = false,\n\t\t// the design to select from\n\t\tRTLIL::Design *design = nullptr\n\t) :\n\t\tselects_boxes(boxes), complete_selection(full && boxes), full_selection(full && !boxes), current_design(design) { }\n\n\t// checks if the given module exists in the current design and is a\n\t// boxed module, warning the user if the current design is not set\n\tbool boxed_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is included in this selection\n\tbool selected_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is wholly included in this selection,\n\t// i.e. not partially selected\n\tbool selected_whole_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given member from the given module is included in this\n\t// selection\n\tbool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;\n\n\t// optimizes this selection for the given design by:\n\t// - removing non-existent modules and members, any boxed modules and\n\t// their members (if selection does not include boxes), and any\n\t// partially selected modules with no selected members;\n\t// - marking partially selected modules as wholly selected if all\n\t// members of that module are selected; and\n\t// - marking selection as a complete_selection if all modules in the\n\t// given design are selected, or a full_selection if it does not\n\t// include boxes.\n\tvoid optimize(RTLIL::Design *design);\n\n\t// checks if selection covers full design (may or may not include\n\t// boxed-modules)\n\tbool selects_all() const {\n\t\treturn full_selection || complete_selection;\n\t}\n\n\t// add whole module to this selection\n\ttemplate<typename T1> void select(T1 *module) {\n\t\tif (!selects_all() && selected_modules.count(module->name) == 0) {\n\t\t\tselected_modules.insert(module->name);\n\t\t\tselected_members.erase(module->name);\n\t\t\tif (module->get_blackbox_attribute())\n\t\t\t\tselects_boxes = true;\n\t\t}\n\t}\n\n\t// add member of module to this selection\n\ttemplate<typename T1, typename T2> void select(T1 *module, T2 *member) {\n\t\tif (!selects_all() && selected_modules.count(module->name) == 0) {\n\t\t\tselected_members[module->name].insert(member->name);\n\t\t\tif (module->get_blackbox_attribute())\n\t\t\t\tselects_boxes = true;\n\t\t}\n\t}\n\n\t// checks if selection is empty\n\tbool empty() const {\n\t\treturn !selects_all() && selected_modules.empty() && selected_members.empty();\n\t}\n\n\t// clear this selection, leaving it empty\n\tvoid clear();\n\n\t// create a new selection which is empty\n\tstatic Selection EmptySelection(RTLIL::Design *design = nullptr) { return Selection(false, false, design); };\n\n\t// create a new selection with all non-boxed modules\n\tstatic Selection FullSelection(RTLIL::Design *design = nullptr) { return Selection(true, false, design); };\n\n\t// create a new selection with all modules, including boxes\n\tstatic Selection CompleteSelection(RTLIL::Design *design = nullptr) { return Selection(true, true, design); };\n};\n\nstruct RTLIL::Monitor\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tMonitor() {\n\t\tstatic unsigned int hashidx_count = 123456789;\n\t\thashidx_count = mkhash_xorshift(hashidx_count);\n\t\thashidx_ = hashidx_count;\n\t}\n\n\tvirtual ~Monitor() { }\n\tvirtual void notify_module_add(RTLIL::Module*) { }\n\tvirtual void notify_module_del(RTLIL::Module*) { }\n\tvirtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { }\n\tvirtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { }\n\tvirtual void notify_connect(RTLIL::Module*, const std::vector<RTLIL::SigSig>&) { }\n\tvirtual void notify_blackout(RTLIL::Module*) { }\n};\n\n// Forward declaration; defined in preproc.h.\nstruct define_map_t;\n\nstruct RTLIL::Design\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tpool<RTLIL::Monitor*> monitors;\n\tdict<std::string, std::string> scratchpad;\n\n\tbool flagBufferedNormalized = false;\n\tvoid bufNormalize(bool enable=true);\n\n\tint refcount_modules_;\n\tdict<RTLIL::IdString, RTLIL::Module*> modules_;\n\tstd::vector<RTLIL::Binding*> bindings_;\n\n\tstd::vector<AST::AstNode*> verilog_packages, verilog_globals;\n\tstd::unique_ptr<define_map_t> verilog_defines;\n\n\tstd::vector<RTLIL::Selection> selection_stack;\n\tdict<RTLIL::IdString, RTLIL::Selection> selection_vars;\n\tstd::string selected_active_module;\n\n\tDesign();\n\t~Design();\n\n\tRTLIL::ObjRange<RTLIL::Module*> modules();\n\tRTLIL::Module *module(const RTLIL::IdString &name);\n\tconst RTLIL::Module *module(const RTLIL::IdString &name) const;\n\tRTLIL::Module *top_module() const;\n\n\tbool has(const RTLIL::IdString &id) const {\n\t\treturn modules_.count(id) != 0;\n\t}\n\n\tvoid add(RTLIL::Module *module);\n\tvoid add(RTLIL::Binding *binding);\n\n\tRTLIL::Module *addModule(RTLIL::IdString name);\n\tvoid remove(RTLIL::Module *module);\n\tvoid rename(RTLIL::Module *module, RTLIL::IdString new_name);\n\n\tvoid scratchpad_unset(const std::string &varname);\n\n\tvoid scratchpad_set_int(const std::string &varname, int value);\n\tvoid scratchpad_set_bool(const std::string &varname, bool value);\n\tvoid scratchpad_set_string(const std::string &varname, std::string value);\n\n\tint scratchpad_get_int(const std::string &varname, int default_value = 0) const;\n\tbool scratchpad_get_bool(const std::string &varname, bool default_value = false) const;\n\tstd::string scratchpad_get_string(const std::string &varname, const std::string &default_value = std::string()) const;\n\n\tvoid sort();\n\tvoid sort_modules();\n\tvoid check();\n\tvoid optimize();\n\n\t// checks if the given module is included in the current selection\n\tbool selected_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is wholly included in the current\n\t// selection, i.e. not partially selected\n\tbool selected_whole_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given member from the given module is included in the\n\t// current selection\n\tbool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;\n\n\t// checks if the given module is included in the current selection\n\tbool selected_module(RTLIL::Module *mod) const;\n\n\t// checks if the given module is wholly included in the current\n\t// selection, i.e. not partially selected\n\tbool selected_whole_module(RTLIL::Module *mod) const;\n\n\t// push the given selection to the selection stack\n\tvoid push_selection(RTLIL::Selection sel);\n\t// push a new selection to the selection stack, with nothing selected\n\tvoid push_empty_selection();\n\t// push a new selection to the selection stack, with all non-boxed\n\t// modules selected\n\tvoid push_full_selection();\n\t// push a new selection to the selection stack, with all modules\n\t// selected including boxes\n\tvoid push_complete_selection();\n\t// pop the current selection from the stack, returning to a full\n\t// selection (no boxes) if the stack is empty\n\tvoid pop_selection();\n\n\t// get the current selection\n\tRTLIL::Selection &selection() {\n\t\treturn selection_stack.back();\n\t}\n\n\t// get the current selection\n\tconst RTLIL::Selection &selection() const {\n\t\treturn selection_stack.back();\n\t}\n\n\t// is the current selection a full selection (no boxes)\n\tbool full_selection() const {\n\t\treturn selection().full_selection;\n\t}\n\n\t// is the given module in the current selection\n\ttemplate<typename T1> bool selected(T1 *module) const {\n\t\treturn selected_module(module->name);\n\t}\n\n\t// is the given member of the given module in the current selection\n\ttemplate<typename T1, typename T2> bool selected(T1 *module, T2 *member) const {\n\t\treturn selected_member(module->name, member->name);\n\t}\n\n\t// add whole module to the current selection\n\ttemplate<typename T1> void select(T1 *module) {\n\t\tRTLIL::Selection &sel = selection();\n\t\tsel.select(module);\n\t}\n\n\t// add member of module to the current selection\n\ttemplate<typename T1, typename T2> void select(T1 *module, T2 *member) {\n\t\tRTLIL::Selection &sel = selection();\n\t\tsel.select(module, member);\n\t}\n\n\n\t// returns all selected modules\n\tstd::vector<RTLIL::Module*> selected_modules(\n\t\t// controls if partially selected modules are included\n\t\tRTLIL::SelectPartials partials = SELECT_ALL,\n\t\t// controls if boxed modules are included\n\t\tRTLIL::SelectBoxes boxes = SB_UNBOXED_WARN\n\t) const;\n\n\t// returns all selected modules, and may include boxes\n\tstd::vector<RTLIL::Module*> all_selected_modules() const { return selected_modules(SELECT_ALL, SB_ALL); }\n\t// returns all selected unboxed modules, silently ignoring any boxed\n\t// modules in the selection\n\tstd::vector<RTLIL::Module*> selected_unboxed_modules() const { return selected_modules(SELECT_ALL, SB_UNBOXED_ONLY); }\n\t// returns all selected unboxed modules, warning the user if any boxed\n\t// modules have been ignored\n\tstd::vector<RTLIL::Module*> selected_unboxed_modules_warn() const { return selected_modules(SELECT_ALL, SB_UNBOXED_WARN); }\n\n\t[[deprecated(\"Use select_unboxed_whole_modules() to maintain prior behaviour, or consider one of the other selected whole module helpers.\")]]\n\tstd::vector<RTLIL::Module*> selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_WARN); }\n\t// returns all selected whole modules, silently ignoring partially\n\t// selected modules, and may include boxes\n\tstd::vector<RTLIL::Module*> all_selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_ALL); }\n\t// returns all selected whole modules, warning the user if any partially\n\t// selected or boxed modules have been ignored; optionally includes\n\t// selected whole modules with the 'whitebox' attribute\n\tstd::vector<RTLIL::Module*> selected_whole_modules_warn(\n\t\t// should whole modules with the 'whitebox' attribute be\n\t\t// included\n\t\tbool include_wb = false\n\t) const { return selected_modules(SELECT_WHOLE_WARN, include_wb ? SB_EXCL_BB_WARN : SB_UNBOXED_WARN); }\n\t// returns all selected unboxed whole modules, silently ignoring\n\t// partially selected or boxed modules\n\tstd::vector<RTLIL::Module*> selected_unboxed_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_ONLY); }\n\t// returns all selected unboxed whole modules, warning the user if any\n\t// partially selected or boxed modules have been ignored\n\tstd::vector<RTLIL::Module*> selected_unboxed_whole_modules_warn() const { return selected_modules(SELECT_WHOLE_WARN, SB_UNBOXED_WARN); }\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);\n#endif\n};\n\nstruct RTLIL::Module : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\tvoid add(RTLIL::Wire *wire);\n\tvoid add(RTLIL::Cell *cell);\n\tvoid add(RTLIL::Process *process);\n\npublic:\n\tRTLIL::Design *design;\n\tpool<RTLIL::Monitor*> monitors;\n\n\tint refcount_wires_;\n\tint refcount_cells_;\n\n\tdict<RTLIL::IdString, RTLIL::Wire*> wires_;\n\tdict<RTLIL::IdString, RTLIL::Cell*> cells_;\n\n\tstd::vector<RTLIL::SigSig> connections_;\n\tstd::vector<RTLIL::Binding*> bindings_;\n\n\tidict<RTLIL::IdString> avail_parameters;\n\tdict<RTLIL::IdString, RTLIL::Const> parameter_default_values;\n\tdict<RTLIL::IdString, RTLIL::Memory*> memories;\n\tdict<RTLIL::IdString, RTLIL::Process*> processes;\n\n\tModule();\n\tvirtual ~Module();\n\tvirtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail = false);\n\tvirtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);\n\tvirtual size_t count_id(const RTLIL::IdString& id);\n\tvirtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);\n\tvirtual bool reprocess_if_necessary(RTLIL::Design *design);\n\n\tvirtual void sort();\n\tvirtual void check();\n\tvirtual void optimize();\n\tvirtual void makeblackbox();\n\n\tbool get_blackbox_attribute(bool ignore_wb=false) const {\n\t\treturn get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));\n\t}\n\n\tvoid connect(const RTLIL::SigSig &conn);\n\tvoid connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);\n\tvoid new_connections(const std::vector<RTLIL::SigSig> &new_conn);\n\tconst std::vector<RTLIL::SigSig> &connections() const;\n\n\tstd::vector<RTLIL::IdString> ports;\n\tvoid fixup_ports();\n\n\tpool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;\n\tvoid bufNormalize();\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tvoid cloneInto(RTLIL::Module *new_mod) const;\n\tvirtual RTLIL::Module *clone() const;\n\n\tbool has_memories() const;\n\tbool has_processes() const;\n\n\tbool has_memories_warn() const;\n\tbool has_processes_warn() const;\n\n\tbool is_selected() const;\n\tbool is_selected_whole() const;\n\n\tstd::vector<RTLIL::Wire*> selected_wires() const;\n\tstd::vector<RTLIL::Cell*> selected_cells() const;\n\tstd::vector<RTLIL::Memory*> selected_memories() const;\n\tstd::vector<RTLIL::Process*> selected_processes() const;\n\tstd::vector<RTLIL::NamedObject*> selected_members() const;\n\n\ttemplate<typename T> bool selected(T *member) const {\n\t\treturn design->selected_member(name, member->name);\n\t}\n\n\tRTLIL::Wire* wire(const RTLIL::IdString &id) {\n\t\tauto it = wires_.find(id);\n\t\treturn it == wires_.end() ? nullptr : it->second;\n\t}\n\tRTLIL::Cell* cell(const RTLIL::IdString &id) {\n\t\tauto it = cells_.find(id);\n\t\treturn it == cells_.end() ? nullptr : it->second;\n\t}\n\n\tconst RTLIL::Wire* wire(const RTLIL::IdString &id) const{\n\t\tauto it = wires_.find(id);\n\t\treturn it == wires_.end() ? nullptr : it->second;\n\t}\n\tconst RTLIL::Cell* cell(const RTLIL::IdString &id) const {\n\t\tauto it = cells_.find(id);\n\t\treturn it == cells_.end() ? nullptr : it->second;\n\t}\n\n\tRTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }\n\tRTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }\n\n\tvoid add(RTLIL::Binding *binding);\n\n\t// Removing wires is expensive. If you have to remove wires, remove them all at once.\n\tvoid remove(const pool<RTLIL::Wire*> &wires);\n\tvoid remove(RTLIL::Cell *cell);\n\tvoid remove(RTLIL::Process *process);\n\n\tvoid rename(RTLIL::Wire *wire, RTLIL::IdString new_name);\n\tvoid rename(RTLIL::Cell *cell, RTLIL::IdString new_name);\n\tvoid rename(RTLIL::IdString old_name, RTLIL::IdString new_name);\n\n\tvoid swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2);\n\tvoid swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2);\n\n\tRTLIL::IdString uniquify(RTLIL::IdString name);\n\tRTLIL::IdString uniquify(RTLIL::IdString name, int &index);\n\n\tRTLIL::Wire *addWire(RTLIL::IdString name, int width = 1);\n\tRTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other);\n\n\tRTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type);\n\tRTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other);\n\n\tRTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other);\n\n\tRTLIL::Process *addProcess(RTLIL::IdString name);\n\tRTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other);\n\n\t// The add* methods create a cell and return the created cell. All signals must exist in advance.\n\n\tRTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addShl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addLt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addEq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addEqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addGe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addGt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\t// truncating division\n\tRTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\t// truncating modulo\n\tRTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = \"\");\n\tRTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = \"\");\n\tRTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addLive (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addFair (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addCover (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addEquiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSr (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\tRTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\n\tRTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addXorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addXnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addMuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tconst RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addFfGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\tRTLIL::Cell* addDffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsreGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tconst RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tconst RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffceGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\n\t// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.\n\n\tRTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Xor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec ReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Shl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Lt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Le (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Eq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Ne (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Ge (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Gt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\t// truncating division\n\tRTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\t// truncating modulo\n\tRTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec LogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = \"\");\n\tRTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\n\tRTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = \"\");\n\tRTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = \"\");\n\tRTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit NandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit OrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit NorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit XorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit XnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit OrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit MuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = \"\");\n\tRTLIL::SigBit NmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = \"\");\n\tRTLIL::SigBit Aoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = \"\");\n\tRTLIL::SigBit Oai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = \"\");\n\tRTLIL::SigBit Aoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = \"\");\n\tRTLIL::SigBit Oai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = \"\");\n\n\tRTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = \"\");\n\tRTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = \"\");\n\tRTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = \"\");\n\tRTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = \"\");\n\tRTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = \"\");\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);\n#endif\n};\n\nnamespace RTLIL_BACKEND {\nvoid dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);\n}\n\nstruct RTLIL::Wire : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addWire() and module->remove() to create or destroy wires\n\tfriend struct RTLIL::Module;\n\tWire();\n\t~Wire();\n\n\tfriend struct RTLIL::Design;\n\tfriend struct RTLIL::Cell;\n\tfriend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);\n\tRTLIL::Cell *driverCell_ = nullptr;\n\tRTLIL::IdString driverPort_;\n\npublic:\n\t// do not simply copy wires\n\tWire(RTLIL::Wire &other) = delete;\n\tvoid operator=(RTLIL::Wire &other) = delete;\n\n\tRTLIL::Module *module;\n\tint width, start_offset, port_id;\n\tbool port_input, port_output, upto, is_signed;\n\n\tRTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };\n\tRTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };\n\n\tint from_hdl_index(int hdl_index) {\n\t\tint zero_index = hdl_index - start_offset;\n\t\tint rtlil_index = upto ? width - 1 - zero_index : zero_index;\n\t\treturn rtlil_index >= 0 && rtlil_index < width ? rtlil_index : INT_MIN;\n\t}\n\n\tint to_hdl_index(int rtlil_index) {\n\t\tif (rtlil_index < 0 || rtlil_index >= width)\n\t\t\treturn INT_MIN;\n\t\tint zero_index = upto ? width - 1 - rtlil_index : rtlil_index;\n\t\treturn zero_index + start_offset;\n\t}\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);\n#endif\n};\n\ninline int GetSize(RTLIL::Wire *wire) {\n\treturn wire->width;\n}\n\nstruct RTLIL::Memory : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tMemory();\n\n\tint width, start_offset, size;\n#ifdef WITH_PYTHON\n\t~Memory();\n\tstatic std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void);\n#endif\n};\n\nstruct RTLIL::Cell : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addCell() and module->remove() to create or destroy cells\n\tfriend struct RTLIL::Module;\n\tCell();\n\t~Cell();\n\npublic:\n\t// do not simply copy cells\n\tCell(RTLIL::Cell &other) = delete;\n\tvoid operator=(RTLIL::Cell &other) = delete;\n\n\tRTLIL::Module *module;\n\tRTLIL::IdString type;\n\tdict<RTLIL::IdString, RTLIL::SigSpec> connections_;\n\tdict<RTLIL::IdString, RTLIL::Const> parameters;\n\n\t// access cell ports\n\tbool hasPort(const RTLIL::IdString &portname) const;\n\tvoid unsetPort(const RTLIL::IdString &portname);\n\tvoid setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);\n\tconst RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const;\n\tconst dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;\n\n\t// information about cell ports\n\tbool known() const;\n\tbool input(const RTLIL::IdString &portname) const;\n\tbool output(const RTLIL::IdString &portname) const;\n\n\t// access cell parameters\n\tbool hasParam(const RTLIL::IdString ¶mname) const;\n\tvoid unsetParam(const RTLIL::IdString ¶mname);\n\tvoid setParam(const RTLIL::IdString ¶mname, RTLIL::Const value);\n\tconst RTLIL::Const &getParam(const RTLIL::IdString ¶mname) const;\n\n\tvoid sort();\n\tvoid check();\n\tvoid fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);\n\n\tbool has_keep_attr() const {\n\t\treturn get_bool_attribute(ID::keep) || (module && module->design && module->design->module(type) &&\n\t\t\t\tmodule->design->module(type)->get_bool_attribute(ID::keep));\n\t}\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);\n#endif\n\n\tbool has_memid() const;\n\tbool is_mem_cell() const;\n};\n\nstruct RTLIL::CaseRule : public RTLIL::AttrObject\n{\n\tstd::vector<RTLIL::SigSpec> compare;\n\tstd::vector<RTLIL::SigSig> actions;\n\tstd::vector<RTLIL::SwitchRule*> switches;\n\n\t~CaseRule();\n\n\tbool empty() const;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::CaseRule *clone() const;\n};\n\nstruct RTLIL::SwitchRule : public RTLIL::AttrObject\n{\n\tRTLIL::SigSpec signal;\n\tstd::vector<RTLIL::CaseRule*> cases;\n\n\t~SwitchRule();\n\n\tbool empty() const;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::SwitchRule *clone() const;\n};\n\nstruct RTLIL::MemWriteAction : RTLIL::AttrObject\n{\n\tRTLIL::IdString memid;\n\tRTLIL::SigSpec address;\n\tRTLIL::SigSpec data;\n\tRTLIL::SigSpec enable;\n\tRTLIL::Const priority_mask;\n};\n\nstruct RTLIL::SyncRule\n{\n\tRTLIL::SyncType type;\n\tRTLIL::SigSpec signal;\n\tstd::vector<RTLIL::SigSig> actions;\n\tstd::vector<RTLIL::MemWriteAction> mem_write_actions;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::SyncRule *clone() const;\n};\n\nstruct RTLIL::Process : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addProcess() and module->remove() to create or destroy processes\n\tfriend struct RTLIL::Module;\n\tProcess();\n\t~Process();\n\npublic:\n\tRTLIL::Module *module;\n\tRTLIL::CaseRule root_case;\n\tstd::vector<RTLIL::SyncRule*> syncs;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::Process *clone() const;\n};\n\n\ninline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }\ninline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }\ninline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? State::S1 : State::S0) { }\ninline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }\ninline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }\ninline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }\ninline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }\n\ninline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {\n\tif (wire == other.wire)\n\t\treturn wire ? (offset < other.offset) : (data < other.data);\n\tif (wire != nullptr && other.wire != nullptr)\n\t\treturn wire->name < other.wire->name;\n\treturn (wire != nullptr) < (other.wire != nullptr);\n}\n\ninline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {\n\treturn (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));\n}\n\ninline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {\n\treturn (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));\n}\n\ninline Hasher RTLIL::SigBit::hash_into(Hasher h) const {\n\tif (wire) {\n\t\th.eat(offset);\n\t\th.eat(wire->name);\n\t\treturn h;\n\t}\n\th.eat(data);\n\treturn h;\n}\n\n\ninline Hasher RTLIL::SigBit::hash_top() const {\n\tHasher h;\n\tif (wire) {\n\t\th.force(hashlib::legacy::djb2_add(wire->name.index_, offset));\n\t\treturn h;\n\t}\n\th.force(data);\n\treturn h;\n}\n\ninline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {\n\treturn (*sig_p)[index];\n}\n\ninline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {\n\treturn (*sig_p)[index];\n}\n\ninline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {\n\tlog_assert(sig.size() == 1 && sig.chunks().size() == 1);\n\t*this = SigBit(sig.chunks().front());\n}\n\ntemplate<typename T>\nvoid RTLIL::Module::rewrite_sigspecs(T &functor)\n{\n\tfor (auto &it : cells_)\n\t\tit.second->rewrite_sigspecs(functor);\n\tfor (auto &it : processes)\n\t\tit.second->rewrite_sigspecs(functor);\n\tfor (auto &it : connections_) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Module::rewrite_sigspecs2(T &functor)\n{\n\tfor (auto &it : cells_)\n\t\tit.second->rewrite_sigspecs2(functor);\n\tfor (auto &it : processes)\n\t\tit.second->rewrite_sigspecs2(functor);\n\tfor (auto &it : connections_) {\n\t\tfunctor(it.first, it.second);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Cell::rewrite_sigspecs(T &functor) {\n\tfor (auto &it : connections_)\n\t\tfunctor(it.second);\n}\n\ntemplate<typename T>\nvoid RTLIL::Cell::rewrite_sigspecs2(T &functor) {\n\tfor (auto &it : connections_)\n\t\tfunctor(it.second);\n}\n\ntemplate<typename T>\nvoid RTLIL::CaseRule::rewrite_sigspecs(T &functor) {\n\tfor (auto &it : compare)\n\t\tfunctor(it);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n\tfor (auto it : switches)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {\n\tfor (auto &it : compare)\n\t\tfunctor(it);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first, it.second);\n\t}\n\tfor (auto it : switches)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SwitchRule::rewrite_sigspecs(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto it : cases)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto it : cases)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SyncRule::rewrite_sigspecs(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n\tfor (auto &it : mem_write_actions) {\n\t\tfunctor(it.address);\n\t\tfunctor(it.data);\n\t\tfunctor(it.enable);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::SyncRule::rewrite_sigspecs2(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first, it.second);\n\t}\n\tfor (auto &it : mem_write_actions) {\n\t\tfunctor(it.address);\n\t\tfunctor(it.data);\n\t\tfunctor(it.enable);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Process::rewrite_sigspecs(T &functor)\n{\n\troot_case.rewrite_sigspecs(functor);\n\tfor (auto it : syncs)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::Process::rewrite_sigspecs2(T &functor)\n{\n\troot_case.rewrite_sigspecs2(functor);\n\tfor (auto it : syncs)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
186
|
-
"satgen.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SATGEN_H\n#define SATGEN_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n#include \"kernel/macc.h\"\n\n#include \"libs/ezsat/ezminisat.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// defined in kernel/register.cc\nextern struct SatSolver *yosys_satsolver_list;\nextern struct SatSolver *yosys_satsolver;\n\nstruct SatSolver\n{\n\tstring name;\n\tSatSolver *next;\n\tvirtual ezSAT *create() = 0;\n\n\tSatSolver(string name) : name(name) {\n\t\tnext = yosys_satsolver_list;\n\t\tyosys_satsolver_list = this;\n\t}\n\n\tvirtual ~SatSolver() {\n\t\tauto p = &yosys_satsolver_list;\n\t\twhile (*p) {\n\t\t\tif (*p == this)\n\t\t\t\t*p = next;\n\t\t\telse\n\t\t\t\tp = &(*p)->next;\n\t\t}\n\t\tif (yosys_satsolver == this)\n\t\t\tyosys_satsolver = yosys_satsolver_list;\n\t}\n};\n\nstruct ezSatPtr : public std::unique_ptr<ezSAT> {\n\tezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { }\n};\n\nstruct SatGen\n{\n\tezSAT *ez;\n\tSigMap *sigmap;\n\tstd::string prefix;\n\tSigPool initial_state;\n\tstd::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;\n\tstd::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;\n\tstd::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;\n\tstd::map<std::pair<std::string, int>, bool> initstates;\n\tbool ignore_div_by_zero;\n\tbool model_undef;\n\tbool def_formal = false;\n\n\tSatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) :\n\t\t\tez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)\n\t{\n\t}\n\n\tvoid setContext(SigMap *sigmap, std::string prefix = std::string())\n\t{\n\t\tthis->sigmap = sigmap;\n\t\tthis->prefix = prefix;\n\t}\n\n\tstd::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef)\n\t{\n\t\tlog_assert(!undef_mode || model_undef);\n\t\tsigmap->apply(sig);\n\n\t\tstd::vector<int> vec;\n\t\tvec.reserve(GetSize(sig));\n\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire == NULL) {\n\t\t\t\tif (model_undef && dup_undef && bit == RTLIL::State::Sx)\n\t\t\t\t\tvec.push_back(ez->frozen_literal());\n\t\t\t\telse\n\t\t\t\t\tvec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE);\n\t\t\t} else {\n\t\t\t\tstd::string wire_name = RTLIL::unescape_id(bit.wire->name);\n\t\t\t\tstd::string name = pf +\n\t\t\t\t\t(bit.wire->width == 1 ? wire_name : stringf(\"%s [%d]\", wire_name.c_str(), bit.offset));\n\t\t\t\tvec.push_back(ez->frozen_literal(name));\n\t\t\t\timported_signals[pf][bit] = vec.back();\n\t\t\t}\n\t\treturn vec;\n\t}\n\n\tstd::vector<int> importSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, false, false);\n\t}\n\n\tstd::vector<int> importDefSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, false, true);\n\t}\n\n\tstd::vector<int> importUndefSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = \"undef:\" + prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, true, false);\n\t}\n\n\tint importSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, false, false).front();\n\t}\n\n\tint importDefSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, false, true).front();\n\t}\n\n\tint importUndefSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = \"undef:\" + prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, true, false).front();\n\t}\n\n\tbool importedSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn imported_signals[pf].count(bit) != 0;\n\t}\n\n\tvoid getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)\n\t{\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tsig_a = asserts_a[pf];\n\t\tsig_en = asserts_en[pf];\n\t}\n\n\tvoid getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)\n\t{\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tsig_a = assumes_a[pf];\n\t\tsig_en = assumes_en[pf];\n\t}\n\n\tint importAsserts(int timestep = -1)\n\t{\n\t\tstd::vector<int> check_bits, enable_bits;\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tif (model_undef) {\n\t\t\tcheck_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_a[pf], timestep)), importDefSigSpec(asserts_a[pf], timestep));\n\t\t\tenable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_en[pf], timestep)), importDefSigSpec(asserts_en[pf], timestep));\n\t\t} else {\n\t\t\tcheck_bits = importDefSigSpec(asserts_a[pf], timestep);\n\t\t\tenable_bits = importDefSigSpec(asserts_en[pf], timestep);\n\t\t}\n\t\treturn ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));\n\t}\n\n\tint importAssumes(int timestep = -1)\n\t{\n\t\tstd::vector<int> check_bits, enable_bits;\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tif (model_undef) {\n\t\t\tcheck_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep));\n\t\t\tenable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep));\n\t\t} else {\n\t\t\tcheck_bits = importDefSigSpec(assumes_a[pf], timestep);\n\t\t\tenable_bits = importDefSigSpec(assumes_en[pf], timestep);\n\t\t}\n\t\treturn ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));\n\t}\n\n\tint signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1)\n\t{\n\t\tif (timestep_rhs < 0)\n\t\t\ttimestep_rhs = timestep_lhs;\n\n\t\tlog_assert(lhs.size() == rhs.size());\n\n\t\tstd::vector<int> vec_lhs = importSigSpec(lhs, timestep_lhs);\n\t\tstd::vector<int> vec_rhs = importSigSpec(rhs, timestep_rhs);\n\n\t\tif (!model_undef)\n\t\t\treturn ez->vec_eq(vec_lhs, vec_rhs);\n\n\t\tstd::vector<int> undef_lhs = importUndefSigSpec(lhs, timestep_lhs);\n\t\tstd::vector<int> undef_rhs = importUndefSigSpec(rhs, timestep_rhs);\n\n\t\tstd::vector<int> eq_bits;\n\t\tfor (int i = 0; i < lhs.size(); i++)\n\t\t\teq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)),\n\t\t\t\t\tez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i)))));\n\t\treturn ez->expression(ezSAT::OpAnd, eq_bits);\n\t}\n\n\tvoid extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, RTLIL::Cell *cell, size_t y_width = 0, bool forced_signed = false)\n\t{\n\t\tbool is_signed = forced_signed;\n\t\tif (!forced_signed && cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters.count(ID::B_SIGNED) > 0)\n\t\t\tis_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool();\n\t\twhile (vec_a.size() < vec_b.size() || vec_a.size() < y_width)\n\t\t\tvec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);\n\t\twhile (vec_b.size() < vec_a.size() || vec_b.size() < y_width)\n\t\t\tvec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE);\n\t}\n\n\tvoid extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)\n\t{\n\t\textendSignalWidth(vec_a, vec_b, cell, vec_y.size(), forced_signed);\n\t\twhile (vec_y.size() < vec_a.size())\n\t\t\tvec_y.push_back(ez->literal());\n\t}\n\n\tvoid extendSignalWidthUnary(std::vector<int> &vec_a, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)\n\t{\n\t\tbool is_signed = forced_signed || (cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool());\n\t\twhile (vec_a.size() < vec_y.size())\n\t\t\tvec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);\n\t\twhile (vec_y.size() < vec_a.size())\n\t\t\tvec_y.push_back(ez->literal());\n\t}\n\n\tvoid undefGating(std::vector<int> &vec_y, std::vector<int> &vec_yy, std::vector<int> &vec_undef)\n\t{\n\t\tlog_assert(model_undef);\n\t\tlog_assert(vec_y.size() == vec_yy.size());\n\t\tif (vec_y.size() > vec_undef.size()) {\n\t\t\tstd::vector<int> trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size());\n\t\t\tstd::vector<int> trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size());\n\t\t\tez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy))));\n\t\t} else {\n\t\t\tlog_assert(vec_y.size() == vec_undef.size());\n\t\t\tez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));\n\t\t}\n\t}\n\n\tstd::pair<std::vector<int>, std::vector<int>> mux(int s, int undef_s, const std::vector<int> &a, const std::vector<int> &undef_a, const std::vector<int> &b, const std::vector<int> &undef_b) {\n\t\tstd::vector<int> res;\n\t\tstd::vector<int> undef_res;\n\t\tres = ez->vec_ite(s, b, a);\n\t\tif (model_undef) {\n\t\t\tstd::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));\n\t\t\tstd::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));\n\t\t\tundef_res = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a));\n\t\t}\n\t\treturn std::make_pair(res, undef_res);\n\t}\n\n\tvoid undefGating(int y, int yy, int undef)\n\t{\n\t\tez->assume(ez->OR(undef, ez->IFF(y, yy)));\n\t}\n\n\tvoid setInitState(int timestep)\n\t{\n\t\tauto key = make_pair(prefix, timestep);\n\t\tlog_assert(initstates.count(key) == 0 || initstates.at(key) == true);\n\t\tinitstates[key] = true;\n\t}\n\n\tbool importCell(RTLIL::Cell *cell, int timestep = -1);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
185
|
+
"rtlil.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef RTLIL_H\n#define RTLIL_H\n\n#include \"kernel/yosys_common.h\"\n#include \"kernel/yosys.h\"\n\n#include <string_view>\n#include <unordered_map>\n\nYOSYS_NAMESPACE_BEGIN\n\nnamespace RTLIL\n{\n\tenum State : unsigned char {\n\t\tS0 = 0,\n\t\tS1 = 1,\n\t\tSx = 2, // undefined value or conflict\n\t\tSz = 3, // high-impedance / not-connected\n\t\tSa = 4, // don't care (used only in cases)\n\t\tSm = 5 // marker (used internally by some passes)\n\t};\n\n\tenum SyncType : unsigned char {\n\t\tST0 = 0, // level sensitive: 0\n\t\tST1 = 1, // level sensitive: 1\n\t\tSTp = 2, // edge sensitive: posedge\n\t\tSTn = 3, // edge sensitive: negedge\n\t\tSTe = 4, // edge sensitive: both edges\n\t\tSTa = 5, // always active\n\t\tSTg = 6, // global clock\n\t\tSTi = 7 // init\n\t};\n\n\t// Semantic metadata - how can this constant be interpreted?\n\t// Values may be generally non-exclusive\n\tenum ConstFlags : unsigned char {\n\t\tCONST_FLAG_NONE = 0,\n\t\tCONST_FLAG_STRING = 1,\n\t\tCONST_FLAG_SIGNED = 2, // only used for parameters\n\t\tCONST_FLAG_REAL = 4 // only used for parameters\n\t};\n\n\tenum SelectPartials : unsigned char {\n\t\tSELECT_ALL = 0, // include partial modules\n\t\tSELECT_WHOLE_ONLY = 1, // ignore partial modules\n\t\tSELECT_WHOLE_WARN = 2, // call log_warning on partial module\n\t\tSELECT_WHOLE_ERR = 3, // call log_error on partial module\n\t\tSELECT_WHOLE_CMDERR = 4 // call log_cmd_error on partial module\n\t};\n\n\tenum SelectBoxes : unsigned char {\n\t\tSB_ALL = 0, // include boxed modules\n\t\tSB_WARN = 1, // helper for log_warning (not for direct use)\n\t\tSB_ERR = 2, // helper for log_error (not for direct use)\n\t\tSB_CMDERR = 3, // helper for log_cmd_error (not for direct use)\n\t\tSB_UNBOXED_ONLY = 4, // ignore boxed modules\n\t\tSB_UNBOXED_WARN = 5, // call log_warning on boxed module\n\t\tSB_UNBOXED_ERR = 6, // call log_error on boxed module\n\t\tSB_UNBOXED_CMDERR = 7, // call log_cmd_error on boxed module\n\t\tSB_INCL_WB = 8, // helper for white boxes (not for direct use)\n\t\tSB_EXCL_BB_ONLY = 12, // ignore black boxes, but not white boxes\n\t\tSB_EXCL_BB_WARN = 13, // call log_warning on black boxed module\n\t\tSB_EXCL_BB_ERR = 14, // call log_error on black boxed module\n\t\tSB_EXCL_BB_CMDERR = 15 // call log_cmd_error on black boxed module\n\t};\n\n\tstruct Const;\n\tstruct AttrObject;\n\tstruct NamedObject;\n\tstruct Selection;\n\tstruct Monitor;\n\tstruct Design;\n\tstruct Module;\n\tstruct Wire;\n\tstruct Memory;\n\tstruct Cell;\n\tstruct SigChunk;\n\tstruct SigBit;\n\tstruct SigSpecIterator;\n\tstruct SigSpecConstIterator;\n\tstruct SigSpec;\n\tstruct CaseRule;\n\tstruct SwitchRule;\n\tstruct MemWriteAction;\n\tstruct SyncRule;\n\tstruct Process;\n\tstruct Binding;\n\tstruct IdString;\n\n\ttypedef std::pair<SigSpec, SigSpec> SigSig;\n};\n\nstruct RTLIL::IdString\n{\n\t#undef YOSYS_XTRACE_GET_PUT\n\t#undef YOSYS_SORT_ID_FREE_LIST\n\t#undef YOSYS_USE_STICKY_IDS\n\t#undef YOSYS_NO_IDS_REFCNT\n\n\t// the global id string cache\n\n\tstatic bool destruct_guard_ok; // POD, will be initialized to zero\n\tstatic struct destruct_guard_t {\n\t\tdestruct_guard_t() { destruct_guard_ok = true; }\n\t\t~destruct_guard_t() { destruct_guard_ok = false; }\n\t} destruct_guard;\n\n\tstatic std::vector<char*> global_id_storage_;\n\tstatic std::unordered_map<std::string_view, int> global_id_index_;\n#ifndef YOSYS_NO_IDS_REFCNT\n\tstatic std::vector<int> global_refcount_storage_;\n\tstatic std::vector<int> global_free_idx_list_;\n#endif\n\n#ifdef YOSYS_USE_STICKY_IDS\n\tstatic int last_created_idx_ptr_;\n\tstatic int last_created_idx_[8];\n#endif\n\n\tstatic inline void xtrace_db_dump()\n\t{\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tfor (int idx = 0; idx < GetSize(global_id_storage_); idx++)\n\t\t{\n\t\t\tif (global_id_storage_.at(idx) == nullptr)\n\t\t\t\tlog(\"#X# DB-DUMP index %d: FREE\\n\", idx);\n\t\t\telse\n\t\t\t\tlog(\"#X# DB-DUMP index %d: '%s' (ref %d)\\n\", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));\n\t\t}\n\t#endif\n\t}\n\n\tstatic inline void checkpoint()\n\t{\n\t#ifdef YOSYS_USE_STICKY_IDS\n\t\tlast_created_idx_ptr_ = 0;\n\t\tfor (int i = 0; i < 8; i++) {\n\t\t\tif (last_created_idx_[i])\n\t\t\t\tput_reference(last_created_idx_[i]);\n\t\t\tlast_created_idx_[i] = 0;\n\t\t}\n\t#endif\n\t#ifdef YOSYS_SORT_ID_FREE_LIST\n\t\tstd::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());\n\t#endif\n\t}\n\n\tstatic inline int get_reference(int idx)\n\t{\n\t\tif (idx) {\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\t\tglobal_refcount_storage_[idx]++;\n\t#endif\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\t\tif (yosys_xtrace)\n\t\t\t\tlog(\"#X# GET-BY-INDEX '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t#endif\n\t\t}\n\t\treturn idx;\n\t}\n\n\tstatic int get_reference(const char *p)\n\t{\n\t\tlog_assert(destruct_guard_ok);\n\n\t\tif (!p[0])\n\t\t\treturn 0;\n\n\t\tauto it = global_id_index_.find((char*)p);\n\t\tif (it != global_id_index_.end()) {\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\t\tglobal_refcount_storage_.at(it->second)++;\n\t#endif\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\t\tif (yosys_xtrace)\n\t\t\t\tlog(\"#X# GET-BY-NAME '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));\n\t#endif\n\t\t\treturn it->second;\n\t\t}\n\n\t\tlog_assert(p[0] == '$' || p[0] == '\\\\');\n\t\tlog_assert(p[1] != 0);\n\t\tfor (const char *c = p; *c; c++)\n\t\t\tif ((unsigned)*c <= (unsigned)' ')\n\t\t\t\tlog_error(\"Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\\n\", *c, p);\n\n\t#ifndef YOSYS_NO_IDS_REFCNT\n\t\tif (global_free_idx_list_.empty()) {\n\t\t\tif (global_id_storage_.empty()) {\n\t\t\t\tglobal_refcount_storage_.push_back(0);\n\t\t\t\tglobal_id_storage_.push_back((char*)\"\");\n\t\t\t\tglobal_id_index_[global_id_storage_.back()] = 0;\n\t\t\t}\n\t\t\tlog_assert(global_id_storage_.size() < 0x40000000);\n\t\t\tglobal_free_idx_list_.push_back(global_id_storage_.size());\n\t\t\tglobal_id_storage_.push_back(nullptr);\n\t\t\tglobal_refcount_storage_.push_back(0);\n\t\t}\n\n\t\tint idx = global_free_idx_list_.back();\n\t\tglobal_free_idx_list_.pop_back();\n\t\tglobal_id_storage_.at(idx) = strdup(p);\n\t\tglobal_id_index_[global_id_storage_.at(idx)] = idx;\n\t\tglobal_refcount_storage_.at(idx)++;\n\t#else\n\t\tif (global_id_storage_.empty()) {\n\t\t\tglobal_id_storage_.push_back((char*)\"\");\n\t\t\tglobal_id_index_[global_id_storage_.back()] = 0;\n\t\t}\n\t\tint idx = global_id_storage_.size();\n\t\tglobal_id_storage_.push_back(strdup(p));\n\t\tglobal_id_index_[global_id_storage_.back()] = idx;\n\t#endif\n\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# New IdString '%s' with index %d.\\n\", p, idx);\n\t\t\tlog_backtrace(\"-X- \", yosys_xtrace-1);\n\t\t}\n\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tif (yosys_xtrace)\n\t\t\tlog(\"#X# GET-BY-NAME '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t#endif\n\n\t#ifdef YOSYS_USE_STICKY_IDS\n\t\t// Avoid Create->Delete->Create pattern\n\t\tif (last_created_idx_[last_created_idx_ptr_])\n\t\t\tput_reference(last_created_idx_[last_created_idx_ptr_]);\n\t\tlast_created_idx_[last_created_idx_ptr_] = idx;\n\t\tget_reference(last_created_idx_[last_created_idx_ptr_]);\n\t\tlast_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;\n\t#endif\n\n\t\treturn idx;\n\t}\n\n#ifndef YOSYS_NO_IDS_REFCNT\n\tstatic inline void put_reference(int idx)\n\t{\n\t\t// put_reference() may be called from destructors after the destructor of\n\t\t// global_refcount_storage_ has been run. in this case we simply do nothing.\n\t\tif (!destruct_guard_ok || !idx)\n\t\t\treturn;\n\n\t#ifdef YOSYS_XTRACE_GET_PUT\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# PUT '%s' (index %d, refcount %d)\\n\", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));\n\t\t}\n\t#endif\n\n\t\tint &refcount = global_refcount_storage_[idx];\n\n\t\tif (--refcount > 0)\n\t\t\treturn;\n\n\t\tlog_assert(refcount == 0);\n\t\tfree_reference(idx);\n\t}\n\tstatic inline void free_reference(int idx)\n\t{\n\t\tif (yosys_xtrace) {\n\t\t\tlog(\"#X# Removed IdString '%s' with index %d.\\n\", global_id_storage_.at(idx), idx);\n\t\t\tlog_backtrace(\"-X- \", yosys_xtrace-1);\n\t\t}\n\n\t\tglobal_id_index_.erase(global_id_storage_.at(idx));\n\t\tfree(global_id_storage_.at(idx));\n\t\tglobal_id_storage_.at(idx) = nullptr;\n\t\tglobal_free_idx_list_.push_back(idx);\n\t}\n#else\n\tstatic inline void put_reference(int) { }\n#endif\n\n\t// the actual IdString object is just is a single int\n\n\tint index_;\n\n\tinline IdString() : index_(0) { }\n\tinline IdString(const char *str) : index_(get_reference(str)) { }\n\tinline IdString(const IdString &str) : index_(get_reference(str.index_)) { }\n\tinline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }\n\tinline IdString(const std::string &str) : index_(get_reference(str.c_str())) { }\n\tinline ~IdString() { put_reference(index_); }\n\n\tinline void operator=(const IdString &rhs) {\n\t\tput_reference(index_);\n\t\tindex_ = get_reference(rhs.index_);\n\t}\n\n\tinline void operator=(const char *rhs) {\n\t\tIdString id(rhs);\n\t\t*this = id;\n\t}\n\n\tinline void operator=(const std::string &rhs) {\n\t\tIdString id(rhs);\n\t\t*this = id;\n\t}\n\n\tinline const char *c_str() const {\n\t\treturn global_id_storage_.at(index_);\n\t}\n\n\tinline std::string str() const {\n\t\treturn std::string(global_id_storage_.at(index_));\n\t}\n\n\tinline bool operator<(const IdString &rhs) const {\n\t\treturn index_ < rhs.index_;\n\t}\n\n\tinline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }\n\tinline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }\n\n\t// The methods below are just convenience functions for better compatibility with std::string.\n\n\tbool operator==(const std::string &rhs) const { return c_str() == rhs; }\n\tbool operator!=(const std::string &rhs) const { return c_str() != rhs; }\n\n\tbool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; }\n\tbool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }\n\n\tchar operator[](size_t i) const {\n\t\t\t\t\tconst char *p = c_str();\n#ifndef NDEBUG\n\t\tfor (; i != 0; i--, p++)\n\t\t\tlog_assert(*p != 0);\n\t\treturn *p;\n#else\n\t\treturn *(p + i);\n#endif\n\t}\n\n\tstd::string substr(size_t pos = 0, size_t len = std::string::npos) const {\n\t\tif (len == std::string::npos || len >= strlen(c_str() + pos))\n\t\t\treturn std::string(c_str() + pos);\n\t\telse\n\t\t\treturn std::string(c_str() + pos, len);\n\t}\n\n\tint compare(size_t pos, size_t len, const char* s) const {\n\t\treturn strncmp(c_str()+pos, s, len);\n\t}\n\n\tbool begins_with(const char* prefix) const {\n\t\tsize_t len = strlen(prefix);\n\t\tif (size() < len) return false;\n\t\treturn compare(0, len, prefix) == 0;\n\t}\n\n\tbool ends_with(const char* suffix) const {\n\t\tsize_t len = strlen(suffix);\n\t\tif (size() < len) return false;\n\t\treturn compare(size()-len, len, suffix) == 0;\n\t}\n\n\tbool contains(const char* str) const {\n\t\treturn strstr(c_str(), str);\n\t}\n\n\tsize_t size() const {\n\t\treturn strlen(c_str());\n\t}\n\n\tbool empty() const {\n\t\treturn c_str()[0] == 0;\n\t}\n\n\tvoid clear() {\n\t\t*this = IdString();\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { return hash_ops<int>::hash_into(index_, h); }\n\n\t[[nodiscard]] Hasher hash_top() const {\n\t\tHasher h;\n\t\th.force((Hasher::hash_t) index_);\n\t\treturn h;\n\t}\n\n\t// The following is a helper key_compare class. Instead of for example std::set<Cell*>\n\t// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the\n\t// set has an influence on the algorithm.\n\n\ttemplate<typename T> struct compare_ptr_by_name {\n\t\tbool operator()(const T *a, const T *b) const {\n\t\t\treturn (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);\n\t\t}\n\t};\n\n\t// often one needs to check if a given IdString is part of a list (for example a list\n\t// of cell types). the following functions helps with that.\n\ttemplate<typename... Args>\n\tbool in(Args... args) const {\n\t\treturn (... || in(args));\n\t}\n\n\tbool in(const IdString &rhs) const { return *this == rhs; }\n\tbool in(const char *rhs) const { return *this == rhs; }\n\tbool in(const std::string &rhs) const { return *this == rhs; }\n\tinline bool in(const pool<IdString> &rhs) const;\n\tinline bool in(const pool<IdString> &&rhs) const;\n\n\tbool isPublic() const { return begins_with(\"\\\\\"); }\n};\n\nnamespace hashlib {\n\ttemplate <>\n\tstruct hash_ops<RTLIL::IdString> {\n\t\tstatic inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) {\n\t\t\treturn a == b;\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash(const RTLIL::IdString id) {\n\t\t\treturn id.hash_top();\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString id, Hasher h) {\n\t\t\treturn id.hash_into(h);\n\t\t}\n\t};\n};\n\n/**\n * How to not use these methods:\n * 1. if(celltype.in({...})) -> if(celltype.in(...))\n * 2. pool<IdString> p; ... a.in(p) -> (bool)p.count(a)\n */\n[[deprecated]]\ninline bool RTLIL::IdString::in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }\n[[deprecated]]\ninline bool RTLIL::IdString::in(const pool<IdString> &&rhs) const { return rhs.count(*this) != 0; }\n\nnamespace RTLIL {\n\tnamespace ID {\n#define X(_id) extern IdString _id;\n#include \"kernel/constids.inc\"\n#undef X\n\t};\n\textern dict<std::string, std::string> constpad;\n\n\tconst pool<IdString> &builtin_ff_cell_types();\n\n\tstatic inline std::string escape_id(const std::string &str) {\n\t\tif (str.size() > 0 && str[0] != '\\\\' && str[0] != '$')\n\t\t\treturn \"\\\\\" + str;\n\t\treturn str;\n\t}\n\n\tstatic inline std::string unescape_id(const std::string &str) {\n\t\tif (str.size() < 2)\n\t\t\treturn str;\n\t\tif (str[0] != '\\\\')\n\t\t\treturn str;\n\t\tif (str[1] == '$' || str[1] == '\\\\')\n\t\t\treturn str;\n\t\tif (str[1] >= '0' && str[1] <= '9')\n\t\t\treturn str;\n\t\treturn str.substr(1);\n\t}\n\n\tstatic inline std::string unescape_id(const RTLIL::IdString &str) {\n\t\treturn unescape_id(str.str());\n\t}\n\n\tstatic inline const char *id2cstr(const RTLIL::IdString &str) {\n\t\treturn log_id(str);\n\t}\n\n\ttemplate <typename T> struct sort_by_name_id {\n\t\tbool operator()(T *a, T *b) const {\n\t\t\treturn a->name < b->name;\n\t\t}\n\t};\n\n\ttemplate <typename T> struct sort_by_name_str {\n\t\tbool operator()(T *a, T *b) const {\n\t\t\treturn strcmp(a->name.c_str(), b->name.c_str()) < 0;\n\t\t}\n\t};\n\n\tstruct sort_by_id_str {\n\t\tbool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {\n\t\t\treturn strcmp(a.c_str(), b.c_str()) < 0;\n\t\t}\n\t};\n\n\tstatic inline std::string encode_filename(const std::string &filename)\n\t{\n\t\tstd::stringstream val;\n\t\tif (!std::any_of(filename.begin(), filename.end(), [](char c) {\n\t\t\treturn static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126;\n\t\t})) return filename;\n\t\tfor (unsigned char const c : filename) {\n\t\t\tif (c < 33 || c > 126)\n\t\t\t\tval << stringf(\"$%02x\", c);\n\t\t\telse\n\t\t\t\tval << c;\n\t\t}\n\t\treturn val.str();\n\t}\n\n\t// see calc.cc for the implementation of this functions\n\tRTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shift (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_shiftx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_eqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_nex (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_buf (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\tRTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);\n\n\tRTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\tRTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\tRTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\tRTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\n\tRTLIL::Const const_bweqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2);\n\tRTLIL::Const const_bwmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);\n\n\n\t// This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().\n\t// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.\n\n\ttemplate<typename T>\n\tstruct ObjIterator {\n\t\tusing iterator_category = std::forward_iterator_tag;\n\t\tusing value_type = T;\n\t\tusing difference_type = ptrdiff_t;\n\t\tusing pointer = T*;\n\t\tusing reference = T&;\n\t\ttypename dict<RTLIL::IdString, T>::iterator it;\n\t\tdict<RTLIL::IdString, T> *list_p;\n\t\tint *refcount_p;\n\n\t\tObjIterator() : list_p(nullptr), refcount_p(nullptr) {\n\t\t}\n\n\t\tObjIterator(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) {\n\t\t\tif (list_p->empty()) {\n\t\t\t\tthis->list_p = nullptr;\n\t\t\t\tthis->refcount_p = nullptr;\n\t\t\t} else {\n\t\t\t\tit = list_p->begin();\n\t\t\t\t(*refcount_p)++;\n\t\t\t}\n\t\t}\n\n\t\tObjIterator(const RTLIL::ObjIterator<T> &other) {\n\t\t\tit = other.it;\n\t\t\tlist_p = other.list_p;\n\t\t\trefcount_p = other.refcount_p;\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)++;\n\t\t}\n\n\t\tObjIterator &operator=(const RTLIL::ObjIterator<T> &other) {\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)--;\n\t\t\tit = other.it;\n\t\t\tlist_p = other.list_p;\n\t\t\trefcount_p = other.refcount_p;\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)++;\n\t\t\treturn *this;\n\t\t}\n\n\t\t~ObjIterator() {\n\t\t\tif (refcount_p)\n\t\t\t\t(*refcount_p)--;\n\t\t}\n\n\t\tinline T operator*() const {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\treturn it->second;\n\t\t}\n\n\t\tinline bool operator!=(const RTLIL::ObjIterator<T> &other) const {\n\t\t\tif (list_p == nullptr || other.list_p == nullptr)\n\t\t\t\treturn list_p != other.list_p;\n\t\t\treturn it != other.it;\n\t\t}\n\n\n\t\tinline bool operator==(const RTLIL::ObjIterator<T> &other) const {\n\t\t\treturn !(*this != other);\n\t\t}\n\n\t\tinline ObjIterator<T>& operator++() {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tif (++it == list_p->end()) {\n\t\t\t\t(*refcount_p)--;\n\t\t\t\tlist_p = nullptr;\n\t\t\t\trefcount_p = nullptr;\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\t\tinline ObjIterator<T>& operator+=(int amt) {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tit += amt;\n\t\t\tif (it == list_p->end()) {\n\t\t\t\t(*refcount_p)--;\n\t\t\t\tlist_p = nullptr;\n\t\t\t\trefcount_p = nullptr;\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\n\t\tinline ObjIterator<T> operator+(int amt) {\n\t\t\tlog_assert(list_p != nullptr);\n\t\t\tObjIterator<T> new_obj(*this);\n\t\t\tnew_obj.it += amt;\n\t\t\tif (new_obj.it == list_p->end()) {\n\t\t\t\t(*(new_obj.refcount_p))--;\n\t\t\t\tnew_obj.list_p = nullptr;\n\t\t\t\tnew_obj.refcount_p = nullptr;\n\t\t\t}\n\t\t\treturn new_obj;\n\t\t}\n\n\t\tinline const ObjIterator<T> operator++(int) {\n\t\t\tObjIterator<T> result(*this);\n\t\t\t++(*this);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<typename T>\n\tstruct ObjRange\n\t{\n\t\tdict<RTLIL::IdString, T> *list_p;\n\t\tint *refcount_p;\n\n\t\tObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }\n\t\tRTLIL::ObjIterator<T> begin() { return RTLIL::ObjIterator<T>(list_p, refcount_p); }\n\t\tRTLIL::ObjIterator<T> end() { return RTLIL::ObjIterator<T>(); }\n\n\t\tsize_t size() const {\n\t\t\treturn list_p->size();\n\t\t}\n\n\t\toperator pool<T>() const {\n\t\t\tpool<T> result;\n\t\t\tfor (auto &it : *list_p)\n\t\t\t\tresult.insert(it.second);\n\t\t\treturn result;\n\t\t}\n\n\t\toperator std::vector<T>() const {\n\t\t\tstd::vector<T> result;\n\t\t\tresult.reserve(list_p->size());\n\t\t\tfor (auto &it : *list_p)\n\t\t\t\tresult.push_back(it.second);\n\t\t\treturn result;\n\t\t}\n\n\t\tpool<T> to_pool() const { return *this; }\n\t\tstd::vector<T> to_vector() const { return *this; }\n\t};\n};\n\nstruct RTLIL::Const\n{\n\tshort int flags;\nprivate:\n\tfriend class KernelRtlilTest;\n\tFRIEND_TEST(KernelRtlilTest, ConstStr);\n\tusing bitvectype = std::vector<RTLIL::State>;\n\tenum class backing_tag: bool { bits, string };\n\t// Do not access the union or tag even in Const methods unless necessary\n\tmutable backing_tag tag;\n\tunion {\n\t\tmutable bitvectype bits_;\n\t\tmutable std::string str_;\n\t};\n\n\t// Use these private utilities instead\n\tbool is_bits() const { return tag == backing_tag::bits; }\n\tbool is_str() const { return tag == backing_tag::string; }\n\n\tbitvectype* get_if_bits() const { return is_bits() ? &bits_ : NULL; }\n\tstd::string* get_if_str() const { return is_str() ? &str_ : NULL; }\n\n\tbitvectype& get_bits() const;\n\tstd::string& get_str() const;\npublic:\n\tConst() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector<RTLIL::State>()) {}\n\tConst(const std::string &str);\n\tConst(long long val, int width = 32);\n\tConst(RTLIL::State bit, int width = 1);\n\tConst(const std::vector<RTLIL::State> &bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(bits) {}\n\tConst(const std::vector<bool> &bits);\n\tConst(const RTLIL::Const &other);\n\tConst(RTLIL::Const &&other);\n\tRTLIL::Const &operator =(const RTLIL::Const &other);\n\t~Const();\n\n\tbool operator <(const RTLIL::Const &other) const;\n\tbool operator ==(const RTLIL::Const &other) const;\n\tbool operator !=(const RTLIL::Const &other) const;\n\n\tstd::vector<RTLIL::State>& bits();\n\tbool as_bool() const;\n\n\t// Convert the constant value to a C++ int.\n\t// NOTE: If the constant is too wide to fit in int (32 bits) this will\n\t// truncate any higher bits, potentially over/underflowing. Consider using\n\t// try_as_int, as_int_saturating, or guarding behind convertible_to_int\n\t// instead.\n\tint as_int(bool is_signed = false) const;\n\n\t// Returns true iff the constant can be converted to an int without\n\t// over/underflow.\n\tbool convertible_to_int(bool is_signed = false) const;\n\n\t// Returns the constant's value as an int if it can be represented without\n\t// over/underflow, or std::nullopt otherwise.\n\tstd::optional<int> try_as_int(bool is_signed = false) const;\n\n\t// Returns the constant's value as an int if it can be represented without\n\t// over/underflow, otherwise the max/min value for int depending on the sign.\n\tint as_int_saturating(bool is_signed = false) const;\n\n\tstd::string as_string(const char* any = \"-\") const;\n\tstatic Const from_string(const std::string &str);\n\tstd::vector<RTLIL::State> to_bits() const;\n\n\tstd::string decode_string() const;\n\tint size() const;\n\tbool empty() const;\n\tvoid bitvectorize() const;\n\n\tvoid append(const RTLIL::Const &other);\n\n\tclass const_iterator {\n\tprivate:\n\t\tconst Const& parent;\n\t\tsize_t idx;\n\n\tpublic:\n\t\tusing iterator_category = std::input_iterator_tag;\n\t\tusing value_type = State;\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing pointer = const State*;\n\t\tusing reference = const State&;\n\n\t\tconst_iterator(const Const& c, size_t i) : parent(c), idx(i) {}\n\n\t\tState operator*() const;\n\n\t\tconst_iterator& operator++() { ++idx; return *this; }\n\t\tconst_iterator& operator--() { --idx; return *this; }\n\t\tconst_iterator& operator++(int) { ++idx; return *this; }\n\t\tconst_iterator& operator--(int) { --idx; return *this; }\n\t\tconst_iterator& operator+=(int i) { idx += i; return *this; }\n\n\t\tconst_iterator operator+(int add) {\n\t\t\treturn const_iterator(parent, idx + add);\n\t\t}\n\t\tconst_iterator operator-(int sub) {\n\t\t\treturn const_iterator(parent, idx - sub);\n\t\t}\n\t\tint operator-(const const_iterator& other) {\n\t\t\treturn idx - other.idx;\n\t\t}\n\n\t\tbool operator==(const const_iterator& other) const {\n\t\t\treturn idx == other.idx;\n\t\t}\n\n\t\tbool operator!=(const const_iterator& other) const {\n\t\t\treturn !(*this == other);\n\t\t}\n\t};\n\n\tconst_iterator begin() const {\n\t\treturn const_iterator(*this, 0);\n\t}\n\tconst_iterator end() const {\n\t\treturn const_iterator(*this, size());\n\t}\n\tState back() const {\n\t\treturn *(end() - 1);\n\t}\n\tState front() const {\n\t\treturn *begin();\n\t}\n\tState at(size_t i) const {\n\t\treturn *const_iterator(*this, i);\n\t}\n\tState operator[](size_t i) const {\n\t\treturn *const_iterator(*this, i);\n\t}\n\n\tbool is_fully_zero() const;\n\tbool is_fully_ones() const;\n\tbool is_fully_def() const;\n\tbool is_fully_undef() const;\n\tbool is_fully_undef_x_only() const;\n\tbool is_onehot(int *pos = nullptr) const;\n\n\tRTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const;\n\n\t// find the MSB without redundant leading bits\n\tint get_min_size(bool is_signed) const;\n\n\t// compress representation to the minimum required bits\n\tvoid compress(bool is_signed = false);\n\n\tstd::optional<int> as_int_compress(bool is_signed) const;\n\n\tvoid extu(int width) {\n\t\tbits().resize(width, RTLIL::State::S0);\n\t}\n\n\tvoid exts(int width) {\n\t\tbitvectype& bv = bits();\n\t\tbv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());\n\t}\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\th.eat(size());\n\t\tfor (auto b : *this)\n\t\t\th.eat(b);\n\t\treturn h;\n\t}\n};\n\nstruct RTLIL::AttrObject\n{\n\tdict<RTLIL::IdString, RTLIL::Const> attributes;\n\n\tbool has_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_bool_attribute(const RTLIL::IdString &id, bool value=true);\n\tbool get_bool_attribute(const RTLIL::IdString &id) const;\n\n\t[[deprecated(\"Use Module::get_blackbox_attribute() instead.\")]]\n\tbool get_blackbox_attribute(bool ignore_wb=false) const {\n\t\treturn get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));\n\t}\n\n\tvoid set_string_attribute(const RTLIL::IdString& id, string value);\n\tstring get_string_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);\n\tvoid add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);\n\tpool<string> get_strpool_attribute(const RTLIL::IdString &id) const;\n\n\tvoid set_src_attribute(const std::string &src) {\n\t\tset_string_attribute(ID::src, src);\n\t}\n\tstd::string get_src_attribute() const {\n\t\treturn get_string_attribute(ID::src);\n\t}\n\n\tvoid set_hdlname_attribute(const vector<string> &hierarchy);\n\tvector<string> get_hdlname_attribute() const;\n\n\tvoid set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data);\n\tvector<int> get_intvec_attribute(const RTLIL::IdString &id) const;\n};\n\nstruct RTLIL::NamedObject : public RTLIL::AttrObject\n{\n\tRTLIL::IdString name;\n};\n\nstruct RTLIL::SigChunk\n{\n\tRTLIL::Wire *wire;\n\tstd::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0\n\tint width, offset;\n\n\tSigChunk() : wire(nullptr), width(0), offset(0) {}\n\tSigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.to_bits()), width(GetSize(data)), offset(0) {}\n\tSigChunk(RTLIL::Const &&value) : wire(nullptr), data(value.to_bits()), width(GetSize(data)), offset(0) {}\n\tSigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {}\n\tSigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {}\n\tSigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {}\n\tSigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {}\n\tSigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {}\n\tSigChunk(const RTLIL::SigBit &bit);\n\n\tRTLIL::SigChunk extract(int offset, int length) const;\n\tRTLIL::SigBit operator[](int offset) const;\n\tinline int size() const { return width; }\n\tinline bool is_wire() const { return wire != NULL; }\n\n\tbool operator <(const RTLIL::SigChunk &other) const;\n\tbool operator ==(const RTLIL::SigChunk &other) const;\n\tbool operator !=(const RTLIL::SigChunk &other) const;\n};\n\nstruct RTLIL::SigBit\n{\n\tRTLIL::Wire *wire;\n\tunion {\n\t\tRTLIL::State data; // used if wire == NULL\n\t\tint offset; // used if wire != NULL\n\t};\n\n\tSigBit();\n\tSigBit(RTLIL::State bit);\n\texplicit SigBit(bool bit);\n\tSigBit(RTLIL::Wire *wire);\n\tSigBit(RTLIL::Wire *wire, int offset);\n\tSigBit(const RTLIL::SigChunk &chunk);\n\tSigBit(const RTLIL::SigChunk &chunk, int index);\n\tSigBit(const RTLIL::SigSpec &sig);\n\tSigBit(const RTLIL::SigBit &sigbit) = default;\n\tRTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;\n\n\tinline bool is_wire() const { return wire != NULL; }\n\n\tbool operator <(const RTLIL::SigBit &other) const;\n\tbool operator ==(const RTLIL::SigBit &other) const;\n\tbool operator !=(const RTLIL::SigBit &other) const;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const;\n\t[[nodiscard]] Hasher hash_top() const;\n};\n\nnamespace hashlib {\n\ttemplate <>\n\tstruct hash_ops<RTLIL::SigBit> {\n\t\tstatic inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) {\n\t\t\treturn a == b;\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash(const RTLIL::SigBit sb) {\n\t\t\treturn sb.hash_top();\n\t\t}\n\t\t[[nodiscard]] static inline Hasher hash_into(const RTLIL::SigBit sb, Hasher h) {\n\t\t\treturn sb.hash_into(h);\n\t\t}\n\t};\n};\n\nstruct RTLIL::SigSpecIterator\n{\n\ttypedef std::input_iterator_tag iterator_category;\n\ttypedef RTLIL::SigBit value_type;\n\ttypedef ptrdiff_t difference_type;\n\ttypedef RTLIL::SigBit* pointer;\n\ttypedef RTLIL::SigBit& reference;\n\n\tRTLIL::SigSpec *sig_p;\n\tint index;\n\n\tinline RTLIL::SigBit &operator*() const;\n\tinline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }\n\tinline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }\n\tinline void operator++() { index++; }\n};\n\nstruct RTLIL::SigSpecConstIterator\n{\n\ttypedef std::input_iterator_tag iterator_category;\n\ttypedef RTLIL::SigBit value_type;\n\ttypedef ptrdiff_t difference_type;\n\ttypedef RTLIL::SigBit* pointer;\n\ttypedef RTLIL::SigBit& reference;\n\n\tconst RTLIL::SigSpec *sig_p;\n\tint index;\n\n\tinline const RTLIL::SigBit &operator*() const;\n\tinline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }\n\tinline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }\n\tinline void operator++() { index++; }\n};\n\nstruct RTLIL::SigSpec\n{\nprivate:\n\tint width_;\n\tHasher::hash_t hash_;\n\tstd::vector<RTLIL::SigChunk> chunks_; // LSB at index 0\n\tstd::vector<RTLIL::SigBit> bits_; // LSB at index 0\n\n\tvoid pack() const;\n\tvoid unpack() const;\n\tvoid updhash() const;\n\n\tinline bool packed() const {\n\t\treturn bits_.empty();\n\t}\n\n\tinline void inline_unpack() const {\n\t\tif (!chunks_.empty())\n\t\t\tunpack();\n\t}\n\n\t// Only used by Module::remove(const pool<Wire*> &wires)\n\t// but cannot be more specific as it isn't yet declared\n\tfriend struct RTLIL::Module;\n\npublic:\n\tSigSpec() : width_(0), hash_(0) {}\n\tSigSpec(std::initializer_list<RTLIL::SigSpec> parts);\n\n\tSigSpec(const RTLIL::Const &value);\n\tSigSpec(RTLIL::Const &&value);\n\tSigSpec(const RTLIL::SigChunk &chunk);\n\tSigSpec(RTLIL::SigChunk &&chunk);\n\tSigSpec(RTLIL::Wire *wire);\n\tSigSpec(RTLIL::Wire *wire, int offset, int width = 1);\n\tSigSpec(const std::string &str);\n\tSigSpec(int val, int width = 32);\n\tSigSpec(RTLIL::State bit, int width = 1);\n\tSigSpec(const RTLIL::SigBit &bit, int width = 1);\n\tSigSpec(const std::vector<RTLIL::SigChunk> &chunks);\n\tSigSpec(const std::vector<RTLIL::SigBit> &bits);\n\tSigSpec(const pool<RTLIL::SigBit> &bits);\n\tSigSpec(const std::set<RTLIL::SigBit> &bits);\n\texplicit SigSpec(bool bit);\n\n\tinline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }\n\tinline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }\n\n\tinline int size() const { return width_; }\n\tinline bool empty() const { return width_ == 0; }\n\n\tinline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }\n\tinline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }\n\n\tinline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }\n\tinline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }\n\n\tinline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }\n\tinline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }\n\n\tvoid sort();\n\tvoid sort_and_unify();\n\n\tvoid replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);\n\tvoid replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;\n\n\tvoid replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules);\n\tvoid replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;\n\n\tvoid replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);\n\tvoid replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;\n\n\tvoid replace(int offset, const RTLIL::SigSpec &with);\n\n\tvoid remove(const RTLIL::SigSpec &pattern);\n\tvoid remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;\n\tvoid remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);\n\n\tvoid remove(const pool<RTLIL::SigBit> &pattern);\n\tvoid remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;\n\tvoid remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);\n\tvoid remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);\n\tvoid remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *other);\n\n\tvoid remove(int offset, int length = 1);\n\tvoid remove_const();\n\n\tRTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;\n\tRTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;\n\tRTLIL::SigSpec extract(int offset, int length = 1) const;\n\tRTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }\n\n\tRTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; };\n\tRTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; };\n\n\tvoid append(const RTLIL::SigSpec &signal);\n\tinline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); }\n\tinline void append(const RTLIL::SigChunk &chunk) { append(RTLIL::SigSpec(chunk)); }\n\tinline void append(const RTLIL::Const &const_) { append(RTLIL::SigSpec(const_)); }\n\n\tvoid append(const RTLIL::SigBit &bit);\n\tinline void append(RTLIL::State state) { append(RTLIL::SigBit(state)); }\n\tinline void append(bool bool_) { append(RTLIL::SigBit(bool_)); }\n\n\tvoid extend_u0(int width, bool is_signed = false);\n\n\tRTLIL::SigSpec repeat(int num) const;\n\n\tvoid reverse() { inline_unpack(); std::reverse(bits_.begin(), bits_.end()); }\n\n\tbool operator <(const RTLIL::SigSpec &other) const;\n\tbool operator ==(const RTLIL::SigSpec &other) const;\n\tinline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }\n\n\tbool is_wire() const;\n\tbool is_chunk() const;\n\tinline bool is_bit() const { return width_ == 1; }\n\n\tbool is_fully_const() const;\n\tbool is_fully_zero() const;\n\tbool is_fully_ones() const;\n\tbool is_fully_def() const;\n\tbool is_fully_undef() const;\n\tbool has_const() const;\n\tbool has_marked_bits() const;\n\tbool is_onehot(int *pos = nullptr) const;\n\n\tbool as_bool() const;\n\n\t// Convert the SigSpec to a C++ int, assuming all bits are constant.\n\t// NOTE: If the value is too wide to fit in int (32 bits) this will\n\t// truncate any higher bits, potentially over/underflowing. Consider using\n\t// try_as_int, as_int_saturating, or guarding behind convertible_to_int\n\t// instead.\n\tint as_int(bool is_signed = false) const;\n\n\t// Returns true iff the SigSpec is constant and can be converted to an int\n\t// without over/underflow.\n\tbool convertible_to_int(bool is_signed = false) const;\n\n\t// Returns the SigSpec's value as an int if it is a constant and can be\n\t// represented without over/underflow, or std::nullopt otherwise.\n\tstd::optional<int> try_as_int(bool is_signed = false) const;\n\n\t// Returns an all constant SigSpec's value as an int if it can be represented\n\t// without over/underflow, otherwise the max/min value for int depending on\n\t// the sign.\n\tint as_int_saturating(bool is_signed = false) const;\n\n\tstd::string as_string() const;\n\tRTLIL::Const as_const() const;\n\tRTLIL::Wire *as_wire() const;\n\tRTLIL::SigChunk as_chunk() const;\n\tRTLIL::SigBit as_bit() const;\n\n\tbool match(const char* pattern) const;\n\n\tstd::set<RTLIL::SigBit> to_sigbit_set() const;\n\tpool<RTLIL::SigBit> to_sigbit_pool() const;\n\tstd::vector<RTLIL::SigBit> to_sigbit_vector() const;\n\tstd::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;\n\tdict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;\n\n\tstatic bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);\n\tstatic bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);\n\tstatic bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);\n\n\toperator std::vector<RTLIL::SigChunk>() const { return chunks(); }\n\toperator std::vector<RTLIL::SigBit>() const { return bits(); }\n\tconst RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }\n\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }\n\n#ifndef NDEBUG\n\tvoid check(Module *mod = nullptr) const;\n#else\n\tvoid check(Module *mod = nullptr) const { (void)mod; }\n#endif\n};\n\nstruct RTLIL::Selection\n{\n\t// selection includes boxed modules\n\tbool selects_boxes;\n\t// selection covers full design, including boxed modules\n\tbool complete_selection;\n\t// selection covers full design, not including boxed modules\n\tbool full_selection;\n\tpool<RTLIL::IdString> selected_modules;\n\tdict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;\n\tRTLIL::Design *current_design;\n\n\t// create a new selection\n\tSelection(\n\t\t// should the selection cover the full design\n\t\tbool full = true,\n\t\t// should the selection include boxed modules\n\t\tbool boxes = false,\n\t\t// the design to select from\n\t\tRTLIL::Design *design = nullptr\n\t) :\n\t\tselects_boxes(boxes), complete_selection(full && boxes), full_selection(full && !boxes), current_design(design) { }\n\n\t// checks if the given module exists in the current design and is a\n\t// boxed module, warning the user if the current design is not set\n\tbool boxed_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is included in this selection\n\tbool selected_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is wholly included in this selection,\n\t// i.e. not partially selected\n\tbool selected_whole_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given member from the given module is included in this\n\t// selection\n\tbool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;\n\n\t// optimizes this selection for the given design by:\n\t// - removing non-existent modules and members, any boxed modules and\n\t// their members (if selection does not include boxes), and any\n\t// partially selected modules with no selected members;\n\t// - marking partially selected modules as wholly selected if all\n\t// members of that module are selected; and\n\t// - marking selection as a complete_selection if all modules in the\n\t// given design are selected, or a full_selection if it does not\n\t// include boxes.\n\tvoid optimize(RTLIL::Design *design);\n\n\t// checks if selection covers full design (may or may not include\n\t// boxed-modules)\n\tbool selects_all() const {\n\t\treturn full_selection || complete_selection;\n\t}\n\n\t// add whole module to this selection\n\ttemplate<typename T1> void select(T1 *module) {\n\t\tif (!selects_all() && selected_modules.count(module->name) == 0) {\n\t\t\tselected_modules.insert(module->name);\n\t\t\tselected_members.erase(module->name);\n\t\t\tif (module->get_blackbox_attribute())\n\t\t\t\tselects_boxes = true;\n\t\t}\n\t}\n\n\t// add member of module to this selection\n\ttemplate<typename T1, typename T2> void select(T1 *module, T2 *member) {\n\t\tif (!selects_all() && selected_modules.count(module->name) == 0) {\n\t\t\tselected_members[module->name].insert(member->name);\n\t\t\tif (module->get_blackbox_attribute())\n\t\t\t\tselects_boxes = true;\n\t\t}\n\t}\n\n\t// checks if selection is empty\n\tbool empty() const {\n\t\treturn !selects_all() && selected_modules.empty() && selected_members.empty();\n\t}\n\n\t// clear this selection, leaving it empty\n\tvoid clear();\n\n\t// create a new selection which is empty\n\tstatic Selection EmptySelection(RTLIL::Design *design = nullptr) { return Selection(false, false, design); };\n\n\t// create a new selection with all non-boxed modules\n\tstatic Selection FullSelection(RTLIL::Design *design = nullptr) { return Selection(true, false, design); };\n\n\t// create a new selection with all modules, including boxes\n\tstatic Selection CompleteSelection(RTLIL::Design *design = nullptr) { return Selection(true, true, design); };\n};\n\nstruct RTLIL::Monitor\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tMonitor() {\n\t\tstatic unsigned int hashidx_count = 123456789;\n\t\thashidx_count = mkhash_xorshift(hashidx_count);\n\t\thashidx_ = hashidx_count;\n\t}\n\n\tvirtual ~Monitor() { }\n\tvirtual void notify_module_add(RTLIL::Module*) { }\n\tvirtual void notify_module_del(RTLIL::Module*) { }\n\tvirtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { }\n\tvirtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { }\n\tvirtual void notify_connect(RTLIL::Module*, const std::vector<RTLIL::SigSig>&) { }\n\tvirtual void notify_blackout(RTLIL::Module*) { }\n};\n\n// Forward declaration; defined in preproc.h.\nstruct define_map_t;\n\nstruct RTLIL::Design\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tpool<RTLIL::Monitor*> monitors;\n\tdict<std::string, std::string> scratchpad;\n\n\tbool flagBufferedNormalized = false;\n\tvoid bufNormalize(bool enable=true);\n\n\tint refcount_modules_;\n\tdict<RTLIL::IdString, RTLIL::Module*> modules_;\n\tstd::vector<RTLIL::Binding*> bindings_;\n\n\tstd::vector<std::unique_ptr<AST::AstNode>> verilog_packages, verilog_globals;\n\tstd::unique_ptr<define_map_t> verilog_defines;\n\n\tstd::vector<RTLIL::Selection> selection_stack;\n\tdict<RTLIL::IdString, RTLIL::Selection> selection_vars;\n\tstd::string selected_active_module;\n\n\tDesign();\n\t~Design();\n\n\tRTLIL::ObjRange<RTLIL::Module*> modules();\n\tRTLIL::Module *module(const RTLIL::IdString &name);\n\tconst RTLIL::Module *module(const RTLIL::IdString &name) const;\n\tRTLIL::Module *top_module() const;\n\n\tbool has(const RTLIL::IdString &id) const {\n\t\treturn modules_.count(id) != 0;\n\t}\n\n\tvoid add(RTLIL::Module *module);\n\tvoid add(RTLIL::Binding *binding);\n\n\tRTLIL::Module *addModule(RTLIL::IdString name);\n\tvoid remove(RTLIL::Module *module);\n\tvoid rename(RTLIL::Module *module, RTLIL::IdString new_name);\n\n\tvoid scratchpad_unset(const std::string &varname);\n\n\tvoid scratchpad_set_int(const std::string &varname, int value);\n\tvoid scratchpad_set_bool(const std::string &varname, bool value);\n\tvoid scratchpad_set_string(const std::string &varname, std::string value);\n\n\tint scratchpad_get_int(const std::string &varname, int default_value = 0) const;\n\tbool scratchpad_get_bool(const std::string &varname, bool default_value = false) const;\n\tstd::string scratchpad_get_string(const std::string &varname, const std::string &default_value = std::string()) const;\n\n\tvoid sort();\n\tvoid sort_modules();\n\tvoid check();\n\tvoid optimize();\n\n\t// checks if the given module is included in the current selection\n\tbool selected_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given module is wholly included in the current\n\t// selection, i.e. not partially selected\n\tbool selected_whole_module(const RTLIL::IdString &mod_name) const;\n\n\t// checks if the given member from the given module is included in the\n\t// current selection\n\tbool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;\n\n\t// checks if the given module is included in the current selection\n\tbool selected_module(RTLIL::Module *mod) const;\n\n\t// checks if the given module is wholly included in the current\n\t// selection, i.e. not partially selected\n\tbool selected_whole_module(RTLIL::Module *mod) const;\n\n\t// push the given selection to the selection stack\n\tvoid push_selection(RTLIL::Selection sel);\n\t// push a new selection to the selection stack, with nothing selected\n\tvoid push_empty_selection();\n\t// push a new selection to the selection stack, with all non-boxed\n\t// modules selected\n\tvoid push_full_selection();\n\t// push a new selection to the selection stack, with all modules\n\t// selected including boxes\n\tvoid push_complete_selection();\n\t// pop the current selection from the stack, returning to a full\n\t// selection (no boxes) if the stack is empty\n\tvoid pop_selection();\n\n\t// get the current selection\n\tRTLIL::Selection &selection() {\n\t\treturn selection_stack.back();\n\t}\n\n\t// get the current selection\n\tconst RTLIL::Selection &selection() const {\n\t\treturn selection_stack.back();\n\t}\n\n\t// is the current selection a full selection (no boxes)\n\tbool full_selection() const {\n\t\treturn selection().full_selection;\n\t}\n\n\t// is the given module in the current selection\n\ttemplate<typename T1> bool selected(T1 *module) const {\n\t\treturn selected_module(module->name);\n\t}\n\n\t// is the given member of the given module in the current selection\n\ttemplate<typename T1, typename T2> bool selected(T1 *module, T2 *member) const {\n\t\treturn selected_member(module->name, member->name);\n\t}\n\n\t// add whole module to the current selection\n\ttemplate<typename T1> void select(T1 *module) {\n\t\tRTLIL::Selection &sel = selection();\n\t\tsel.select(module);\n\t}\n\n\t// add member of module to the current selection\n\ttemplate<typename T1, typename T2> void select(T1 *module, T2 *member) {\n\t\tRTLIL::Selection &sel = selection();\n\t\tsel.select(module, member);\n\t}\n\n\n\t// returns all selected modules\n\tstd::vector<RTLIL::Module*> selected_modules(\n\t\t// controls if partially selected modules are included\n\t\tRTLIL::SelectPartials partials = SELECT_ALL,\n\t\t// controls if boxed modules are included\n\t\tRTLIL::SelectBoxes boxes = SB_UNBOXED_WARN\n\t) const;\n\n\t// returns all selected modules, and may include boxes\n\tstd::vector<RTLIL::Module*> all_selected_modules() const { return selected_modules(SELECT_ALL, SB_ALL); }\n\t// returns all selected unboxed modules, silently ignoring any boxed\n\t// modules in the selection\n\tstd::vector<RTLIL::Module*> selected_unboxed_modules() const { return selected_modules(SELECT_ALL, SB_UNBOXED_ONLY); }\n\t// returns all selected unboxed modules, warning the user if any boxed\n\t// modules have been ignored\n\tstd::vector<RTLIL::Module*> selected_unboxed_modules_warn() const { return selected_modules(SELECT_ALL, SB_UNBOXED_WARN); }\n\n\t[[deprecated(\"Use select_unboxed_whole_modules() to maintain prior behaviour, or consider one of the other selected whole module helpers.\")]]\n\tstd::vector<RTLIL::Module*> selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_WARN); }\n\t// returns all selected whole modules, silently ignoring partially\n\t// selected modules, and may include boxes\n\tstd::vector<RTLIL::Module*> all_selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_ALL); }\n\t// returns all selected whole modules, warning the user if any partially\n\t// selected or boxed modules have been ignored; optionally includes\n\t// selected whole modules with the 'whitebox' attribute\n\tstd::vector<RTLIL::Module*> selected_whole_modules_warn(\n\t\t// should whole modules with the 'whitebox' attribute be\n\t\t// included\n\t\tbool include_wb = false\n\t) const { return selected_modules(SELECT_WHOLE_WARN, include_wb ? SB_EXCL_BB_WARN : SB_UNBOXED_WARN); }\n\t// returns all selected unboxed whole modules, silently ignoring\n\t// partially selected or boxed modules\n\tstd::vector<RTLIL::Module*> selected_unboxed_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_ONLY); }\n\t// returns all selected unboxed whole modules, warning the user if any\n\t// partially selected or boxed modules have been ignored\n\tstd::vector<RTLIL::Module*> selected_unboxed_whole_modules_warn() const { return selected_modules(SELECT_WHOLE_WARN, SB_UNBOXED_WARN); }\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);\n#endif\n};\n\nstruct RTLIL::Module : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\tvoid add(RTLIL::Wire *wire);\n\tvoid add(RTLIL::Cell *cell);\n\tvoid add(RTLIL::Process *process);\n\npublic:\n\tRTLIL::Design *design;\n\tpool<RTLIL::Monitor*> monitors;\n\n\tint refcount_wires_;\n\tint refcount_cells_;\n\n\tdict<RTLIL::IdString, RTLIL::Wire*> wires_;\n\tdict<RTLIL::IdString, RTLIL::Cell*> cells_;\n\n\tstd::vector<RTLIL::SigSig> connections_;\n\tstd::vector<RTLIL::Binding*> bindings_;\n\n\tidict<RTLIL::IdString> avail_parameters;\n\tdict<RTLIL::IdString, RTLIL::Const> parameter_default_values;\n\tdict<RTLIL::IdString, RTLIL::Memory*> memories;\n\tdict<RTLIL::IdString, RTLIL::Process*> processes;\n\n\tModule();\n\tvirtual ~Module();\n\tvirtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail = false);\n\tvirtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);\n\tvirtual size_t count_id(const RTLIL::IdString& id);\n\tvirtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);\n\tvirtual bool reprocess_if_necessary(RTLIL::Design *design);\n\n\tvirtual void sort();\n\tvirtual void check();\n\tvirtual void optimize();\n\tvirtual void makeblackbox();\n\n\tbool get_blackbox_attribute(bool ignore_wb=false) const {\n\t\treturn get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));\n\t}\n\n\tvoid connect(const RTLIL::SigSig &conn);\n\tvoid connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);\n\tvoid new_connections(const std::vector<RTLIL::SigSig> &new_conn);\n\tconst std::vector<RTLIL::SigSig> &connections() const;\n\n\tstd::vector<RTLIL::IdString> ports;\n\tvoid fixup_ports();\n\n\tpool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;\n\tvoid bufNormalize();\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tvoid cloneInto(RTLIL::Module *new_mod) const;\n\tvirtual RTLIL::Module *clone() const;\n\n\tbool has_memories() const;\n\tbool has_processes() const;\n\n\tbool has_memories_warn() const;\n\tbool has_processes_warn() const;\n\n\tbool is_selected() const;\n\tbool is_selected_whole() const;\n\n\tstd::vector<RTLIL::Wire*> selected_wires() const;\n\tstd::vector<RTLIL::Cell*> selected_cells() const;\n\tstd::vector<RTLIL::Memory*> selected_memories() const;\n\tstd::vector<RTLIL::Process*> selected_processes() const;\n\tstd::vector<RTLIL::NamedObject*> selected_members() const;\n\n\ttemplate<typename T> bool selected(T *member) const {\n\t\treturn design->selected_member(name, member->name);\n\t}\n\n\tRTLIL::Wire* wire(const RTLIL::IdString &id) {\n\t\tauto it = wires_.find(id);\n\t\treturn it == wires_.end() ? nullptr : it->second;\n\t}\n\tRTLIL::Cell* cell(const RTLIL::IdString &id) {\n\t\tauto it = cells_.find(id);\n\t\treturn it == cells_.end() ? nullptr : it->second;\n\t}\n\n\tconst RTLIL::Wire* wire(const RTLIL::IdString &id) const{\n\t\tauto it = wires_.find(id);\n\t\treturn it == wires_.end() ? nullptr : it->second;\n\t}\n\tconst RTLIL::Cell* cell(const RTLIL::IdString &id) const {\n\t\tauto it = cells_.find(id);\n\t\treturn it == cells_.end() ? nullptr : it->second;\n\t}\n\n\tRTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }\n\tRTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }\n\n\tvoid add(RTLIL::Binding *binding);\n\n\t// Removing wires is expensive. If you have to remove wires, remove them all at once.\n\tvoid remove(const pool<RTLIL::Wire*> &wires);\n\tvoid remove(RTLIL::Cell *cell);\n\tvoid remove(RTLIL::Process *process);\n\n\tvoid rename(RTLIL::Wire *wire, RTLIL::IdString new_name);\n\tvoid rename(RTLIL::Cell *cell, RTLIL::IdString new_name);\n\tvoid rename(RTLIL::IdString old_name, RTLIL::IdString new_name);\n\n\tvoid swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2);\n\tvoid swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2);\n\n\tRTLIL::IdString uniquify(RTLIL::IdString name);\n\tRTLIL::IdString uniquify(RTLIL::IdString name, int &index);\n\n\tRTLIL::Wire *addWire(RTLIL::IdString name, int width = 1);\n\tRTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other);\n\n\tRTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type);\n\tRTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other);\n\n\tRTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other);\n\n\tRTLIL::Process *addProcess(RTLIL::IdString name);\n\tRTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other);\n\n\t// The add* methods create a cell and return the created cell. All signals must exist in advance.\n\n\tRTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addShl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addShiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addLt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addEq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addEqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addNex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addGe (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addGt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\t// truncating division\n\tRTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\t// truncating modulo\n\tRTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::Cell* addLogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::Cell* addMux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = \"\");\n\tRTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = \"\");\n\tRTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addLive (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addFair (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addCover (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = \"\");\n\tRTLIL::Cell* addEquiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSr (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addFf (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\tRTLIL::Cell* addDff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsre (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdff (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffe (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffce (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const srst_value, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\n\tRTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addXorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addXnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addMuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addNmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addAoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\tRTLIL::Cell* addOai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const RTLIL::SigBit &sig_y, const std::string &src = \"\");\n\n\tRTLIL::Cell* addSrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tconst RTLIL::SigSpec &sig_q, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addFfGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\tRTLIL::Cell* addDffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDffsreGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool clk_polarity = true, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tconst RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAldffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_aload, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tconst RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffeGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addSdffceGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_clk, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_srst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addAdlatchGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q,\n\t\t\tbool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const std::string &src = \"\");\n\tRTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,\n\t\t\tRTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = \"\");\n\n\tRTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = \"\");\n\n\t// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.\n\n\tRTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Xor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec ReduceAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceXor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Shl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sshl (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sshr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shift (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Lt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Le (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Eq (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Ne (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Ge (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Gt (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\t// truncating division\n\tRTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\t// truncating modulo\n\tRTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\tRTLIL::SigSpec LogicOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\tRTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = \"\");\n\tRTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = \"\");\n\n\tRTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = \"\");\n\tRTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = \"\");\n\tRTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit NandGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit OrGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit NorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit XorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit XnorGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit OrnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = \"\");\n\tRTLIL::SigBit MuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = \"\");\n\tRTLIL::SigBit NmuxGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = \"\");\n\tRTLIL::SigBit Aoi3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = \"\");\n\tRTLIL::SigBit Oai3Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = \"\");\n\tRTLIL::SigBit Aoi4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = \"\");\n\tRTLIL::SigBit Oai4Gate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const RTLIL::SigBit &sig_d, const std::string &src = \"\");\n\n\tRTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Anyseq (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = \"\");\n\tRTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = \"\");\n\n\tRTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = \"\");\n\tRTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = \"\");\n\tRTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = \"\");\n\tRTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = \"\");\n\tRTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = \"\");\n\tRTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = \"\");\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);\n#endif\n};\n\nnamespace RTLIL_BACKEND {\nvoid dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);\n}\n\nstruct RTLIL::Wire : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addWire() and module->remove() to create or destroy wires\n\tfriend struct RTLIL::Module;\n\tWire();\n\t~Wire();\n\n\tfriend struct RTLIL::Design;\n\tfriend struct RTLIL::Cell;\n\tfriend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);\n\tRTLIL::Cell *driverCell_ = nullptr;\n\tRTLIL::IdString driverPort_;\n\npublic:\n\t// do not simply copy wires\n\tWire(RTLIL::Wire &other) = delete;\n\tvoid operator=(RTLIL::Wire &other) = delete;\n\n\tRTLIL::Module *module;\n\tint width, start_offset, port_id;\n\tbool port_input, port_output, upto, is_signed;\n\n\tRTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };\n\tRTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };\n\n\tint from_hdl_index(int hdl_index) {\n\t\tint zero_index = hdl_index - start_offset;\n\t\tint rtlil_index = upto ? width - 1 - zero_index : zero_index;\n\t\treturn rtlil_index >= 0 && rtlil_index < width ? rtlil_index : INT_MIN;\n\t}\n\n\tint to_hdl_index(int rtlil_index) {\n\t\tif (rtlil_index < 0 || rtlil_index >= width)\n\t\t\treturn INT_MIN;\n\t\tint zero_index = upto ? width - 1 - rtlil_index : rtlil_index;\n\t\treturn zero_index + start_offset;\n\t}\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);\n#endif\n};\n\ninline int GetSize(RTLIL::Wire *wire) {\n\treturn wire->width;\n}\n\nstruct RTLIL::Memory : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\n\tMemory();\n\n\tint width, start_offset, size;\n#ifdef WITH_PYTHON\n\t~Memory();\n\tstatic std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void);\n#endif\n};\n\nstruct RTLIL::Cell : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addCell() and module->remove() to create or destroy cells\n\tfriend struct RTLIL::Module;\n\tCell();\n\t~Cell();\n\npublic:\n\t// do not simply copy cells\n\tCell(RTLIL::Cell &other) = delete;\n\tvoid operator=(RTLIL::Cell &other) = delete;\n\n\tRTLIL::Module *module;\n\tRTLIL::IdString type;\n\tdict<RTLIL::IdString, RTLIL::SigSpec> connections_;\n\tdict<RTLIL::IdString, RTLIL::Const> parameters;\n\n\t// access cell ports\n\tbool hasPort(const RTLIL::IdString &portname) const;\n\tvoid unsetPort(const RTLIL::IdString &portname);\n\tvoid setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);\n\tconst RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const;\n\tconst dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;\n\n\t// information about cell ports\n\tbool known() const;\n\tbool input(const RTLIL::IdString &portname) const;\n\tbool output(const RTLIL::IdString &portname) const;\n\n\t// access cell parameters\n\tbool hasParam(const RTLIL::IdString ¶mname) const;\n\tvoid unsetParam(const RTLIL::IdString ¶mname);\n\tvoid setParam(const RTLIL::IdString ¶mname, RTLIL::Const value);\n\tconst RTLIL::Const &getParam(const RTLIL::IdString ¶mname) const;\n\n\tvoid sort();\n\tvoid check();\n\tvoid fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);\n\n\tbool has_keep_attr() const {\n\t\treturn get_bool_attribute(ID::keep) || (module && module->design && module->design->module(type) &&\n\t\t\t\tmodule->design->module(type)->get_bool_attribute(ID::keep));\n\t}\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\n#ifdef WITH_PYTHON\n\tstatic std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);\n#endif\n\n\tbool has_memid() const;\n\tbool is_mem_cell() const;\n};\n\nstruct RTLIL::CaseRule : public RTLIL::AttrObject\n{\n\tstd::vector<RTLIL::SigSpec> compare;\n\tstd::vector<RTLIL::SigSig> actions;\n\tstd::vector<RTLIL::SwitchRule*> switches;\n\n\t~CaseRule();\n\n\tbool empty() const;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::CaseRule *clone() const;\n};\n\nstruct RTLIL::SwitchRule : public RTLIL::AttrObject\n{\n\tRTLIL::SigSpec signal;\n\tstd::vector<RTLIL::CaseRule*> cases;\n\n\t~SwitchRule();\n\n\tbool empty() const;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::SwitchRule *clone() const;\n};\n\nstruct RTLIL::MemWriteAction : RTLIL::AttrObject\n{\n\tRTLIL::IdString memid;\n\tRTLIL::SigSpec address;\n\tRTLIL::SigSpec data;\n\tRTLIL::SigSpec enable;\n\tRTLIL::Const priority_mask;\n};\n\nstruct RTLIL::SyncRule\n{\n\tRTLIL::SyncType type;\n\tRTLIL::SigSpec signal;\n\tstd::vector<RTLIL::SigSig> actions;\n\tstd::vector<RTLIL::MemWriteAction> mem_write_actions;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::SyncRule *clone() const;\n};\n\nstruct RTLIL::Process : public RTLIL::NamedObject\n{\n\tHasher::hash_t hashidx_;\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }\n\nprotected:\n\t// use module->addProcess() and module->remove() to create or destroy processes\n\tfriend struct RTLIL::Module;\n\tProcess();\n\t~Process();\n\npublic:\n\tRTLIL::Module *module;\n\tRTLIL::CaseRule root_case;\n\tstd::vector<RTLIL::SyncRule*> syncs;\n\n\ttemplate<typename T> void rewrite_sigspecs(T &functor);\n\ttemplate<typename T> void rewrite_sigspecs2(T &functor);\n\tRTLIL::Process *clone() const;\n};\n\n\ninline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }\ninline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }\ninline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? State::S1 : State::S0) { }\ninline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }\ninline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }\ninline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }\ninline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }\n\ninline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {\n\tif (wire == other.wire)\n\t\treturn wire ? (offset < other.offset) : (data < other.data);\n\tif (wire != nullptr && other.wire != nullptr)\n\t\treturn wire->name < other.wire->name;\n\treturn (wire != nullptr) < (other.wire != nullptr);\n}\n\ninline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {\n\treturn (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));\n}\n\ninline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {\n\treturn (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));\n}\n\ninline Hasher RTLIL::SigBit::hash_into(Hasher h) const {\n\tif (wire) {\n\t\th.eat(offset);\n\t\th.eat(wire->name);\n\t\treturn h;\n\t}\n\th.eat(data);\n\treturn h;\n}\n\n\ninline Hasher RTLIL::SigBit::hash_top() const {\n\tHasher h;\n\tif (wire) {\n\t\th.force(hashlib::legacy::djb2_add(wire->name.index_, offset));\n\t\treturn h;\n\t}\n\th.force(data);\n\treturn h;\n}\n\ninline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {\n\treturn (*sig_p)[index];\n}\n\ninline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {\n\treturn (*sig_p)[index];\n}\n\ninline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {\n\tlog_assert(sig.size() == 1 && sig.chunks().size() == 1);\n\t*this = SigBit(sig.chunks().front());\n}\n\ntemplate<typename T>\nvoid RTLIL::Module::rewrite_sigspecs(T &functor)\n{\n\tfor (auto &it : cells_)\n\t\tit.second->rewrite_sigspecs(functor);\n\tfor (auto &it : processes)\n\t\tit.second->rewrite_sigspecs(functor);\n\tfor (auto &it : connections_) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Module::rewrite_sigspecs2(T &functor)\n{\n\tfor (auto &it : cells_)\n\t\tit.second->rewrite_sigspecs2(functor);\n\tfor (auto &it : processes)\n\t\tit.second->rewrite_sigspecs2(functor);\n\tfor (auto &it : connections_) {\n\t\tfunctor(it.first, it.second);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Cell::rewrite_sigspecs(T &functor) {\n\tfor (auto &it : connections_)\n\t\tfunctor(it.second);\n}\n\ntemplate<typename T>\nvoid RTLIL::Cell::rewrite_sigspecs2(T &functor) {\n\tfor (auto &it : connections_)\n\t\tfunctor(it.second);\n}\n\ntemplate<typename T>\nvoid RTLIL::CaseRule::rewrite_sigspecs(T &functor) {\n\tfor (auto &it : compare)\n\t\tfunctor(it);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n\tfor (auto it : switches)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {\n\tfor (auto &it : compare)\n\t\tfunctor(it);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first, it.second);\n\t}\n\tfor (auto it : switches)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SwitchRule::rewrite_sigspecs(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto it : cases)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto it : cases)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::SyncRule::rewrite_sigspecs(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first);\n\t\tfunctor(it.second);\n\t}\n\tfor (auto &it : mem_write_actions) {\n\t\tfunctor(it.address);\n\t\tfunctor(it.data);\n\t\tfunctor(it.enable);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::SyncRule::rewrite_sigspecs2(T &functor)\n{\n\tfunctor(signal);\n\tfor (auto &it : actions) {\n\t\tfunctor(it.first, it.second);\n\t}\n\tfor (auto &it : mem_write_actions) {\n\t\tfunctor(it.address);\n\t\tfunctor(it.data);\n\t\tfunctor(it.enable);\n\t}\n}\n\ntemplate<typename T>\nvoid RTLIL::Process::rewrite_sigspecs(T &functor)\n{\n\troot_case.rewrite_sigspecs(functor);\n\tfor (auto it : syncs)\n\t\tit->rewrite_sigspecs(functor);\n}\n\ntemplate<typename T>\nvoid RTLIL::Process::rewrite_sigspecs2(T &functor)\n{\n\troot_case.rewrite_sigspecs2(functor);\n\tfor (auto it : syncs)\n\t\tit->rewrite_sigspecs2(functor);\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
186
|
+
"satgen.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SATGEN_H\n#define SATGEN_H\n\n#include \"kernel/rtlil.h\"\n#include \"kernel/sigtools.h\"\n#include \"kernel/celltypes.h\"\n#include \"kernel/macc.h\"\n\n#include \"libs/ezsat/ezminisat.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\n// defined in kernel/register.cc\nextern struct SatSolver *yosys_satsolver_list;\nextern struct SatSolver *yosys_satsolver;\n\nstruct SatSolver\n{\n\tstring name;\n\tSatSolver *next;\n\tvirtual ezSAT *create() = 0;\n\n\tSatSolver(string name) : name(name) {\n\t\tnext = yosys_satsolver_list;\n\t\tyosys_satsolver_list = this;\n\t}\n\n\tvirtual ~SatSolver() {\n\t\tauto p = &yosys_satsolver_list;\n\t\twhile (*p) {\n\t\t\tif (*p == this)\n\t\t\t\t*p = next;\n\t\t\telse\n\t\t\t\tp = &(*p)->next;\n\t\t}\n\t\tif (yosys_satsolver == this)\n\t\t\tyosys_satsolver = yosys_satsolver_list;\n\t}\n};\n\nstruct ezSatPtr : public std::unique_ptr<ezSAT> {\n\tezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { }\n};\n\nstruct SatGen\n{\n\tezSAT *ez;\n\tconst SigMap *sigmap;\n\tstd::string prefix;\n\tSigPool initial_state;\n\tstd::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;\n\tstd::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;\n\tstd::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;\n\tstd::map<std::pair<std::string, int>, bool> initstates;\n\tbool ignore_div_by_zero;\n\tbool model_undef;\n\tbool def_formal = false;\n\n\tSatGen(ezSAT *ez, const SigMap *sigmap, std::string prefix = std::string()) :\n\t\t\tez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)\n\t{\n\t}\n\n\tvoid setContext(const SigMap *sigmap, std::string prefix = std::string())\n\t{\n\t\tthis->sigmap = sigmap;\n\t\tthis->prefix = prefix;\n\t}\n\n\tstd::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef)\n\t{\n\t\tlog_assert(!undef_mode || model_undef);\n\t\tsigmap->apply(sig);\n\n\t\tstd::vector<int> vec;\n\t\tvec.reserve(GetSize(sig));\n\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire == NULL) {\n\t\t\t\tif (model_undef && dup_undef && bit == RTLIL::State::Sx)\n\t\t\t\t\tvec.push_back(ez->frozen_literal());\n\t\t\t\telse\n\t\t\t\t\tvec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE);\n\t\t\t} else {\n\t\t\t\tstd::string wire_name = RTLIL::unescape_id(bit.wire->name);\n\t\t\t\tstd::string name = pf +\n\t\t\t\t\t(bit.wire->width == 1 ? wire_name : stringf(\"%s [%d]\", wire_name.c_str(), bit.offset));\n\t\t\t\tvec.push_back(ez->frozen_literal(name));\n\t\t\t\timported_signals[pf][bit] = vec.back();\n\t\t\t}\n\t\treturn vec;\n\t}\n\n\tstd::vector<int> importSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, false, false);\n\t}\n\n\tstd::vector<int> importDefSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, false, true);\n\t}\n\n\tstd::vector<int> importUndefSigSpec(RTLIL::SigSpec sig, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = \"undef:\" + prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(sig, pf, true, false);\n\t}\n\n\tint importSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, false, false).front();\n\t}\n\n\tint importDefSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, false, true).front();\n\t}\n\n\tint importUndefSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = \"undef:\" + prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn importSigSpecWorker(bit, pf, true, false).front();\n\t}\n\n\tbool importedSigBit(RTLIL::SigBit bit, int timestep = -1)\n\t{\n\t\tlog_assert(timestep != 0);\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\treturn imported_signals[pf].count(bit) != 0;\n\t}\n\n\tvoid getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)\n\t{\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tsig_a = asserts_a[pf];\n\t\tsig_en = asserts_en[pf];\n\t}\n\n\tvoid getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)\n\t{\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tsig_a = assumes_a[pf];\n\t\tsig_en = assumes_en[pf];\n\t}\n\n\tint importAsserts(int timestep = -1)\n\t{\n\t\tstd::vector<int> check_bits, enable_bits;\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tif (model_undef) {\n\t\t\tcheck_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_a[pf], timestep)), importDefSigSpec(asserts_a[pf], timestep));\n\t\t\tenable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(asserts_en[pf], timestep)), importDefSigSpec(asserts_en[pf], timestep));\n\t\t} else {\n\t\t\tcheck_bits = importDefSigSpec(asserts_a[pf], timestep);\n\t\t\tenable_bits = importDefSigSpec(asserts_en[pf], timestep);\n\t\t}\n\t\treturn ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));\n\t}\n\n\tint importAssumes(int timestep = -1)\n\t{\n\t\tstd::vector<int> check_bits, enable_bits;\n\t\tstd::string pf = prefix + (timestep == -1 ? \"\" : stringf(\"@%d:\", timestep));\n\t\tif (model_undef) {\n\t\t\tcheck_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep));\n\t\t\tenable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep));\n\t\t} else {\n\t\t\tcheck_bits = importDefSigSpec(assumes_a[pf], timestep);\n\t\t\tenable_bits = importDefSigSpec(assumes_en[pf], timestep);\n\t\t}\n\t\treturn ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));\n\t}\n\n\tint signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1)\n\t{\n\t\tif (timestep_rhs < 0)\n\t\t\ttimestep_rhs = timestep_lhs;\n\n\t\tlog_assert(lhs.size() == rhs.size());\n\n\t\tstd::vector<int> vec_lhs = importSigSpec(lhs, timestep_lhs);\n\t\tstd::vector<int> vec_rhs = importSigSpec(rhs, timestep_rhs);\n\n\t\tif (!model_undef)\n\t\t\treturn ez->vec_eq(vec_lhs, vec_rhs);\n\n\t\tstd::vector<int> undef_lhs = importUndefSigSpec(lhs, timestep_lhs);\n\t\tstd::vector<int> undef_rhs = importUndefSigSpec(rhs, timestep_rhs);\n\n\t\tstd::vector<int> eq_bits;\n\t\tfor (int i = 0; i < lhs.size(); i++)\n\t\t\teq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)),\n\t\t\t\t\tez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i)))));\n\t\treturn ez->expression(ezSAT::OpAnd, eq_bits);\n\t}\n\n\tvoid extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, RTLIL::Cell *cell, size_t y_width = 0, bool forced_signed = false)\n\t{\n\t\tbool is_signed = forced_signed;\n\t\tif (!forced_signed && cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters.count(ID::B_SIGNED) > 0)\n\t\t\tis_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool();\n\t\twhile (vec_a.size() < vec_b.size() || vec_a.size() < y_width)\n\t\t\tvec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);\n\t\twhile (vec_b.size() < vec_a.size() || vec_b.size() < y_width)\n\t\t\tvec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE);\n\t}\n\n\tvoid extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)\n\t{\n\t\textendSignalWidth(vec_a, vec_b, cell, vec_y.size(), forced_signed);\n\t\twhile (vec_y.size() < vec_a.size())\n\t\t\tvec_y.push_back(ez->literal());\n\t}\n\n\tvoid extendSignalWidthUnary(std::vector<int> &vec_a, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)\n\t{\n\t\tbool is_signed = forced_signed || (cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool());\n\t\twhile (vec_a.size() < vec_y.size())\n\t\t\tvec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);\n\t\twhile (vec_y.size() < vec_a.size())\n\t\t\tvec_y.push_back(ez->literal());\n\t}\n\n\tvoid undefGating(std::vector<int> &vec_y, std::vector<int> &vec_yy, std::vector<int> &vec_undef)\n\t{\n\t\tlog_assert(model_undef);\n\t\tlog_assert(vec_y.size() == vec_yy.size());\n\t\tif (vec_y.size() > vec_undef.size()) {\n\t\t\tstd::vector<int> trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size());\n\t\t\tstd::vector<int> trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size());\n\t\t\tez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy))));\n\t\t} else {\n\t\t\tlog_assert(vec_y.size() == vec_undef.size());\n\t\t\tez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));\n\t\t}\n\t}\n\n\tstd::pair<std::vector<int>, std::vector<int>> mux(int s, int undef_s, const std::vector<int> &a, const std::vector<int> &undef_a, const std::vector<int> &b, const std::vector<int> &undef_b) {\n\t\tstd::vector<int> res;\n\t\tstd::vector<int> undef_res;\n\t\tres = ez->vec_ite(s, b, a);\n\t\tif (model_undef) {\n\t\t\tstd::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));\n\t\t\tstd::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));\n\t\t\tundef_res = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a));\n\t\t}\n\t\treturn std::make_pair(res, undef_res);\n\t}\n\n\tvoid undefGating(int y, int yy, int undef)\n\t{\n\t\tez->assume(ez->OR(undef, ez->IFF(y, yy)));\n\t}\n\n\tvoid setInitState(int timestep)\n\t{\n\t\tauto key = make_pair(prefix, timestep);\n\t\tlog_assert(initstates.count(key) == 0 || initstates.at(key) == true);\n\t\tinitstates[key] = true;\n\t}\n\n\tbool importCell(RTLIL::Cell *cell, int timestep = -1);\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
187
187
|
"scopeinfo.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2024 Jannis Harder <jix@yosyshq.com> <me@jix.one>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SCOPEINFO_H\n#define SCOPEINFO_H\n\n#include <vector>\n#include <algorithm>\n\n#include \"kernel/yosys.h\"\n#include \"kernel/celltypes.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\ntemplate<typename T>\nclass IdTree\n{\npublic:\n\tstruct Cursor;\n\nprotected:\n\tIdTree *parent = nullptr;\n\tIdString scope_name;\n\tint depth = 0;\n\n\tpool<IdString> names;\n\tdict<IdString, T> entries;\npublic: // XXX\n\tdict<IdString, std::unique_ptr<IdTree>> subtrees;\n\n\ttemplate<typename P, typename T_ref>\n\tstatic Cursor do_insert(IdTree *tree, P begin, P end, T_ref &&value)\n\t{\n\t\tlog_assert(begin != end && \"path must be non-empty\");\n\t\twhile (true) {\n\t\t\tIdString name = *begin;\n\t\t\t++begin;\n\t\t\tlog_assert(!name.empty());\n\t\t\ttree->names.insert(name);\n\t\t\tif (begin == end) {\n\t\t\t\ttree->entries.emplace(name, std::forward<T_ref>(value));\n\t\t\t\treturn Cursor(tree, name);\n\t\t\t}\n\t\t\tauto &unique = tree->subtrees[name];\n\t\t\tif (!unique) {\n\t\t\t\tunique.reset(new IdTree);\n\t\t\t\tunique->scope_name = name;\n\t\t\t\tunique->parent = tree;\n\t\t\t\tunique->depth = tree->depth + 1;\n\t\t\t}\n\t\t\ttree = unique.get();\n\t\t}\n\t}\n\npublic:\n\tIdTree() = default;\n\tIdTree(const IdTree &) = delete;\n\tIdTree(IdTree &&) = delete;\n\n\t// A cursor remains valid as long as the (sub-)IdTree it points at is alive\n\tstruct Cursor\n\t{\n\t\tfriend class IdTree;\n\tprotected:\n\tpublic:\n\t\tIdTree *target;\n\t\tIdString scope_name;\n\n\t\tCursor() : target(nullptr) {}\n\t\tCursor(IdTree *target, IdString scope_name) : target(target), scope_name(scope_name) {\n\t\t\tif (scope_name.empty())\n\t\t\t\tlog_assert(target->parent == nullptr);\n\t\t}\n\n\t\tCursor do_first_child() {\n\t\t\tIdTree *tree = nullptr;\n\t\t\tif (scope_name.empty()) {\n\t\t\t\ttree = target;\n\t\t\t} else {\n\t\t\t\tauto found = target->subtrees.find(scope_name);\n\t\t\t\tif (found != target->subtrees.end()) {\n\t\t\t\t\ttree = found->second.get();\n\t\t\t\t} else {\n\t\t\t\t\treturn Cursor();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tree->names.empty()) {\n\t\t\t\treturn Cursor();\n\t\t\t}\n\t\t\treturn Cursor(tree, *tree->names.begin());\n\t\t}\n\n\t\tCursor do_next_sibling() {\n\t\t\tif (scope_name.empty())\n\t\t\t\treturn Cursor();\n\t\t\tauto found = target->names.find(scope_name);\n\t\t\tif (found == target->names.end())\n\t\t\t\treturn Cursor();\n\t\t\t++found;\n\t\t\tif (found == target->names.end())\n\t\t\t\treturn Cursor();\n\t\t\treturn Cursor(target, *found);\n\t\t}\n\n\t\tCursor do_parent() {\n\t\t\tif (scope_name.empty())\n\t\t\t\treturn Cursor();\n\t\t\tif (target->parent != nullptr)\n\t\t\t\treturn Cursor(target->parent, target->scope_name);\n\t\t\treturn Cursor(target, IdString());\n\t\t}\n\n\t\tCursor do_next_preorder() {\n\t\t\tCursor current = *this;\n\t\t\tCursor next = current.do_first_child();\n\t\t\tif (next.valid())\n\t\t\t\treturn next;\n\t\t\twhile (current.valid()) {\n\t\t\t\tif (next.valid())\n\t\t\t\t\treturn next;\n\t\t\t\tnext = current.do_next_sibling();\n\t\t\t\tif (next.valid())\n\t\t\t\t\treturn next;\n\t\t\t\tcurrent = current.do_parent();\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\n\t\tCursor do_child(IdString name) {\n\t\t\tIdTree *tree = nullptr;\n\t\t\tif (scope_name.empty()) {\n\t\t\t\ttree = target;\n\t\t\t} else {\n\t\t\t\tauto found = target->subtrees.find(scope_name);\n\t\t\t\tif (found != target->subtrees.end()) {\n\t\t\t\t\ttree = found->second.get();\n\t\t\t\t} else {\n\t\t\t\t\treturn Cursor();\n\t\t\t\t}\n\t\t\t}\n\t\t\tauto found = tree->names.find(name);\n\t\t\tif (found == tree->names.end()) {\n\t\t\t\treturn Cursor();\n\t\t\t}\n\t\t\treturn Cursor(tree, *found);\n\t\t}\n\n\tpublic:\n\t\tbool operator==(const Cursor &other) const {\n\t\t\treturn target == other.target && scope_name == other.scope_name;\n\t\t}\n\t\tbool operator!=(const Cursor &other) const {\n\t\t\treturn !(*this == other);\n\t\t}\n\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const\n\t\t{\n\t\t\th.eat(scope_name);\n\t\t\th.eat(target);\n\t\t\treturn h;\n\t\t}\n\n\t\tbool valid() const {\n\t\t\treturn target != nullptr;\n\t\t}\n\n\t\tint depth() const {\n\t\t\tlog_assert(valid());\n\t\t\treturn target->depth + !scope_name.empty();\n\t\t}\n\n\t\tbool is_root() const {\n\t\t\treturn target != nullptr && scope_name.empty();\n\t\t}\n\n\t\tbool has_entry() const {\n\t\t\tlog_assert(valid());\n\t\t\treturn !scope_name.empty() && target->entries.count(scope_name);\n\t\t}\n\n\t\tT &entry() {\n\t\t\tlog_assert(!scope_name.empty());\n\t\t\treturn target->entries.at(scope_name);\n\t\t}\n\n\t\tvoid assign_path_to(std::vector<IdString> &out_path) {\n\t\t\tlog_assert(valid());\n\t\t\tout_path.clear();\n\t\t\tif (scope_name.empty())\n\t\t\t\treturn;\n\t\t\tout_path.push_back(scope_name);\n\t\t\tIdTree *current = target;\n\t\t\twhile (current->parent) {\n\t\t\t\tout_path.push_back(current->scope_name);\n\t\t\t\tcurrent = current->parent;\n\t\t\t}\n\t\t\tstd::reverse(out_path.begin(), out_path.end());\n\t\t}\n\n\t\tstd::vector<IdString> path() {\n\t\t\tstd::vector<IdString> result;\n\t\t\tassign_path_to(result);\n\t\t\treturn result;\n\t\t}\n\n\t\tstd::string path_str() {\n\t\t\tstd::string result;\n\t\t\tfor (const auto &item : path()) {\n\t\t\t\tif (!result.empty())\n\t\t\t\t\tresult.push_back(' ');\n\t\t\t\tresult += RTLIL::unescape_id(item);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tCursor first_child() {\n\t\t\tlog_assert(valid());\n\t\t\treturn do_first_child();\n\t\t}\n\n\t\tCursor next_preorder() {\n\t\t\tlog_assert(valid());\n\t\t\treturn do_next_preorder();\n\t\t}\n\n\t\tCursor parent() {\n\t\t\tlog_assert(valid());\n\t\t\treturn do_parent();\n\t\t}\n\n\t\tCursor child(IdString name) {\n\t\t\tlog_assert(valid());\n\t\t\treturn do_child(name);\n\t\t}\n\n\t\tCursor common_ancestor(Cursor other) {\n\t\t\tCursor current = *this;\n\n\t\t\twhile (current != other) {\n\t\t\t\tif (!current.valid() || !other.valid())\n\t\t\t\t\treturn Cursor();\n\t\t\t\tint delta = current.depth() - other.depth();\n\t\t\t\tif (delta >= 0)\n\t\t\t\t\tcurrent = current.do_parent();\n\t\t\t\tif (delta <= 0)\n\t\t\t\t\tother = other.do_parent();\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\t};\n\n\ttemplate<typename P>\n\tCursor insert(P begin, P end, const T &value) {\n\t\treturn do_insert(this, begin, end, value);\n\t}\n\n\ttemplate<typename P>\n\tCursor insert(P begin, P end, T &&value) {\n\t\treturn do_insert(this, begin, end, std::move(value));\n\t}\n\n\ttemplate<typename P>\n\tCursor insert(const P &path, const T &value) {\n\t\treturn do_insert(this, path.begin(), path.end(), value);\n\t}\n\n\ttemplate<typename P>\n\tCursor insert(const P &path, T &&value) {\n\t\treturn do_insert(this, path.begin(), path.end(), std::move(value));\n\t}\n\n\tCursor cursor() {\n\t\treturn parent ? Cursor(this->parent, this->scope_name) : Cursor(this, IdString());\n\t}\n\n\ttemplate<typename P>\n\tCursor cursor(P begin, P end) {\n\t\tCursor current = cursor();\n\t\tfor (; begin != end; ++begin) {\n\t\t\tcurrent = current.do_child(*begin);\n\t\t\tif (!current.valid())\n\t\t\t\tbreak;\n\t\t}\n\t\treturn current;\n\t}\n\n\ttemplate<typename P>\n\tCursor cursor(const P &path) {\n\t\treturn cursor(path.begin(), path.end());\n\t}\n};\n\n\nstruct ModuleItem {\n\tenum class Type {\n\t\tWire,\n\t\tCell,\n\t};\n\tType type;\n\tvoid *ptr;\n\n\tModuleItem(Wire *wire) : type(Type::Wire), ptr(wire) {}\n\tModuleItem(Cell *cell) : type(Type::Cell), ptr(cell) {}\n\n\tbool is_wire() const { return type == Type::Wire; }\n\tbool is_cell() const { return type == Type::Cell; }\n\n\tWire *wire() const { return type == Type::Wire ? static_cast<Wire *>(ptr) : nullptr; }\n\tCell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }\n\n\tbool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }\n\t[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(ptr); return h; }\n};\n\nstatic inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log(\"%p %s\", cursor.target, log_id(cursor.scope_name)); }\n\ntemplate<typename T>\nstatic inline void log_dump_val_worker(const typename std::unique_ptr<T> &cursor ) { log(\"unique %p\", cursor.get()); }\n\ntemplate<typename O>\nstd::vector<IdString> parse_hdlname(const O* object)\n{\n\tstd::vector<IdString> path;\n\tfor (auto const &item : object->get_hdlname_attribute())\n\t\tpath.push_back(\"\\\\\" + item);\n\tif (path.empty() && object->name.isPublic())\n\t\tpath.push_back(object->name);\n\tif (!path.empty() && !(object->name.isPublic() || object->name.begins_with(\"$paramod\") || object->name.begins_with(\"$abstract\"))) {\n\t\tpath.pop_back();\n\t\tpath.push_back(object->name);\n\t}\n\treturn path;\n}\n\ntemplate<typename O>\nstd::pair<std::vector<IdString>, IdString> parse_scopename(const O* object)\n{\n\tstd::vector<IdString> path;\n\tIdString trailing = object->name;\n\tif (object->name.isPublic() || object->name.begins_with(\"$paramod\") || object->name.begins_with(\"$abstract\")) {\n\t\tfor (auto const &item : object->get_hdlname_attribute())\n\t\t\tpath.push_back(\"\\\\\" + item);\n\t\tif (!path.empty()) {\n\t\t\ttrailing = path.back();\n\t\t\tpath.pop_back();\n\t\t}\n\t} else if (object->has_attribute(ID::hdlname)) {\n\t\tfor (auto const &item : object->get_hdlname_attribute())\n\t\t\tpath.push_back(\"\\\\\" + item);\n\t\tif (!path.empty()) {\n\t\t\tpath.pop_back();\n\t\t}\n\t} else {\n\t\tfor (auto const &item : split_tokens(object->get_string_attribute(ID(scopename)), \" \"))\n\t\t\tpath.push_back(\"\\\\\" + item);\n\t}\n\treturn {path, trailing};\n}\n\nstruct ModuleHdlnameIndex {\n\ttypedef IdTree<ModuleItem>::Cursor Cursor;\n\n\tRTLIL::Module *module;\n\tIdTree<ModuleItem> tree;\n\tdict<ModuleItem, Cursor> lookup;\n\n\tModuleHdlnameIndex(RTLIL::Module *module) : module(module) {}\n\nprivate:\n\ttemplate<typename I, typename Filter>\n\tvoid index_items(I begin, I end, Filter filter);\n\npublic:\n\t// Index all wires and cells of the module\n\tvoid index();\n\n\t// Index all wires of the module\n\tvoid index_wires();\n\n\t// Index all cells of the module\n\tvoid index_cells();\n\n\t// Index only the $scopeinfo cells of the module.\n\t// This is sufficient when using `containing_scope`.\n\tvoid index_scopeinfo_cells();\n\n\n\t// Return the cursor for the containing scope of some RTLIL object (Wire/Cell/...)\n\ttemplate<typename O>\n\tstd::pair<Cursor, IdString> containing_scope(O *object) {\n\t\tauto pair = parse_scopename(object);\n\t\treturn {tree.cursor(pair.first), pair.second};\n\t}\n\n\t// Return a vector of source locations starting from the indexed module to\n\t// the scope represented by the cursor. The vector alternates module and\n\t// module item source locations, using empty strings for missing src\n\t// attributes.\n\tstd::vector<std::string> scope_sources(Cursor cursor);\n\n\t// Return a vector of source locations starting from the indexed module to\n\t// the passed RTLIL object (Wire/Cell/...). The vector alternates module\n\t// and module item source locations, using empty strings for missing src\n\t// attributes.\n\ttemplate<typename O>\n\tstd::vector<std::string> sources(O *object) {\n\t\tauto pair = parse_scopename(object);\n\t\tstd::vector<std::string> result = scope_sources(tree.cursor(pair.first));\n\t\tresult.push_back(object->get_src_attribute());\n\t\treturn result;\n\t}\n};\n\nenum class ScopeinfoAttrs {\n\tModule,\n\tCell,\n};\n\n// Check whether the flattened module or flattened cell corresponding to a $scopeinfo cell had a specific attribute.\nbool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);\n\n// Get a specific attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.\nRTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);\n\n// Get all attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.\ndict<RTLIL::IdString, RTLIL::Const> scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs);\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
188
188
|
"sexpr.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2024 Emily Schmidt <emily@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SEXPR_H\n#define SEXPR_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nclass SExpr {\npublic:\n\tstd::variant<std::vector<SExpr>, std::string> _v;\npublic:\n\tSExpr(std::string a) : _v(std::move(a)) {}\n SExpr(const char *a) : _v(a) {}\n // FIXME: should maybe be defined for all integral types\n\tSExpr(int n) : _v(std::to_string(n)) {}\n\tSExpr(std::vector<SExpr> const &l) : _v(l) {}\n\tSExpr(std::vector<SExpr> &&l) : _v(std::move(l)) {}\n // It would be nicer to have an std::initializer_list constructor,\n // but that causes confusing issues with overload resolution sometimes.\n template<typename... Args> static SExpr list(Args&&... args) {\n\t return SExpr(std::vector<SExpr>{std::forward<Args>(args)...});\n }\n bool is_atom() const { return std::holds_alternative<std::string>(_v); }\n std::string const &atom() const { return std::get<std::string>(_v); }\n bool is_list() const { return std::holds_alternative<std::vector<SExpr>>(_v); }\n std::vector<SExpr> const &list() const { return std::get<std::vector<SExpr>>(_v); }\n\tstd::string to_string() const;\n};\n\nstd::ostream &operator<<(std::ostream &os, SExpr const &sexpr);\n\nnamespace SExprUtil {\n // A little hack so that `using SExprUtil::list` lets you import a shortcut to `SExpr::list`\n template<typename... Args> SExpr list(Args&&... args) {\n\t return SExpr(std::vector<SExpr>{std::forward<Args>(args)...});\n }\n}\n\n// SExprWriter is a pretty printer for s-expr. It does not try very hard to get a good layout.\nclass SExprWriter {\n std::ostream &os;\n int _max_line_width;\n int _indent = 0;\n int _pos = 0;\n // If _pending_nl is set, print a newline before the next character.\n // This lets us \"undo\" the last newline so we can put\n // closing parentheses or a hanging comment on the same line.\n bool _pending_nl = false;\n // Unclosed parentheses (boolean stored is indent_rest)\n\tvector<bool> _unclosed;\n // Used only for push() and pop() (stores _unclosed.size())\n\tvector<size_t> _unclosed_stack;\n\tvoid nl_if_pending();\n void puts(std::string_view s);\n int check_fit(SExpr const &sexpr, int space);\n void print(SExpr const &sexpr, bool close = true, bool indent_rest = true);\npublic:\n SExprWriter(std::ostream &os, int max_line_width = 80)\n : os(os)\n , _max_line_width(max_line_width)\n {}\n // Print an s-expr.\n SExprWriter &operator <<(SExpr const &sexpr) {\n print(sexpr);\n _pending_nl = true;\n return *this;\n }\n // Print an s-expr (which must be a list), but leave room for extra elements\n // which may be printed using either << or further calls to open.\n // If indent_rest = false, the remaining elements are not intended\n // (for avoiding unreasonable indentation on deeply nested structures).\n void open(SExpr const &sexpr, bool indent_rest = true) {\n log_assert(sexpr.is_list());\n print(sexpr, false, indent_rest);\n }\n // Close the s-expr opened with the last call to open\n // (if an argument is given, close that many s-exprs).\n void close(size_t n = 1);\n // push() remembers how many s-exprs are currently open\n\tvoid push() {\n\t\t_unclosed_stack.push_back(_unclosed.size());\n\t}\n // pop() closes all s-expr opened since the corresponding call to push()\n\tvoid pop() {\n\t\tauto t = _unclosed_stack.back();\n\t\tlog_assert(_unclosed.size() >= t);\n\t\tclose(_unclosed.size() - t);\n\t\t_unclosed_stack.pop_back();\n\t}\n // Print a comment.\n // If hanging = true, append it to the end of the last printed s-expr.\n\tvoid comment(std::string const &str, bool hanging = false);\n // Flush any unprinted characters to the std::ostream, but does not close unclosed parentheses.\n void flush() {\n nl_if_pending();\n }\n // Destructor closes any unclosed parentheses and flushes.\n ~SExprWriter();\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
189
|
-
"sigtools.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SIGTOOLS_H\n#define SIGTOOLS_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct SigPool\n{\n\tstruct bitDef_t : public std::pair<RTLIL::Wire*, int> {\n\t\tbitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }\n\t\tbitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(first->name);\n\t\t\th.eat(second);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tpool<bitDef_t> bits;\n\n\tvoid clear()\n\t{\n\t\tbits.clear();\n\t}\n\n\tvoid add(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits.insert(bit);\n\t}\n\n\tvoid add(const SigPool &other)\n\t{\n\t\tfor (auto &bit : other.bits)\n\t\t\tbits.insert(bit);\n\t}\n\n\tvoid del(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits.erase(bit);\n\t}\n\n\tvoid del(const SigPool &other)\n\t{\n\t\tfor (auto &bit : other.bits)\n\t\t\tbits.erase(bit);\n\t}\n\n\tvoid expand(const RTLIL::SigSpec &from, const RTLIL::SigSpec &to)\n\t{\n\t\tlog_assert(GetSize(from) == GetSize(to));\n\t\tfor (int i = 0; i < GetSize(from); i++) {\n\t\t\tbitDef_t bit_from(from[i]), bit_to(to[i]);\n\t\t\tif (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)\n\t\t\t\tbits.insert(bit_to);\n\t\t}\n\t}\n\n\tRTLIL::SigSpec extract(const RTLIL::SigSpec &sig) const\n\t{\n\t\tRTLIL::SigSpec result;\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\tresult.append(bit);\n\t\treturn result;\n\t}\n\n\tRTLIL::SigSpec remove(const RTLIL::SigSpec &sig) const\n\t{\n\t\tRTLIL::SigSpec result;\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit) == 0)\n\t\t\t\tresult.append(bit);\n\t\treturn result;\n\t}\n\n\tbool check(const RTLIL::SigBit &bit) const\n\t{\n\t\treturn bit.wire != NULL && bits.count(bit);\n\t}\n\n\tbool check_any(const RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool check_all(const RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit) == 0)\n\t\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tRTLIL::SigSpec export_one() const\n\t{\n\t\tfor (auto &bit : bits)\n\t\t\treturn RTLIL::SigSpec(bit.first, bit.second);\n\t\treturn RTLIL::SigSpec();\n\t}\n\n\tRTLIL::SigSpec export_all() const\n\t{\n\t\tpool<RTLIL::SigBit> sig;\n\t\tfor (auto &bit : bits)\n\t\t\tsig.insert(RTLIL::SigBit(bit.first, bit.second));\n\t\treturn sig;\n\t}\n\n\tsize_t size() const\n\t{\n\t\treturn bits.size();\n\t}\n};\n\ntemplate <typename T, class Compare = void>\nstruct SigSet\n{\n\tstatic_assert(!std::is_same<Compare,void>::value, \"Default value for `Compare' class not found for SigSet<T>. Please specify.\");\n\n\tstruct bitDef_t : public std::pair<RTLIL::Wire*, int> {\n\t\tbitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }\n\t\tbitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(first->name);\n\t\t\th.eat(second);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tdict<bitDef_t, std::set<T, Compare>> bits;\n\n\tvoid clear()\n\t{\n\t\tbits.clear();\n\t}\n\n\tvoid insert(const RTLIL::SigSpec &sig, T data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].insert(data);\n\t}\n\n\tvoid insert(const RTLIL::SigSpec& sig, const std::set<T> &data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].insert(data.begin(), data.end());\n\t}\n\n\tvoid erase(const RTLIL::SigSpec& sig)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].clear();\n\t}\n\n\tvoid erase(const RTLIL::SigSpec &sig, T data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].erase(data);\n\t}\n\n\tvoid erase(const RTLIL::SigSpec &sig, const std::set<T> &data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].erase(data.begin(), data.end());\n\t}\n\n\tvoid find(const RTLIL::SigSpec &sig, std::set<T> &result)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL) {\n\t\t\t\tauto &data = bits[bit];\n\t\t\t\tresult.insert(data.begin(), data.end());\n\t\t\t}\n\t}\n\n\tvoid find(const RTLIL::SigSpec &sig, pool<T> &result)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL) {\n\t\t\t\tauto &data = bits[bit];\n\t\t\t\tresult.insert(data.begin(), data.end());\n\t\t\t}\n\t}\n\n\tstd::set<T> find(const RTLIL::SigSpec &sig)\n\t{\n\t\tstd::set<T> result;\n\t\tfind(sig, result);\n\t\treturn result;\n\t}\n\n\tbool has(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\treturn true;\n\t\treturn false;\n\t}\n};\n\ntemplate<typename T>\nclass SigSet<T, typename std::enable_if<!std::is_pointer<T>::value>::type> : public SigSet<T, std::less<T>> {};\ntemplate<typename T>\nusing sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell*>::value>::type;\ntemplate<typename T>\nclass SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};\n\n/**\n * SigMap wraps a union-find \"database\"\n * to map SigBits of a module to canonical representative SigBits.\n * SigBits that are connected share a set in the underlying database.\n * If a SigBit has a const state (impl: bit.wire is nullptr),\n * it's promoted to a representative.\n */\nstruct SigMap\n{\n\tmfp<SigBit> database;\n\n\tSigMap(RTLIL::Module *module = NULL)\n\t{\n\t\tif (module != NULL)\n\t\t\tset(module);\n\t}\n\n\tvoid swap(SigMap &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t}\n\n\tvoid clear()\n\t{\n\t\tdatabase.clear();\n\t}\n\n\t// Rebuild SigMap for all connections in module\n\tvoid set(RTLIL::Module *module)\n\t{\n\t\tint bitcount = 0;\n\t\tfor (auto &it : module->connections())\n\t\t\tbitcount += it.first.size();\n\n\t\tdatabase.clear();\n\t\tdatabase.reserve(bitcount);\n\n\t\tfor (auto &it : module->connections())\n\t\t\tadd(it.first, it.second);\n\t}\n\n\t// Add connections from \"from\" to \"to\", bit-by-bit\n\tvoid add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)\n\t{\n\t\tlog_assert(GetSize(from) == GetSize(to));\n\n\t\tfor (int i = 0; i < GetSize(from); i++)\n\t\t{\n\t\t\tint bfi = database.lookup(from[i]);\n\t\t\tint bti = database.lookup(to[i]);\n\n\t\t\tconst RTLIL::SigBit &bf = database[bfi];\n\t\t\tconst RTLIL::SigBit &bt = database[bti];\n\n\t\t\tif (bf.wire || bt.wire)\n\t\t\t{\n\t\t\t\tdatabase.imerge(bfi, bti);\n\n\t\t\t\tif (bf.wire == nullptr)\n\t\t\t\t\tdatabase.ipromote(bfi);\n\n\t\t\t\tif (bt.wire == nullptr)\n\t\t\t\t\tdatabase.ipromote(bti);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add sig as disconnected from anything\n\tvoid add(const RTLIL::SigBit &bit)\n\t{\n\t\tconst auto &b = database.find(bit);\n\t\tif (b.wire != nullptr)\n\t\t\tdatabase.promote(bit);\n\t}\n\n\tvoid add(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tadd(bit);\n\t}\n\n\tinline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }\n\n\t// Modify bit to its representative\n\tvoid apply(RTLIL::SigBit &bit) const\n\t{\n\t\tbit = database.find(bit);\n\t}\n\n\tvoid apply(RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tapply(bit);\n\t}\n\n\tRTLIL::SigBit operator()(RTLIL::SigBit bit) const\n\t{\n\t\tapply(bit);\n\t\treturn bit;\n\t}\n\n\tRTLIL::SigSpec operator()(RTLIL::SigSpec sig) const\n\t{\n\t\tapply(sig);\n\t\treturn sig;\n\t}\n\n\tRTLIL::SigSpec operator()(RTLIL::Wire *wire) const\n\t{\n\t\tSigSpec sig(wire);\n\t\tapply(sig);\n\t\treturn sig;\n\t}\n\n\t// All non-const bits\n\tRTLIL::SigSpec allbits() const\n\t{\n\t\tRTLIL::SigSpec sig;\n\t\tfor (const auto &bit : database)\n\t\t\tif (bit.wire != nullptr)\n\t\t\t\tsig.append(bit);\n\t\treturn sig;\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif /* SIGTOOLS_H */\n",
|
|
189
|
+
"sigtools.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef SIGTOOLS_H\n#define SIGTOOLS_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct SigPool\n{\n\tstruct bitDef_t : public std::pair<RTLIL::Wire*, int> {\n\t\tbitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }\n\t\tbitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(first->name);\n\t\t\th.eat(second);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tpool<bitDef_t> bits;\n\n\tvoid clear()\n\t{\n\t\tbits.clear();\n\t}\n\n\tvoid add(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits.insert(bit);\n\t}\n\n\tvoid add(const SigPool &other)\n\t{\n\t\tfor (auto &bit : other.bits)\n\t\t\tbits.insert(bit);\n\t}\n\n\tvoid del(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits.erase(bit);\n\t}\n\n\tvoid del(const SigPool &other)\n\t{\n\t\tfor (auto &bit : other.bits)\n\t\t\tbits.erase(bit);\n\t}\n\n\tvoid expand(const RTLIL::SigSpec &from, const RTLIL::SigSpec &to)\n\t{\n\t\tlog_assert(GetSize(from) == GetSize(to));\n\t\tfor (int i = 0; i < GetSize(from); i++) {\n\t\t\tbitDef_t bit_from(from[i]), bit_to(to[i]);\n\t\t\tif (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)\n\t\t\t\tbits.insert(bit_to);\n\t\t}\n\t}\n\n\tRTLIL::SigSpec extract(const RTLIL::SigSpec &sig) const\n\t{\n\t\tRTLIL::SigSpec result;\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\tresult.append(bit);\n\t\treturn result;\n\t}\n\n\tRTLIL::SigSpec remove(const RTLIL::SigSpec &sig) const\n\t{\n\t\tRTLIL::SigSpec result;\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit) == 0)\n\t\t\t\tresult.append(bit);\n\t\treturn result;\n\t}\n\n\tbool check(const RTLIL::SigBit &bit) const\n\t{\n\t\treturn bit.wire != NULL && bits.count(bit);\n\t}\n\n\tbool check_any(const RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool check_all(const RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit) == 0)\n\t\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tRTLIL::SigSpec export_one() const\n\t{\n\t\tfor (auto &bit : bits)\n\t\t\treturn RTLIL::SigSpec(bit.first, bit.second);\n\t\treturn RTLIL::SigSpec();\n\t}\n\n\tRTLIL::SigSpec export_all() const\n\t{\n\t\tpool<RTLIL::SigBit> sig;\n\t\tfor (auto &bit : bits)\n\t\t\tsig.insert(RTLIL::SigBit(bit.first, bit.second));\n\t\treturn sig;\n\t}\n\n\tsize_t size() const\n\t{\n\t\treturn bits.size();\n\t}\n};\n\ntemplate <typename T, class Compare = void>\nstruct SigSet\n{\n\tstatic_assert(!std::is_same<Compare,void>::value, \"Default value for `Compare' class not found for SigSet<T>. Please specify.\");\n\n\tstruct bitDef_t : public std::pair<RTLIL::Wire*, int> {\n\t\tbitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }\n\t\tbitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(first->name);\n\t\t\th.eat(second);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tdict<bitDef_t, std::set<T, Compare>> bits;\n\n\tvoid clear()\n\t{\n\t\tbits.clear();\n\t}\n\n\tvoid insert(const RTLIL::SigSpec &sig, T data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].insert(data);\n\t}\n\n\tvoid insert(const RTLIL::SigSpec& sig, const std::set<T> &data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].insert(data.begin(), data.end());\n\t}\n\n\tvoid erase(const RTLIL::SigSpec& sig)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].clear();\n\t}\n\n\tvoid erase(const RTLIL::SigSpec &sig, T data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].erase(data);\n\t}\n\n\tvoid erase(const RTLIL::SigSpec &sig, const std::set<T> &data)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL)\n\t\t\t\tbits[bit].erase(data.begin(), data.end());\n\t}\n\n\tvoid find(const RTLIL::SigSpec &sig, std::set<T> &result)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL) {\n\t\t\t\tauto &data = bits[bit];\n\t\t\t\tresult.insert(data.begin(), data.end());\n\t\t\t}\n\t}\n\n\tvoid find(const RTLIL::SigSpec &sig, pool<T> &result)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tif (bit.wire != NULL) {\n\t\t\t\tauto &data = bits[bit];\n\t\t\t\tresult.insert(data.begin(), data.end());\n\t\t\t}\n\t}\n\n\tstd::set<T> find(const RTLIL::SigSpec &sig)\n\t{\n\t\tstd::set<T> result;\n\t\tfind(sig, result);\n\t\treturn result;\n\t}\n\n\tbool has(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tif (bit.wire != NULL && bits.count(bit))\n\t\t\t\treturn true;\n\t\treturn false;\n\t}\n};\n\ntemplate<typename T>\nclass SigSet<T, typename std::enable_if<!std::is_pointer<T>::value>::type> : public SigSet<T, std::less<T>> {};\ntemplate<typename T>\nusing sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell*>::value>::type;\ntemplate<typename T>\nclass SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};\n\nstruct SigMapView\n{\n\tmfp<SigBit> database;\n\n\t// Modify bit to its representative\n\tvoid apply(RTLIL::SigBit &bit) const\n\t{\n\t\tbit = database.find(bit);\n\t}\n\n\tvoid apply(RTLIL::SigSpec &sig) const\n\t{\n\t\tfor (auto &bit : sig)\n\t\t\tapply(bit);\n\t}\n\n\tRTLIL::SigBit operator()(RTLIL::SigBit bit) const\n\t{\n\t\tapply(bit);\n\t\treturn bit;\n\t}\n\n\tRTLIL::SigSpec operator()(RTLIL::SigSpec sig) const\n\t{\n\t\tapply(sig);\n\t\treturn sig;\n\t}\n\n\tRTLIL::SigSpec operator()(RTLIL::Wire *wire) const\n\t{\n\t\tSigSpec sig(wire);\n\t\tapply(sig);\n\t\treturn sig;\n\t}\n};\n\n/**\n * SigMap wraps a union-find \"database\"\n * to map SigBits of a module to canonical representative SigBits.\n * SigBits that are connected share a set in the underlying database.\n * If a SigBit has a const state (impl: bit.wire is nullptr),\n * it's promoted to a representative.\n */\nstruct SigMap final : public SigMapView\n{\n\tSigMap(RTLIL::Module *module = NULL)\n\t{\n\t\tif (module != NULL)\n\t\t\tset(module);\n\t}\n\n\tvoid swap(SigMap &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t}\n\n\tvoid clear()\n\t{\n\t\tdatabase.clear();\n\t}\n\n\t// Rebuild SigMap for all connections in module\n\tvoid set(RTLIL::Module *module)\n\t{\n\t\tint bitcount = 0;\n\t\tfor (auto &it : module->connections())\n\t\t\tbitcount += it.first.size();\n\n\t\tdatabase.clear();\n\t\tdatabase.reserve(bitcount);\n\n\t\tfor (auto &it : module->connections())\n\t\t\tadd(it.first, it.second);\n\t}\n\n\t// Add connections from \"from\" to \"to\", bit-by-bit\n\tvoid add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)\n\t{\n\t\tlog_assert(GetSize(from) == GetSize(to));\n\n\t\tfor (int i = 0; i < GetSize(from); i++)\n\t\t{\n\t\t\tint bfi = database.lookup(from[i]);\n\t\t\tint bti = database.lookup(to[i]);\n\n\t\t\tconst RTLIL::SigBit &bf = database[bfi];\n\t\t\tconst RTLIL::SigBit &bt = database[bti];\n\n\t\t\tif (bf.wire || bt.wire)\n\t\t\t{\n\t\t\t\tdatabase.imerge(bfi, bti);\n\n\t\t\t\tif (bf.wire == nullptr)\n\t\t\t\t\tdatabase.ipromote(bfi);\n\n\t\t\t\tif (bt.wire == nullptr)\n\t\t\t\t\tdatabase.ipromote(bti);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add sig as disconnected from anything\n\tvoid add(const RTLIL::SigBit &bit)\n\t{\n\t\tconst auto &b = database.find(bit);\n\t\tif (b.wire != nullptr)\n\t\t\tdatabase.promote(bit);\n\t}\n\n\tvoid add(const RTLIL::SigSpec &sig)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\tadd(bit);\n\t}\n\n\tinline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }\n\n\t// All non-const bits\n\tRTLIL::SigSpec allbits() const\n\t{\n\t\tRTLIL::SigSpec sig;\n\t\tfor (const auto &bit : database)\n\t\t\tif (bit.wire != nullptr)\n\t\t\t\tsig.append(bit);\n\t\treturn sig;\n\t}\n};\n\n/**\n * SiValgMap wraps a union-find \"database\" to map SigBits of a module to\n * canonical representative SigBits plus some optional Val value associated with the bits.\n * Val has a commutative, associative, idempotent operator|=, a default constructor\n * which constructs an identity element, and a copy constructor.\n * SigBits that are connected share a set in the underlying database;\n * the associated value is the \"sum\" of all the values associated with the contributing bits.\n * If any of the SigBits in a set are a constant, the canonical SigBit is a constant.\n */\ntemplate <class Val>\nstruct SigValMap final : public SigMapView\n{\n\tdict<SigBit, Val> values;\n\n\tvoid swap(SigValMap<Val> &other)\n\t{\n\t\tdatabase.swap(other.database);\n\t\tvalues.swap(other.values);\n\t}\n\n\tvoid clear()\n\t{\n\t\tdatabase.clear();\n\t\tvalues.clear();\n\t}\n\n\t// Rebuild SigMap for all connections in module\n\tvoid set(RTLIL::Module *module)\n\t{\n\t\tint bitcount = 0;\n\t\tfor (auto &it : module->connections())\n\t\t\tbitcount += it.first.size();\n\n\t\tdatabase.clear();\n\t\tvalues.clear();\n\t\tdatabase.reserve(bitcount);\n\n\t\tfor (auto &it : module->connections())\n\t\t\tadd(it.first, it.second);\n\t}\n\n\t// Add connections from \"from\" to \"to\", bit-by-bit.\n\tvoid add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)\n\t{\n\t\tlog_assert(GetSize(from) == GetSize(to));\n\n\t\tfor (int i = 0; i < GetSize(from); i++)\n\t\t{\n\t\t\tint bfi = database.lookup(from[i]);\n\t\t\tint bti = database.lookup(to[i]);\n\t\t\tif (bfi == bti) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst RTLIL::SigBit &bf = database[bfi];\n\t\t\tconst RTLIL::SigBit &bt = database[bti];\n\t\t\tif (bf.wire == nullptr) {\n\t\t\t\t// bf is constant so make it the canonical representative.\n\t\t\t\tdatabase.imerge(bti, bfi);\n\t\t\t\tmerge_value(bt, bf);\n\t\t\t} else {\n\t\t\t\t// Make bt the canonical representative.\n\t\t\t\tdatabase.imerge(bfi, bti);\n\t\t\t\tmerge_value(bf, bt);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid addVal(const RTLIL::SigBit &bit, const Val &val)\n\t{\n\t\tvalues[database.find(bit)] |= val;\n\t}\n\n\tvoid addVal(const RTLIL::SigSpec &sig, const Val &val)\n\t{\n\t\tfor (const auto &bit : sig)\n\t\t\taddVal(bit, val);\n\t}\n\n\tVal apply_and_get_value(RTLIL::SigBit &bit) const\n\t{\n\t\tbit = database.find(bit);\n\t\tauto it = values.find(bit);\n\t\treturn it == values.end() ? Val() : it->second;\n\t}\n\nprivate:\n\tvoid merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to)\n\t{\n\t\tauto it = values.find(from);\n\t\tif (it == values.end()) {\n\t\t\treturn;\n\t\t}\n\t\t// values[to] could resize the underlying `entries` so\n\t\t// finish using `it` first.\n\t\tVal v = it->second;\n\t\tvalues.erase(it);\n\t\tvalues[to] |= v;\n\t}\n};\n\nYOSYS_NAMESPACE_END\n\n#endif /* SIGTOOLS_H */\n",
|
|
190
190
|
"timinginfo.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n * (C) 2020 Eddie Hung <eddie@fpgeh.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n#ifndef TIMINGINFO_H\n#define TIMINGINFO_H\n\n#include \"kernel/yosys.h\"\n\nYOSYS_NAMESPACE_BEGIN\n\nstruct TimingInfo\n{\n\tstruct NameBit\n\t{\n\t\tRTLIL::IdString name;\n\t\tint offset;\n\t\tNameBit() : offset(0) {}\n\t\tNameBit(const RTLIL::IdString name, int offset) : name(name), offset(offset) {}\n\t\texplicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}\n\t\tbool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; }\n\t\tbool operator!=(const NameBit& nb) const { return !operator==(nb); }\n\t\tstd::optional<SigBit> get_connection(RTLIL::Cell *cell) {\n\t\t\tif (!cell->hasPort(name))\n\t\t\t\treturn {};\n\t\t\tauto &port = cell->getPort(name);\n\t\t\tif (offset >= port.size())\n\t\t\t\treturn {};\n\t\t\treturn port[offset];\n\t\t}\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(name);\n\t\t\th.eat(offset);\n\t\t\treturn h;\n\t\t}\n\t};\n\tstruct BitBit\n\t{\n\t\tNameBit first, second;\n\t\tBitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}\n\t\tBitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {}\n\t\tbool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; }\n\t\t[[nodiscard]] Hasher hash_into(Hasher h) const {\n\t\t\th.eat(first);\n\t\t\th.eat(second);\n\t\t\treturn h;\n\t\t}\n\t};\n\n\tstruct ModuleTiming\n\t{\n\t\tdict<BitBit, int> comb;\n\t\tdict<NameBit, std::pair<int,NameBit>> arrival, required;\n\t\tbool has_inputs;\n\t};\n\n\tdict<RTLIL::IdString, ModuleTiming> data;\n\n\tTimingInfo()\n\t{\n\t}\n\n\tTimingInfo(RTLIL::Design *design)\n\t{\n\t\tsetup(design);\n\t}\n\n\tvoid setup(RTLIL::Design *design)\n\t{\n\t\tfor (auto module : design->modules()) {\n\t\t\tif (!module->get_blackbox_attribute())\n\t\t\t\tcontinue;\n\t\t\tsetup_module(module);\n\t\t}\n\t}\n\n\tconst ModuleTiming& setup_module(RTLIL::Module *module)\n\t{\n\t\tauto r = data.insert(module->name);\n\t\tlog_assert(r.second);\n\t\tauto &t = r.first->second;\n\n\t\tfor (auto cell : module->cells()) {\n\t\t\tif (cell->type == ID($specify2)) {\n\t\t\t\tauto en = cell->getPort(ID::EN);\n\t\t\t\tif (en.is_fully_const() && !en.as_bool())\n\t\t\t\t\tcontinue;\n\t\t\t\tauto src = cell->getPort(ID::SRC);\n\t\t\t\tauto dst = cell->getPort(ID::DST);\n\t\t\t\tfor (const auto &c : src.chunks())\n\t\t\t\t\tif (!c.wire || !c.wire->port_input)\n\t\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\\n\", log_id(module), log_id(cell), log_signal(src));\n\t\t\t\tfor (const auto &c : dst.chunks())\n\t\t\t\t\tif (!c.wire || !c.wire->port_output)\n\t\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\\n\", log_id(module), log_id(cell), log_signal(dst));\n\t\t\t\tint rise_max = cell->getParam(ID::T_RISE_MAX).as_int();\n\t\t\t\tint fall_max = cell->getParam(ID::T_FALL_MAX).as_int();\n\t\t\t\tint max = std::max(rise_max,fall_max);\n\t\t\t\tif (max < 0)\n\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\\n\", log_id(module), log_id(cell));\n\t\t\t\tif (cell->getParam(ID::FULL).as_bool()) {\n\t\t\t\t\tfor (const auto &s : src)\n\t\t\t\t\t\tfor (const auto &d : dst) {\n\t\t\t\t\t\t\tauto r = t.comb.insert(BitBit(s,d));\n\t\t\t\t\t\t\tif (!r.second)\n\t\t\t\t\t\t\t\tlog_error(\"Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\\n\", log_id(module), log_signal(s), log_signal(d));\n\t\t\t\t\t\t\tr.first->second = max;\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlog_assert(GetSize(src) == GetSize(dst));\n\t\t\t\t\tfor (auto i = 0; i < GetSize(src); i++) {\n\t\t\t\t\t\tconst auto &s = src[i];\n\t\t\t\t\t\tconst auto &d = dst[i];\n\t\t\t\t\t\tauto r = t.comb.insert(BitBit(s,d));\n\t\t\t\t\t\tif (!r.second)\n\t\t\t\t\t\t\tlog_error(\"Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\\n\", log_id(module), log_signal(s), log_signal(d));\n\t\t\t\t\t\tr.first->second = max;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (cell->type == ID($specify3)) {\n\t\t\t\tauto src = cell->getPort(ID::SRC).as_bit();\n\t\t\t\tauto dst = cell->getPort(ID::DST);\n\t\t\t\tif (!src.wire || !src.wire->port_input)\n\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\\n\", log_id(module), log_id(cell), log_signal(src));\n\t\t\t\tfor (const auto &c : dst.chunks())\n\t\t\t\t\tif (!c.wire->port_output)\n\t\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\\n\", log_id(module), log_id(cell), log_signal(dst));\n\t\t\t\tint rise_max = cell->getParam(ID::T_RISE_MAX).as_int();\n\t\t\t\tint fall_max = cell->getParam(ID::T_FALL_MAX).as_int();\n\t\t\t\tint max = std::max(rise_max,fall_max);\n\t\t\t\tif (max < 0) {\n\t\t\t\t\tlog_warning(\"Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\\n\", log_id(module), log_id(cell));\n\t\t\t\t\tmax = 0;\n\t\t\t\t}\n\t\t\t\tfor (const auto &d : dst) {\n\t\t\t\t\tauto r = t.arrival.insert(NameBit(d));\n\t\t\t\t\tauto &v = r.first->second;\n\t\t\t\t\tif (r.second || v.first < max) {\n\t\t\t\t\t\tv.first = max;\n\t\t\t\t\t\tv.second = NameBit(src);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (cell->type == ID($specrule)) {\n\t\t\t\tIdString type = cell->getParam(ID::TYPE).decode_string();\n\t\t\t\tif (type != ID($setup) && type != ID($setuphold))\n\t\t\t\t\tcontinue;\n\t\t\t\tauto src = cell->getPort(ID::SRC);\n\t\t\t\tauto dst = cell->getPort(ID::DST).as_bit();\n\t\t\t\tfor (const auto &c : src.chunks())\n\t\t\t\t\tif (!c.wire || !c.wire->port_input)\n\t\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\\n\", log_id(module), log_id(cell), log_signal(src));\n\t\t\t\tif (!dst.wire || !dst.wire->port_input)\n\t\t\t\t\tlog_error(\"Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\\n\", log_id(module), log_id(cell), log_signal(dst));\n\t\t\t\tint max = cell->getParam(ID::T_LIMIT_MAX).as_int();\n\t\t\t\tif (max < 0) {\n\t\t\t\t\tlog_warning(\"Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\\n\", log_id(module), log_id(cell));\n\t\t\t\t\tmax = 0;\n\t\t\t\t}\n\t\t\t\tfor (const auto &s : src) {\n\t\t\t\t\tauto r = t.required.insert(NameBit(s));\n\t\t\t\t\tauto &v = r.first->second;\n\t\t\t\t\tif (r.second || v.first < max) {\n\t\t\t\t\t\tv.first = max;\n\t\t\t\t\t\tv.second = NameBit(dst);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (auto port_name : module->ports) {\n\t\t\tauto wire = module->wire(port_name);\n\t\t\tif (wire->port_input) {\n\t\t\t\tt.has_inputs = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn t;\n\t}\n\n\tdecltype(data)::const_iterator find(RTLIL::IdString module_name) const { return data.find(module_name); }\n\tdecltype(data)::const_iterator end() const { return data.end(); }\n\tint count(RTLIL::IdString module_name) const { return data.count(module_name); }\n\tconst ModuleTiming& at(RTLIL::IdString module_name) const { return data.at(module_name); }\n};\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
191
191
|
"utils.h": "/*\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n// This file contains various c++ utility routines and helper classes that\n// do not depend on any other components of yosys (except stuff like log_*).\n\n#include \"kernel/yosys.h\"\n\n#ifndef UTILS_H\n#define UTILS_H\n\nYOSYS_NAMESPACE_BEGIN\n\n// ------------------------------------------------\n// A map-like container, but you can save and restore the state\n// ------------------------------------------------\n\ntemplate<typename Key, typename T>\nstruct stackmap\n{\nprivate:\n\tstd::vector<dict<Key, T*>> backup_state;\n\tdict<Key, T> current_state;\n\tstatic T empty_tuple;\n\npublic:\n\tstackmap() { }\n\tstackmap(const dict<Key, T> &other) : current_state(other) { }\n\n\ttemplate<typename Other>\n\tvoid operator=(const Other &other)\n\t{\n\t\tfor (auto &it : current_state)\n\t\t\tif (!backup_state.empty() && backup_state.back().count(it.first) == 0)\n\t\t\t\tbackup_state.back()[it.first] = new T(it.second);\n\t\tcurrent_state.clear();\n\n\t\tfor (auto &it : other)\n\t\t\tset(it.first, it.second);\n\t}\n\n\tbool has(const Key &k)\n\t{\n\t\treturn current_state.count(k) != 0;\n\t}\n\n\tvoid set(const Key &k, const T &v)\n\t{\n\t\tif (!backup_state.empty() && backup_state.back().count(k) == 0)\n\t\t\tbackup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;\n\t\tcurrent_state[k] = v;\n\t}\n\n\tvoid unset(const Key &k)\n\t{\n\t\tif (!backup_state.empty() && backup_state.back().count(k) == 0)\n\t\t\tbackup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;\n\t\tcurrent_state.erase(k);\n\t}\n\n\tconst T &get(const Key &k)\n\t{\n\t\tif (current_state.count(k) == 0)\n\t\t\treturn empty_tuple;\n\t\treturn current_state.at(k);\n\t}\n\n\tvoid reset(const Key &k)\n\t{\n\t\tfor (int i = GetSize(backup_state)-1; i >= 0; i--)\n\t\t\tif (backup_state[i].count(k) != 0) {\n\t\t\t\tif (backup_state[i].at(k) == nullptr)\n\t\t\t\t\tcurrent_state.erase(k);\n\t\t\t\telse\n\t\t\t\t\tcurrent_state[k] = *backup_state[i].at(k);\n\t\t\t\treturn;\n\t\t\t}\n\t\tcurrent_state.erase(k);\n\t}\n\n\tconst dict<Key, T> &stdmap()\n\t{\n\t\treturn current_state;\n\t}\n\n\tvoid save()\n\t{\n\t\tbackup_state.resize(backup_state.size()+1);\n\t}\n\n\tvoid restore()\n\t{\n\t\tlog_assert(!backup_state.empty());\n\t\tfor (auto &it : backup_state.back())\n\t\t\tif (it.second != nullptr) {\n\t\t\t\tcurrent_state[it.first] = *it.second;\n\t\t\t\tdelete it.second;\n\t\t\t} else\n\t\t\t\tcurrent_state.erase(it.first);\n\t\tbackup_state.pop_back();\n\t}\n\n\t~stackmap()\n\t{\n\t\twhile (!backup_state.empty())\n\t\t\trestore();\n\t}\n};\n\n\n// ------------------------------------------------\n// A simple class for topological sorting\n// ------------------------------------------------\n\ntemplate <typename T, typename C = std::less<T>> class TopoSort\n{\n public:\n\t// We use this ordering of the edges in the adjacency matrix for\n\t// exact compatibility with an older implementation.\n\tstruct IndirectCmp {\n IndirectCmp(const std::vector<T> &nodes) : node_cmp_(), nodes_(nodes) {}\n\t\tbool operator()(int a, int b) const\n\t\t{\n log_assert(static_cast<size_t>(a) < nodes_.size());\n\t\t\tlog_assert(static_cast<size_t>(b) < nodes_.size());\n\t\t\treturn node_cmp_(nodes_[a], nodes_[b]);\n\t\t}\n\t\tconst C node_cmp_;\n\t\tconst std::vector<T> &nodes_;\n\t};\n\n\tbool analyze_loops;\n\tstd::map<T, int, C> node_to_index;\n\tstd::vector<std::set<int, IndirectCmp>> edges;\n\tstd::vector<T> sorted;\n\tstd::set<std::vector<T>> loops;\n\n\tTopoSort() : indirect_cmp(nodes)\n\t{\n\t\tanalyze_loops = true;\n\t\tfound_loops = false;\n\t}\n\n\tint node(T n)\n\t{\n auto rv = node_to_index.emplace(n, static_cast<int>(nodes.size()));\n if (rv.second) {\n \t nodes.push_back(n);\n\t\t edges.push_back(std::set<int, IndirectCmp>(indirect_cmp));\n\t\t}\n\t\treturn rv.first->second;\n\t}\n\n\tvoid edge(int l_index, int r_index) { edges[r_index].insert(l_index); }\n\n\tvoid edge(T left, T right) { edge(node(left), node(right)); }\n\n\tbool has_node(const T &node) { return node_to_index.find(node) != node_to_index.end(); }\n\n\tbool sort()\n\t{\n\t\tlog_assert(GetSize(node_to_index) == GetSize(edges));\n\t\tlog_assert(GetSize(nodes) == GetSize(edges));\n\n\t\tloops.clear();\n\t\tsorted.clear();\n\t\tfound_loops = false;\n\n\t\tstd::vector<bool> marked_cells(edges.size(), false);\n\t\tstd::vector<bool> active_cells(edges.size(), false);\n\t\tstd::vector<int> active_stack;\n\t\tsorted.reserve(edges.size());\n\n\t\tfor (const auto &it : node_to_index)\n\t\t\tsort_worker(it.second, marked_cells, active_cells, active_stack);\n\n\t\tlog_assert(GetSize(sorted) == GetSize(nodes));\n\n\t\treturn !found_loops;\n\t}\n\n\t// Build the more expensive representation of edges for\n\t// a few passes that use it directly.\n\tstd::map<T, std::set<T, C>, C> get_database()\n\t{\n\t\tstd::map<T, std::set<T, C>, C> database;\n\t\tfor (size_t i = 0; i < nodes.size(); ++i) {\n\t\t\tstd::set<T, C> converted_edge_set;\n\t\t\tfor (int other_node : edges[i]) {\n\t\t\t\tconverted_edge_set.insert(nodes[other_node]);\n\t\t\t}\n\t\t\tdatabase.emplace(nodes[i], converted_edge_set);\n\t\t}\n\t\treturn database;\n\t}\n\n private:\n\tbool found_loops;\n\tstd::vector<T> nodes;\n\tconst IndirectCmp indirect_cmp;\n\n\tvoid sort_worker(const int root_index, std::vector<bool> &marked_cells, std::vector<bool> &active_cells, std::vector<int> &active_stack)\n\t{\n\t\tif (active_cells[root_index]) {\n\t\t\tfound_loops = true;\n\t\t\tif (analyze_loops) {\n\t\t\t\tstd::vector<T> loop;\n\t\t\t\tfor (int i = GetSize(active_stack) - 1; i >= 0; i--) {\n\t\t\t\t\tconst int index = active_stack[i];\n\t\t\t\t\tloop.push_back(nodes[index]);\n\t\t\t\t\tif (index == root_index)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tloops.insert(loop);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (marked_cells[root_index])\n\t\t\treturn;\n\n\t\tif (!edges[root_index].empty()) {\n\t\t\tif (analyze_loops)\n\t\t\t\tactive_stack.push_back(root_index);\n\t\t\tactive_cells[root_index] = true;\n\n\t\t\tfor (int left_n : edges[root_index])\n\t\t\t\tsort_worker(left_n, marked_cells, active_cells, active_stack);\n\n\t\t\tif (analyze_loops)\n\t\t\t\tactive_stack.pop_back();\n\t\t\tactive_cells[root_index] = false;\n\t\t}\n\n\t\tmarked_cells[root_index] = true;\n\t\tsorted.push_back(nodes[root_index]);\n\t}\n};\n\n// this class is used for implementing operator-> on iterators that return values rather than references\n// it's necessary because in C++ operator-> is called recursively until a raw pointer is obtained\ntemplate<class T>\nstruct arrow_proxy {\n\tT v;\n\texplicit arrow_proxy(T const & v) : v(v) {}\n\tT* operator->() { return &v; }\n};\n\ninline int ceil_log2(int x)\n{\n#if defined(__GNUC__)\n return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;\n#else\n\tif (x <= 0)\n\t\treturn 0;\n\tfor (int i = 0; i < 32; i++)\n\t\tif (((x-1) >> i) == 0)\n\t\t\treturn i;\n\tlog_abort();\n#endif\n}\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|
|
192
192
|
"yosys.h": "/* -*- c++ -*-\n * yosys -- Yosys Open SYnthesis Suite\n *\n * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n */\n\n\n// *** NOTE TO THE READER ***\n//\n// Maybe you have just opened this file in the hope to learn more about the\n// Yosys API. Let me congratulate you on this great decision! ;)\n//\n// If you want to know how the design is represented by Yosys in the memory,\n// you should read \"kernel/rtlil.h\".\n//\n// If you want to know how to register a command with Yosys, you could read\n// \"kernel/register.h\", but it would be easier to just look at a simple\n// example instead. A simple one would be \"passes/cmds/log.cc\".\n//\n// This header is very boring. It just defines some general things that\n// belong nowhere else and includes the interesting headers.\n\n\n#ifndef YOSYS_H\n#define YOSYS_H\n\n#include \"kernel/yosys_common.h\"\n\n#include \"kernel/log.h\"\n#include \"kernel/rtlil.h\"\n#include \"kernel/register.h\"\n\n#ifdef YOSYS_ENABLE_TCL\nstruct Tcl_Interp;\n#endif\n\nYOSYS_NAMESPACE_BEGIN\n\nvoid yosys_setup();\n\n#ifdef WITH_PYTHON\nbool yosys_already_setup();\n#endif\n\nvoid yosys_shutdown();\n\n#ifdef YOSYS_ENABLE_TCL\nTcl_Interp *yosys_get_tcl_interp();\n#endif\n\nextern RTLIL::Design *yosys_design;\n\nRTLIL::Design *yosys_get_design();\nstd::string proc_self_dirname();\nstd::string proc_share_dirname();\nstd::string proc_program_prefix();\nconst char *create_prompt(RTLIL::Design *design, int recursion_counter);\nstd::vector<std::string> glob_filename(const std::string &filename_pattern);\nvoid rewrite_filename(std::string &filename);\n\nvoid run_pass(std::string command, RTLIL::Design *design = nullptr);\nbool run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr, std::string *from_to_label = nullptr);\nvoid run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);\nvoid shell(RTLIL::Design *design);\n\n// journal of all input and output files read (for \"yosys -E\")\nextern std::set<std::string> yosys_input_files, yosys_output_files;\n\n// from kernel/version_*.o (cc source generated from Makefile)\nextern const char *yosys_version_str;\nconst char* yosys_maybe_version();\n\n// from passes/cmds/design.cc\nextern std::map<std::string, RTLIL::Design*> saved_designs;\nextern std::vector<RTLIL::Design*> pushed_designs;\n\n// from passes/cmds/pluginc.cc\nextern std::map<std::string, void*> loaded_plugins;\n#ifdef WITH_PYTHON\nextern std::map<std::string, void*> loaded_python_plugins;\n#endif\nextern std::map<std::string, std::string> loaded_plugin_aliases;\nvoid load_plugin(std::string filename, std::vector<std::string> aliases);\n\nextern std::string yosys_share_dirname;\nextern std::string yosys_abc_executable;\n\nYOSYS_NAMESPACE_END\n\n#endif\n",
|