yosys 是否保留端口顺序?
Does yosys preserve port ordering?
yosys 是否保留 modules/cells 的 input/output 端口的顺序?当它是 read/written 时,RTL 中的顺序是否保证与 verilog 的顺序相匹配? yosys 会更改顺序吗"unexpectedly"?
Yosys 确实存储了模块端口在 RTLIL::Wire::port_id
中声明的顺序。实例上的位置参数重命名为 , , , ...
。 hierarchy
命令然后使用 port_id
属性 在设计细化期间正确重命名单元实例上的端口。
将模块编写为 verilog 文件时,线路 port_id
属性 用于确定端口在模块中声明的顺序 header.
所以是的:Yosys 确实保留了模块 input/output 端口的顺序并解析了单元实例中位置参数的名称。
当 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正在使用位置参数(模块端口由参数的顺序决定)。
yosys 是否保留 modules/cells 的 input/output 端口的顺序?当它是 read/written 时,RTL 中的顺序是否保证与 verilog 的顺序相匹配? yosys 会更改顺序吗"unexpectedly"?
Yosys 确实存储了模块端口在 RTLIL::Wire::port_id
中声明的顺序。实例上的位置参数重命名为 , , , ...
。 hierarchy
命令然后使用 port_id
属性 在设计细化期间正确重命名单元实例上的端口。
将模块编写为 verilog 文件时,线路 port_id
属性 用于确定端口在模块中声明的顺序 header.
所以是的:Yosys 确实保留了模块 input/output 端口的顺序并解析了单元实例中位置参数的名称。
当 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正在使用位置参数(模块端口由参数的顺序决定)。