【问题标题】:Does yosys preserve port ordering?yosys 是否保留端口顺序?
【发布时间】:2015-08-21 19:36:16
【问题描述】:

yosys 是否保留模块/单元的输入/输出端口的顺序? RTL 中的顺序是否保证在读/写时与 verilog 的顺序相匹配? yosys 是否会“意外”更改订单?

【问题讨论】:

    标签: yosys


    【解决方案1】:

    Yosys 确实存储了RTLIL::Wire::port_id 中声明模块端口的顺序。实例上的位置参数重命名为$1, $2, $3, ...。然后hierarchy 命令使用port_id 属性在设计细化期间正确重命名单元实例上的端口。

    将模块编写为 verilog 文件时,线 port_id 属性用于确定在模块头中声明端口的顺序。

    所以是的:Yosys 确实保留了模块输入/输出端口的顺序,并解析了单元实例中位置参数的名称。

    hierarchy 未运行或单元类型的声明不可用时,这些单元实例中的位置参数不会被解析,并且在将设计编写为verilog 文件时它们再次作为位置参数转储。

    编辑: 回复评论:以下示例插件(portsigdemo.cc)演示了如何创建一个包含所有模块端口/单元端口的 SigSpec,按照相应端口声明的顺序模块:

    #include "kernel/yosys.h"
    #include "kernel/consteval.h"
    
    USING_YOSYS_NAMESPACE
    PRIVATE_NAMESPACE_BEGIN
    
    SigSpec get_portsig(Module *module, string direction, Cell *cell = nullptr)
    {
        if (cell)
            log_assert(cell->type == module->name);
    
        SigSpec sig;
        dict<int, SigSpec> sigs;
    
        for (auto wire : module->wires())
        {
            bool selected = false;
    
            if (direction == "in")
                selected = wire->port_input;
            else if (direction == "out")
                selected = wire->port_output;
            else
                log_abort();
    
            if (selected) {
                if (cell) {
                    if (cell->hasPort(wire->name))
                        sigs[wire->port_id] = cell->getPort(wire->name);
                    else if (cell->hasPort(stringf("$%d", wire->port_id)))
                        sigs[wire->port_id] = cell->getPort(stringf("$%d", wire->port_id));
                    else
                        log_abort();
                } else {
                    sigs[wire->port_id] = wire;
                }
            }
        }
    
        sigs.sort();
        for (auto &it : sigs)
            sig.append(it.second);
    
        return sig;
    }
    
    struct PortsigDemoPass : public Pass
    {
        PortsigDemoPass():Pass("portsigdemo") { }
    
        virtual void execute(vector < string >, Design * design)
        {
            for (auto module : design->modules())
            {
                log("Module %s:\n", log_id(module));
                log("  Inputs: %s\n", log_signal(get_portsig(module, "in")));
                log("  Outputs: %s\n", log_signal(get_portsig(module, "out")));
    
                for (auto cell : module->cells())
                {
                    auto cell_type_mod = cell->module->design->module(cell->type);
                    if (cell_type_mod) {
                        log("  Cell %s (%s):\n", log_id(cell), log_id(cell->type));
                        log("    Inputs: %s\n", log_signal(get_portsig(cell_type_mod, "in", cell)));
                        log("    Outputs: %s\n", log_signal(get_portsig(cell_type_mod, "out", cell)));
                    }
                }
            }
        }
    } PortsigDemoPass;
    
    PRIVATE_NAMESPACE_END
    

    示例用法:

    $ cat > portsigdemo.v << EOT
    module mod1 (input [3:0] A, B, output [3:0] Y);
      mod2 mod2_inst0 (.P(A[0]), .Q(B[0]), .X(Y[0]));
      mod2 mod2_inst1 (.P(B[1]), .Q(A[1]), .X(Y[1]));
      mod2 mod2_inst2 (A[2], B[2], Y[2]);
      mod2 mod2_inst3 (B[3], A[3], Y[3]);
    endmodule
    
    module mod2 (input P, Q, output X);
      assign X = P ^ Q;
    endmodule
    EOT
    
    $ yosys-config --build portsigdemo.so portsigdemo.cc
    $ yosys -m portsigdemo.so -p portsigdemo portsigdemo.v
    ...
    -- Running command `portsigdemo' --
    Module mod2:
      Inputs: { \Q \P }
      Outputs: \X
    Module mod1:
      Inputs: { \B \A }
      Outputs: \Y
      Cell mod2_inst3 (mod2):
        Inputs: { \A [3] \B [3] }
        Outputs: \Y [3]
      Cell mod2_inst2 (mod2):
        Inputs: { \B [2] \A [2] }
        Outputs: \Y [2]
      Cell mod2_inst1 (mod2):
        Inputs: { \A [1] \B [1] }
        Outputs: \Y [1]
      Cell mod2_inst0 (mod2):
        Inputs: { \B [0] \A [0] }
        Outputs: \Y [0]
    

    PS:在portsigdemo.v 中,单元(模块实例)mod1.mod2_inst0 和 mod1.mod2_inst1 使用命名参数(模块端口的名称已给出),单元 mod1.mod2_inst2 和 mod1.mod2_inst3 使用位置参数(模块端口由参数的顺序决定)。

    【讨论】:

    • “实例的位置参数”是什么意思?除了 port_id 的存在之外,我不理解这个答案的大部分内容。我真正想做的是为所有单元格输入获取一个 SigSpec,为所有单元格输出获取一个 SigSpec,它们根据 Verilog 定义进行排序。
    • @CliforVienna 非常感谢,我现在明白了,但这似乎仍然不适用于内置单元格类型。为内置单元定义的端口在哪里,它们有关联的顺序吗?
    • @JeremySalwen 你是对的:内置单元类型没有关联的端口顺序,因为内置单元类型的端口总是按名称引用。
    猜你喜欢
    • 1970-01-01
    • 2010-10-14
    • 2017-03-04
    • 2021-03-04
    • 2016-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多