Yosys工具概述

hegangben
2025-05-27 / 0 评论 / 1 阅读 / 正在检测是否收录...

对于一个新工具,以及学习源码,可以让ai帮忙分析。例如下面源码解读使用的kimi协助分析

一、基本使用
【从零开始学习VLSI设计(一)】Yosys工具概述-CSDN博客

1.安装

$ sudo apt-get install build-essential clang bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev
$ git clone https://github.com/YosysHQ/yosys.git
$ cd yosys
$ make
$ sudo make install

2.使用

//读取top.v
read_verilog top.v
//读取lib库
read_verilog -lib -specify +/xilinx/cells_sim.v
read_verilog -lib +/xilinx/cells_xtra.v
//检查层次连接
hierarchy -check -auto-top
//综合
synth_xilinx -flatten -nosrl -noclkbuf -nodsp
//显示连接关系图
show
//执行优化
opt

mb6307o9.png

二、项目结构
mb630fdv.png

Yosys 是一个开源的硬件描述语言(HDL)合成工具,它主要用于将 Verilog 或 VHDL 代码转换成门级网表(netlist),这些网表可以被发送到 ASIC 或 FPGA 的合成工具。Yosys 支持多种不同的后端目标,使其成为一个灵活的前端合成工具。

Yosys 的项目结构大致如下:

  1. 内核(Kernel)

    • 包含 Yosys 的核心功能,如内存管理、日志记录、基本数据类型和算法等。
  2. 前端(Frontends)

    • 用于读取和解析不同的硬件描述语言,如 Verilog、VHDL、SystemVerilog 等。
    • 将 HDL 代码转换成 Yosys 内部表示(AST - Abstract Syntax Tree)。
  3. 后端(Backends)

    • 用于将 Yosys 内部表示转换成不同的网表格式,如 EDIF、Bels、Netlists 等。
    • 支持多种不同的技术目标,如 Xilinx、Altera/Intel、Lattice 等。
  4. 优化(Optimizations)

    • 包含一系列优化传递(passes),用于改进和简化内部表示。
    • 优化包括但不限于常数传播、死代码消除、代数简化、查找表优化等。
  5. 库(Libraries)

    • 提供了一系列预定义的逻辑单元(如 LUTs、Flip-Flops、内存单元等)和宏单元。
    • 用于生成特定功能的标准单元和宏。
  6. 工具(Tools)

    • 提供了一系列用于调试、分析和转换设计的工具。
    • 包括查看器、测试生成器、等价性检查器等。
  7. 测试(Tests)

    • 包含了用于测试 Yosys 功能的自动化测试套件。
    • 用于确保 Yosys 的功能正确性和稳定性。
  8. 文档(Documentation)

    • 提供了用户手册、内部 API 文档和开发文档。
    • 帮助用户和开发者理解如何使用和贡献 Yosys。
  9. 脚本和示例(Scripts and Examples)

    • 提供了一系列示例和脚本,展示如何使用 Yosys 进行不同的合成和优化任务。
    • 用于教学和作为最佳实践的参考。
  10. 第三方集成(Third-party Integrations)

    • 包括与第三方工具链的集成,如 OpenSTA、ABC 等。
    • 提供了与这些工具的接口,以便在合成流程中使用它们的特定功能。

Yosys 的项目结构设计得既模块化又可扩展,使得它可以适应不同的用户需求和目标平台。开发者可以通过添加新的前端、后端或优化传递来扩展 Yosys 的功能。

三、内部数据结构

mb630oli.png

上图为yosys内部的逻辑门类型
mb630v5l.png
mb630zce.png

上图为yosys内部网表的主要数据结构

以下是 rtlil.h 和 rtlil.cc 文件中与 design->modules() 相关的一些关键点:

RTLIL::Design 类:

定义了 RTLIL::Design 类,它表示整个设计,包含所有模块和其他全局信息。
RTLIL::Design 类中有一个 modules 成员,它是一个 std::vector,存储设计中的所有模块。
RTLIL::Module 类:

定义了 RTLIL::Module 类,它表示设计中的一个模块,是设计的基本构建块。
RTLIL::Module 类包含成员如 wires、cells 等,用于存储模块内的线网和单元。
RTLIL::Wire 类:

定义了 RTLIL::Wire 类,它表示一个线网,用于连接模块内的信号。
RTLIL::Cell 类:

定义了 RTLIL::Cell 类,它表示一个单元,如逻辑门或存储元件。
RTLIL::SigSpec 类:

定义了 RTLIL::SigSpec 类,它表示一个信号规范,可以包含多个信号位或信号块。
RTLIL::SigBit 类:

定义了 RTLIL::SigBit 类,它表示一个信号位,可以是一个线网的一部分或一个常量值。
这些数据结构共同构成了 Yosys 处理和存储网表信息的基础设施。通过这些数据结构,Yosys 可以读取、修改和输出 RTL 级别的硬件设计。
RTLIL::Design

struct RTLIL::Design
{
    unsigned int hashidx_;
    unsigned int hash() const { return hashidx_; }
 
    pool<RTLIL::Monitor*> monitors;
    dict<std::string, std::string> scratchpad;
 
    bool flagBufferedNormalized = false;
    void bufNormalize(bool enable=true);
 
    int refcount_modules_;
    dict<RTLIL::IdString, RTLIL::Module*> modules_;
    std::vector<RTLIL::Binding*> bindings_;
 
    std::vector<AST::AstNode*> verilog_packages, verilog_globals;
    std::unique_ptr<define_map_t> verilog_defines;
 
    std::vector<RTLIL::Selection> selection_stack;
    dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
    std::string selected_active_module;
 
    Design();
    ~Design();
 
    RTLIL::ObjRange<RTLIL::Module*> modules();
    RTLIL::Module *module(const RTLIL::IdString &name);
    const RTLIL::Module *module(const RTLIL::IdString &name) const;
    RTLIL::Module *top_module();
 
    bool has(const RTLIL::IdString &id) const {
        return modules_.count(id) != 0;
    }
 
    void add(RTLIL::Module *module);
    void add(RTLIL::Binding *binding);
 
    RTLIL::Module *addModule(RTLIL::IdString name);
    void remove(RTLIL::Module *module);
    void rename(RTLIL::Module *module, RTLIL::IdString new_name);
 
    void scratchpad_unset(const std::string &varname);
 
    void scratchpad_set_int(const std::string &varname, int value);
    void scratchpad_set_bool(const std::string &varname, bool value);
    void scratchpad_set_string(const std::string &varname, std::string value);
 
    int scratchpad_get_int(const std::string &varname, int default_value = 0) const;
    bool scratchpad_get_bool(const std::string &varname, bool default_value = false) const;
    std::string scratchpad_get_string(const std::string &varname, const std::string &default_value = std::string()) const;
 
    void sort();
    void check();
    void optimize();
 
    bool selected_module(const RTLIL::IdString &mod_name) const;
    bool selected_whole_module(const RTLIL::IdString &mod_name) const;
    bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
 
    bool selected_module(RTLIL::Module *mod) const;
    bool selected_whole_module(RTLIL::Module *mod) const;
 
    RTLIL::Selection &selection() {
        return selection_stack.back();
    }
 
    const RTLIL::Selection &selection() const {
        return selection_stack.back();
    }
 
    bool full_selection() const {
        return selection_stack.back().full_selection;
    }
 
    template<typename T1> bool selected(T1 *module) const {
        return selected_module(module->name);
    }
 
    template<typename T1, typename T2> bool selected(T1 *module, T2 *member) const {
        return selected_member(module->name, member->name);
    }
 
    template<typename T1> void select(T1 *module) {
        if (selection_stack.size() > 0) {
            RTLIL::Selection &sel = selection_stack.back();
            sel.select(module);
        }
    }
 
    template<typename T1, typename T2> void select(T1 *module, T2 *member) {
        if (selection_stack.size() > 0) {
            RTLIL::Selection &sel = selection_stack.back();
            sel.select(module, member);
        }
    }
 
 
    std::vector<RTLIL::Module*> selected_modules() const;
    std::vector<RTLIL::Module*> selected_whole_modules() const;
    std::vector<RTLIL::Module*> selected_whole_modules_warn(bool include_wb = false) const;
#ifdef WITH_PYTHON
    static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
#endif
};

RTLIL::Model

struct RTLIL::Module : public RTLIL::AttrObject
{
    unsigned int hashidx_;
    unsigned int hash() const { return hashidx_; }
 
protected:
    void add(RTLIL::Wire *wire);
    void add(RTLIL::Cell *cell);
    void add(RTLIL::Process *process);
 
public:
    RTLIL::Design *design;
    pool<RTLIL::Monitor*> monitors;
 
    int refcount_wires_;
    int refcount_cells_;
 
    dict<RTLIL::IdString, RTLIL::Wire*> wires_;
    dict<RTLIL::IdString, RTLIL::Cell*> cells_;
 
    std::vector<RTLIL::SigSig>   connections_;
    std::vector<RTLIL::Binding*> bindings_;
 
    RTLIL::IdString name;
    idict<RTLIL::IdString> avail_parameters;
    dict<RTLIL::IdString, RTLIL::Const> parameter_default_values;
    dict<RTLIL::IdString, RTLIL::Memory*> memories;
    dict<RTLIL::IdString, RTLIL::Process*> processes;
 
    Module();
    virtual ~Module();
    virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail = false);
    virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
    virtual size_t count_id(const RTLIL::IdString& id);
    virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
    virtual bool reprocess_if_necessary(RTLIL::Design *design);
 
    virtual void sort();
    virtual void check();
    virtual void optimize();
    virtual void makeblackbox();
 
    void connect(const RTLIL::SigSig &conn);
    void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
    void new_connections(const std::vector<RTLIL::SigSig> &new_conn);
    const std::vector<RTLIL::SigSig> &connections() const;
 
    std::vector<RTLIL::IdString> ports;
    void fixup_ports();
 
    pool<pair<RTLIL::Cell*, RTLIL::IdString>> bufNormQueue;
    void bufNormalize();
 
    template<typename T> void rewrite_sigspecs(T &functor);
    template<typename T> void rewrite_sigspecs2(T &functor);
    void cloneInto(RTLIL::Module *new_mod) const;
    virtual RTLIL::Module *clone() const;
 
    bool has_memories() const;
    bool has_processes() const;
 
    bool has_memories_warn() const;
    bool has_processes_warn() const;
 
    std::vector<RTLIL::Wire*> selected_wires() const;
    std::vector<RTLIL::Cell*> selected_cells() const;
 
    template<typename T> bool selected(T *member) const {
        return design->selected_member(name, member->name);
    }
 
    RTLIL::Wire* wire(const RTLIL::IdString &id) {
        auto it = wires_.find(id);
        return it == wires_.end() ? nullptr : it->second;
    }
    RTLIL::Cell* cell(const RTLIL::IdString &id) {
        auto it = cells_.find(id);
        return it == cells_.end() ? nullptr : it->second;
    }
 
    const RTLIL::Wire* wire(const RTLIL::IdString &id) const{
        auto it = wires_.find(id);
        return it == wires_.end() ? nullptr : it->second;
    }
    const RTLIL::Cell* cell(const RTLIL::IdString &id) const {
        auto it = cells_.find(id);
        return it == cells_.end() ? nullptr : it->second;
    }
 
    RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); }
    RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
 
    void add(RTLIL::Binding *binding);
 
    // Removing wires is expensive. If you have to remove wires, remove them all at once.
    void remove(const pool<RTLIL::Wire*> &wires);
    void remove(RTLIL::Cell *cell);
    void remove(RTLIL::Process *process);
 
    void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
    void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
    void rename(RTLIL::IdString old_name, RTLIL::IdString new_name);
 
    void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2);
    void swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2);
 
    RTLIL::IdString uniquify(RTLIL::IdString name);
    RTLIL::IdString uniquify(RTLIL::IdString name, int &index);
 
    RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1);
    RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other);
 
    RTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type);
    RTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other);
 
    RTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other);
 
    RTLIL::Process *addProcess(RTLIL::IdString name);
    RTLIL::Process *addProcess(RTLIL::IdString name, const RTLIL::Process *other);
 
    // The add* methods create a cell and return the created cell. All signals must exist in advance.
 
    RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::Cell* addReduceAnd  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addReduceOr   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addReduceXor  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::Cell* addReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    // truncating division
    RTLIL::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 = "");
    // truncating modulo
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::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 = "");
 
    RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
    RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
 
    RTLIL::Cell* addBweqx  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
    RTLIL::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 = "");
 
    RTLIL::Cell* addSlice  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = "");
    RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
    RTLIL::Cell* addLut    (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = "");
    RTLIL::Cell* addTribuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_y, const std::string &src = "");
    RTLIL::Cell* addAssert (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = "");
    RTLIL::Cell* addAssume (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = "");
    RTLIL::Cell* addLive   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = "");
    RTLIL::Cell* addFair   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = "");
    RTLIL::Cell* addCover  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_en, const std::string &src = "");
    RTLIL::Cell* addEquiv  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
 
    RTLIL::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 = "");
    RTLIL::Cell* addFf    (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::Cell* addBufGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addNotGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addAndGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addNandGate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addOrGate     (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addNorGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addXorGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addXnorGate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addAndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::Cell* addOrnotGate  (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::Cell* addSrGate     (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 = "");
    RTLIL::Cell* addFfGate     (RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::Cell* addDffsrGate  (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 = "");
    RTLIL::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,
            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 = "");
    RTLIL::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,
            bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true, const std::string &src = "");
    RTLIL::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,
            bool arst_value = false, bool clk_polarity = true, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
    RTLIL::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,
            const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool aload_polarity = true, const std::string &src = "");
    RTLIL::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,
            const RTLIL::SigSpec &sig_ad, bool clk_polarity = true, bool en_polarity = true, bool aload_polarity = true, const std::string &src = "");
    RTLIL::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,
            bool srst_value = false, bool clk_polarity = true, bool srst_polarity = true, const std::string &src = "");
    RTLIL::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,
            bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
    RTLIL::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,
            bool srst_value = false, bool clk_polarity = true, bool en_polarity = true, bool srst_polarity = true, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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,
            bool arst_value = false, bool en_polarity = true, bool arst_polarity = true, const std::string &src = "");
    RTLIL::Cell* addDlatchsrGate  (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 = "");
 
    RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
 
    // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
 
    RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec And  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Or   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Xor  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Xnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec ReduceAnd  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec ReduceOr   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec ReduceXor  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec ReduceBool (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec Shl    (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Shr    (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Sshl   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Sshr   (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Shift  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Shiftx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec Lt  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Le  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Eq  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Ne  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Eqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Nex (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Ge  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Gt  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    // truncating division
    RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    // truncating modulo
    RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::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 = "");
 
    RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec LogicAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
    RTLIL::SigSpec LogicOr  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
 
    RTLIL::SigSpec Mux      (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
    RTLIL::SigSpec Pmux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
    RTLIL::SigSpec Bmux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
    RTLIL::SigSpec Demux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
 
    RTLIL::SigSpec Bweqx      (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = "");
    RTLIL::SigSpec Bwmux      (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
 
    RTLIL::SigBit BufGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
    RTLIL::SigBit NotGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
    RTLIL::SigBit AndGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit NandGate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit OrGate     (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit NorGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit XorGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit XnorGate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit AndnotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit OrnotGate  (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
    RTLIL::SigBit MuxGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = "");
    RTLIL::SigBit NmuxGate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_s, const std::string &src = "");
    RTLIL::SigBit Aoi3Gate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = "");
    RTLIL::SigBit Oai3Gate   (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_c, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::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 = "");
 
    RTLIL::SigSpec Anyconst  (RTLIL::IdString name, int width = 1, const std::string &src = "");
    RTLIL::SigSpec Anyseq    (RTLIL::IdString name, int width = 1, const std::string &src = "");
    RTLIL::SigSpec Allconst  (RTLIL::IdString name, int width = 1, const std::string &src = "");
    RTLIL::SigSpec Allseq    (RTLIL::IdString name, int width = 1, const std::string &src = "");
    RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = "");
 
    RTLIL::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 = "");
    RTLIL::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 = "");
    RTLIL::SigSpec GetTag          (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = "");
    RTLIL::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 = "");
    RTLIL::SigSpec OriginalTag     (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = "");
    RTLIL::SigSpec FutureFF        (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = "");
 
#ifdef WITH_PYTHON
    static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);
#endif
};

RTLIL::CELL

struct RTLIL::Cell : public RTLIL::AttrObject
{
    unsigned int hashidx_;
    unsigned int hash() const { return hashidx_; }
 
protected:
    // use module->addCell() and module->remove() to create or destroy cells
    friend struct RTLIL::Module;
    Cell();
    ~Cell();
 
public:
    // do not simply copy cells
    Cell(RTLIL::Cell &other) = delete;
    void operator=(RTLIL::Cell &other) = delete;
 
    RTLIL::Module *module;
    RTLIL::IdString name;
    RTLIL::IdString type;
    dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
    dict<RTLIL::IdString, RTLIL::Const> parameters;
 
    // access cell ports
    bool hasPort(const RTLIL::IdString &portname) const;
    void unsetPort(const RTLIL::IdString &portname);
    void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);
    const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const;
    const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
 
    // information about cell ports
    bool known() const;
    bool input(const RTLIL::IdString &portname) const;
    bool output(const RTLIL::IdString &portname) const;
 
    // access cell parameters
    bool hasParam(const RTLIL::IdString &paramname) const;
    void unsetParam(const RTLIL::IdString &paramname);
    void setParam(const RTLIL::IdString &paramname, RTLIL::Const value);
    const RTLIL::Const &getParam(const RTLIL::IdString &paramname) const;
 
    void sort();
    void check();
    void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
 
    bool has_keep_attr() const {
        return get_bool_attribute(ID::keep) || (module && module->design && module->design->module(type) &&
                module->design->module(type)->get_bool_attribute(ID::keep));
    }
 
    template<typename T> void rewrite_sigspecs(T &functor);
    template<typename T> void rewrite_sigspecs2(T &functor);
 
#ifdef WITH_PYTHON
    static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
#endif
 
    bool has_memid() const;
    bool is_mem_cell() const;
};

RTLIL::Wire

struct RTLIL::Wire : public RTLIL::AttrObject
{
    unsigned int hashidx_;
    unsigned int hash() const { return hashidx_; }
 
protected:
    // use module->addWire() and module->remove() to create or destroy wires
    friend struct RTLIL::Module;
    Wire();
    ~Wire();
 
    friend struct RTLIL::Design;
    friend struct RTLIL::Cell;
    friend void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
    RTLIL::Cell *driverCell_ = nullptr;
    RTLIL::IdString driverPort_;
 
public:
    // do not simply copy wires
    Wire(RTLIL::Wire &other) = delete;
    void operator=(RTLIL::Wire &other) = delete;
 
    RTLIL::Module *module;
    RTLIL::IdString name;
    int width, start_offset, port_id;
    bool port_input, port_output, upto, is_signed;
 
    RTLIL::Cell *driverCell() const    { log_assert(driverCell_); return driverCell_; };
    RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };
 
#ifdef WITH_PYTHON
    static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
#endif
};

四、核心代码功能
1.passes/opt
opt.cc主要调用如下功能:

1opt_expr

执行表达式优化,包括常量折叠和简单表达式重写。

2opt_merge

合并相似的逻辑单元

3opt_muxtree

优化多路复用器树。

4opt_reduce

简化逻辑表达式。

5opt_share

共享逻辑单元

6

opt_dff

优化触发器

7opt_clean

清理设计,移除不必要的元素。

  1. passes/proc
    proc.cc依次调用其他功能:

1proc_clean

清理设计,移除不必要的元素,如未使用的线网和模块。

2proc_rmdead

删除死代码,即那些不驱动任何输出的线网或模块,以简化设计

3proc_prune

4proc_init

初始化,为触发器(如 D 触发器)分配初始值,确保设计在复位后有确定的状态。

5proc_arst

处理异步复位信号,确保设计能够正确处理复位逻辑。

6proc_rom

处理只读存储器(ROM),将其转换为等效的逻辑或存储器结构。

7proc_mux

处理多路复用器,将条件语句转换为多路复用逻辑。

8proc_dlatch

处理锁存器,将设计中的锁存器转换为等效的逻辑结构。

9proc_dff

将过程(processes)中的触发器(flip-flops)提取出来并转换为 D 触发器单元的代码

10proc_memwr

处理存储器写入,优化存储器的写入操作,以提高效率和减少资源消耗。

11opt_expr

进行常量折叠和简单表达式重写

3.opt/opt_ffinv.cc

/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2022  Marcelina Kościelnicka <mwk@0x04.net>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */
 
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
#include "kernel/ffinit.h"
#include "kernel/ff.h"
 
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
//用于处理逻辑电路中的触发器(Flip-Flops, FFs)和逻辑门(如 LUTs 和 非门)的优化
struct OptFfInvWorker
{
    int count = 0;
    RTLIL::Module *module;
    ModIndex index;
    FfInitVals initvals;
 
    // Case 1:
    // - FF is driven by inverter
    // - ... which has no other users
    // - all users of FF are LUTs
    //如果触发器的 D 输入被一个没有其他使用者的非门驱动,并且所有使用该触发器的逻辑都是查找表(LUTs),则将非门推到触发器的另一边
    bool push_d_inv(FfData &ff) {
        //它检查触发器的宽度是否为1
        log_assert(ff.width == 1);
        //检查触发器的 D 输入是否是模块的输入
        if (index.query_is_input(ff.sig_d))
            return false;
        //检查触发器的 D 输入是否是模块的输出
        if (index.query_is_output(ff.sig_d))
            return false;
        //查询 D 输入连接到的所有端口。如果连接的端口数量不是2,函数返回 false
        auto d_ports = index.query_ports(ff.sig_d);
        if (d_ports.size() != 2)
            return false;
        Cell *d_inv = nullptr;
        //遍历 D 输入连接的端口,识别连接到非门($not 或 $_NOT_)或查找表($lut)。如果找到非门,将其存储在 d_inv 变量中。如果找到其他类型的单元,函数返回 false。
        for (auto &port: d_ports) {
            if (port.cell == ff.cell && port.port == ID::D)
                continue;
            if (port.port != ID::Y)
                return false;
            //识别连接到非门($not 或 $_NOT_)
            if (port.cell->type.in(ID($not), ID($_NOT_))) {
                // OK
            } 
            //识别连接到或查找表($lut)
            else if (port.cell->type.in(ID($lut))) {
                if (port.cell->getParam(ID::WIDTH) != 1)
                    return false;
                if (port.cell->getParam(ID::LUT).as_int() != 1)
                    return false;
            } else {
                return false;
            }
            log_assert(d_inv == nullptr);
            d_inv = port.cell;
        }
        if (!d_inv) return false;
        //检查触发器的 Q 输出是否是模块的输出。如果是,函数返回 false
        if (index.query_is_output(ff.sig_q))
            return false;
        //查询 Q 输出连接到的所有端口。遍历这些端口,识别连接到非门或查找表的单元,并将它们存储在 q_luts 集合中
        auto q_ports = index.query_ports(ff.sig_q);
        pool<Cell *> q_luts;
        for (auto &port: q_ports) {
            if (port.cell == ff.cell && port.port == ID::Q)
                continue;
            if (port.cell == d_inv)
                return false;
            if (port.port != ID::A)
                return false;
            if (!port.cell->type.in(ID($not), ID($_NOT_), ID($lut)))
                return false;
            q_luts.insert(port.cell);
        }
        //翻转触发器的复位位
        ff.flip_rst_bits({0});
        //将触发器的 D 输入信号更新为非门的输入信号,直接扔掉反向器
        ff.sig_d = d_inv->getPort(ID::A);
        //遍历 q_luts 集合中的每个查找表(LUT),根据需要翻转 LUT 的掩码。
        //如果 LUT 的宽度为1 且新掩码为2,则将 LUT 的输出直接连接到触发器的 Q 输出,并从模块中移除 LUT。否则,更新 LUT 的掩码
        for (Cell *lut: q_luts) {
            if (lut->type == ID($lut)) {
                int flip_mask = 0;
                SigSpec sig_a = lut->getPort(ID::A);//输入
                for (int i = 0; i < GetSize(sig_a); i++) {
                    //判断lut和inv之间是否有连线
                    if (index.sigmap(sig_a[i]) == index.sigmap(ff.sig_q[0])) {
                        flip_mask |= 1 << i;
                    }
                }
                Const mask = lut->getParam(ID::LUT);
                Const new_mask;
                for (int j = 0; j < (1 << GetSize(sig_a)); j++) {
                    new_mask.bits().push_back(mask[j ^ flip_mask]);
                }
                if (GetSize(sig_a) == 1 && new_mask.as_int() == 2) {
                    module->connect(lut->getPort(ID::Y), ff.sig_q);
                    module->remove(lut);
                } else {
                    lut->setParam(ID::LUT, new_mask);
                }
            } else {
                // it was an inverter
                //将lut的Y输出口,连到inv的输出口
                module->connect(lut->getPort(ID::Y), ff.sig_q);
                //移除lut单元
                module->remove(lut);
            }
        }
        //使用 ff.emit() 重新生成触发器
        ff.emit();
        return true;
    }
 
    // Case 2:
    // - FF is driven by LUT
    // - ... which has no other users
    // - FF has one user
    // - ... which is an inverter
    //如果触发器的 Q 输出被一个没有其他使用者的查找表驱动,并且该查找表只有一个使用者(一个非门),则将非门推到触发器的另一边
    bool push_q_inv(FfData &ff) {
        if (index.query_is_input(ff.sig_d))
            return false;
        if (index.query_is_output(ff.sig_d))
            return false;
 
        Cell *d_lut = nullptr;
        auto d_ports = index.query_ports(ff.sig_d);
        if (d_ports.size() != 2)
            return false;
        for (auto &port: d_ports) {
            if (port.cell == ff.cell && port.port == ID::D)
                continue;
            if (port.port != ID::Y)
                return false;
            if (!port.cell->type.in(ID($not), ID($_NOT_), ID($lut)))
                return false;
            log_assert(d_lut == nullptr);
            d_lut = port.cell;
        }
        if (!d_lut) return false;
 
        if (index.query_is_output(ff.sig_q))
            return false;
        auto q_ports = index.query_ports(ff.sig_q);
        if (q_ports.size() != 2)
            return false;
        Cell *q_inv = nullptr;
        for (auto &port: q_ports) {
            if (port.cell == ff.cell && port.port == ID::Q)
                continue;
            if (port.cell == d_lut)
                return false;
            if (port.port != ID::A)
                return false;
            if (port.cell->type.in(ID($not), ID($_NOT_))) {
                // OK
            } else if (port.cell->type.in(ID($lut))) {
                if (port.cell->getParam(ID::WIDTH) != 1)
                    return false;
                if (port.cell->getParam(ID::LUT).as_int() != 1)
                    return false;
            } else {
                return false;
            }
            log_assert(q_inv == nullptr);
            q_inv = port.cell;
        }
        if (!q_inv) return false;
 
        ff.flip_rst_bits({0});
        ff.sig_q = q_inv->getPort(ID::Y);
        module->remove(q_inv);
 
        if (d_lut->type == ID($lut)) {
            Const mask = d_lut->getParam(ID::LUT);
            Const new_mask;
            for (int i = 0; i < GetSize(mask); i++) {
                if (mask[i] == State::S0)
                    new_mask.bits().push_back(State::S1);
                else
                    new_mask.bits().push_back(State::S0);
            }
            d_lut->setParam(ID::LUT, new_mask);
            if (d_lut->getParam(ID::WIDTH) == 1 && new_mask.as_int() == 2) {
                module->connect(ff.sig_d, d_lut->getPort(ID::A));
                module->remove(d_lut);
            }
        } else {
            // it was an inverter
            module->connect(ff.sig_d, d_lut->getPort(ID::A));
            module->remove(d_lut);
        }
 
        ff.emit();
        return true;
    }
 
    OptFfInvWorker(RTLIL::Module *module) :
        module(module), index(module), initvals(&index.sigmap, module)
    {
        log("Discovering LUTs.\n");
 
        std::vector<Cell *> ffs;
 
        for (Cell *cell : module->selected_cells())//所有cells
            //检查当前单元是否是内置的触发器类型,如果是,则将其添加到 ffs 向量中
            if (RTLIL::builtin_ff_cell_types().count(cell->type))
                ffs.push_back(cell);
        //遍历所有FF
        for (Cell *cell : ffs) {
            FfData ff(&initvals, cell);
            //果触发器有设置/复位(set/reset)功能,则跳过当前触发器
            if (ff.has_sr)
                continue;
            //如果触发器没有时钟信号,则跳过当前触发器
            if (!ff.has_clk)
                continue;
            //如果触发器有异步加载功能,则跳过当前触发器。
            if (ff.has_aload)
                continue;
            //如果触发器的宽度不是1(即不是单比特触发器),则跳过当前触发器。
            if (ff.width != 1)
                continue;
 
            //尝试将触发器的数据输入(D)端的反相器推入触发器内部,如果成功,则增加 count 计数器
            if (push_d_inv(ff)) {
                count++;
            } else if (push_q_inv(ff)) {
                count++;
            }
        }
    }
};
 
struct OptFfInvPass : public Pass {
    OptFfInvPass() : Pass("opt_ffinv", "push inverters through FFs") 
    void help() override
    {
        //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
        log("\n");
        log("    opt_ffinv [selection]\n");
        log("\n");
        //当 Inverters 可以合并到另一侧的 LUT 时,此通道将 inverters 推到 FF 的另一侧
        log("This pass pushes inverters to the other side of a FF when they can be merged\n");
        log("into LUTs on the other side.\n");
        log("\n");
    }
    //用于遍历设计中的模块并应用优化
    void execute(std::vector<std::string> args, RTLIL::Design *design) override
    {
        log_header(design, "Executing OPT_FFINV pass (push inverters through FFs).\n");
 
        size_t argidx;
        //命令参数个数
        for (argidx = 1; argidx < args.size(); argidx++)
        {
            break;
        }
        //处理额外的命令行参数。
        extra_args(args, argidx, design);
 
        int total_count = 0;
        for (auto module : design->selected_modules())
        {
            //对每个模块进行opt_ffinv处理
            OptFfInvWorker worker(module);
            //处理个数
            total_count += worker.count;
        }
        if (total_count)
            //设置一个布尔值,表明优化操作确实做了一些事情
            design->scratchpad_set_bool("opt.did_something", true);
        log("Pushed %d inverters.\n", total_count);
    }
} OptFfInvPass;
 
PRIVATE_NAMESPACE_END
五、新增功能插件
在使用yosys工具时,如果想新增一些自己的功能,应该怎么办呢?例如要新增一个优化功能,有两种思路,一种是在已有的源码文件中,找一个地方单独写这部分优化代码,在执行源码功能时,就会顺带执行该部分的优化代码。除此之外,还可以自己编写插件,将自己的功能包装成一个单独的工具,这个yosys里给留了具体实施的空间。

例如opt_expr就是一个用于优化的功能插件,自己可以写一个opt_inv.cc的插件,然后编写内容,如下:

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
 
USING_YOSYS_NAMESPACE
 
struct MyOptPass : public Pass {
    //插件命令为opt_inv
    MyOptPass() : Pass("opt_inv", "my custom optimization pass") 
    void execute(std::vector<std::string> args, RTLIL::Design *design) override {
        // 您的优化逻辑
    }
} MyOptPass;

————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                    

原文链接:https://blog.csdn.net/ljjjjjjjjjjj/article/details/144077123

在 Yosys 中检测组合逻辑环(Combinational Loop)可以通过以下步骤实现。组合逻辑环通常指电路中存在无寄存器隔离的反馈路径,可能导致不可预测的振荡或亚稳态问题。以下是详细操作流程:

  1. 基本流程:使用 check 命令
    Yosys 内置的 check 命令可以检测组合环,但需要先将设计转换为逻辑网表。
    tcl复制

    读取 RTL 文件(例如 Verilog)read_verilog design.v

    转换为逻辑网表(综合并展开进程)synth -noabcproc; opt; clean# 检查组合环check -assert # 检测组合环和其他潜在问题

    输出示例:

    log复制


    Checking module \top... Found combinational loop in logic: Signal: \a -> \b -> \c -> \aERROR: Found 1 combinational loops!


    说明:check 命令会自动报告组合环路径,但可能需要结合其他步骤准确定位。

  2. 使用 show 命令可视化环路
    通过生成电路图定位环路的具体路径。
    tcl复制

    读取并处理设计read_verilog design.v

    hierarchy -checkproc; opt; clean# 生成逻辑图并导出为 .dot 文件show -prefix comb_loop -format dot# 使用 Graphviz 查看环路system "xdot comb_loop.dot"
    说明:
    oshow 命令生成电路的图形化表示(需要安装 Graphviz)。
    o在生成的 .dot 文件中,反馈路径会以环路形式呈现。

  3. 详细分析:通过 lsg 命令生成逻辑结构图
    Yosys 的 lsg(Logic Signal Graph)命令可以生成信号依赖图,帮助分析环路。
    tcl复制
    read_verilog design.vproc; opt; clean# 生成逻辑信号图lsg -output comb_loop.log

    检查生成的日志文件!cat comb_loop.log | grep "loop"

    输出示例:

    log复制


    Found loop: a -> b -> c -> a


    说明:lsg 会列出所有信号依赖关系,从中筛选环路。

  4. 使用 Formal Verification 检测环路
    通过形式化验证工具(如 SymbiYosys)强制检测组合环路。
    步骤 1:创建验证脚本 comb_loop.sby
    ini复制
    [options]mode prove
    [engines]smtbmc
    [script]read_verilog -formal design.v
    prep -top top_module

    断言不存在组合环assert -no-loop

    [files]design.v
    步骤 2:运行验证
    bash复制
    sby -f comb_loop.sby
    说明:若存在组合环,形式化引擎会返回反例路径。

  5. 组合环修复示例
    假设检测到环路路径 a -> b -> c -> a,需修改 RTL 代码打破环路。
    原始代码(存在环路) :
    verilog复制
    module top (input x, output y); wire a, b, c; assign a = x | c; assign b = a & ~c; assign c = b; assign y = c;endmodule
    修复代码(插入寄存器) :
    verilog复制
    module top (input clk, input x, output reg y); wire a, b, c; reg c_reg; always @(posedge clk) begin c_reg <= b; // 插入寄存器打破环路 end assign a = x | c_reg; assign b = a & ~c_reg; assign c = b; assign y = c_reg;endmodule
  6. 进阶调试:自定义组合环检测脚本
    编写 Tcl 脚本遍历所有信号依赖关系,手动检测环路。

    read_verilog design.vproc;
    opt;
    clean
    # 遍历所有信号
    foreach net [lsort -unique [list_nets]] 
    {
      set drivers [get_drivers $net]  
      set loads [get_loads $net]  
      if {[llength $drivers] > 0 && [llength $loads] > 0} 
      {    
     puts "Signal: $net"    
     puts "  Drivers: $drivers"    
     puts "  Loads: $loads"    
     # 检查驱动和负载是否形成环路    
     if {[regexp $net $drivers] || [regexp $net $loads]}
     {      
       puts "ERROR: Combinational loop detected on signal $net!"    
       }
      }
    }

常见问题解决
误报/漏报:check 命令可能因未综合完整逻辑而漏报,建议先运行 synth。
复杂环路:多级环路需通过 show 或 lsg 图形化分析。
工具依赖:可视化需安装 Graphviz,验证需 SymbiYosys。
通过上述方法,可以高效定位和修复 RTL 设计中的组合逻辑环问题。

0

评论 (0)

取消