将 x(无关)分配给组合输出的寄存器复位值以提高面积效率
Assigning x (dont care) to a register reset value or combinatorical output to improve area efficiency
我的问题是关于 FPGA 设计的——如果我的设计中有一些我不关心它们的复位值是多少的寄存器,我可以将复位值设置为 x 吗?这会提高面积效率吗(合成器是否能够利用它并以更有效的方式生成设计?)
例如,
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
reg_1 <= 'x
end
...
end
编辑:
另一个类似主题的问题——假设我有一个状态机,例如我不关心某些输出在某些状态下会是什么——将它们设置为“x”会提高面积效率吗?
例如,如果我有一个具有两个状态 STATE_1、STATE_2 和两个输出的 fsm,综合工具将能够利用以下代码:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = x;
end
STATE_2:begin
out_1 = x;
out_2 = 0;
end
end
比这个更好:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = 0;
end
STATE_2:begin
out_1 = 0;
out_2 = 0;
end
end
(假设我不关心 STATE_1 中的 out_2 和 STATE_2 中的 out_1 是什么)。
谢谢
在顺序逻辑中使用 'x
是的,在 Verilog 方面,您可以使用此语法。但是,在您的特定示例中,这样做并没有真正意义,您可以认为这是一种糟糕的编码实践。除了显式分配 'x
,您还可以省略异步重置。
以下两个进程将综合到同一个触发器。我个人会推荐使用后一种风格。
// Assigning 'x to tell synthesis tool that there is no reset value
always @(posedge clk or negedge reset_n)
if(~reset_n)
reg_1 <= 'x;
else
reg_1 <= reg_1_next;
// Omitting the asynchronous reset from the sensitivity list to tell
// synthesis tool that there is no reset
always @(posedge clk)
reg_1 <= reg_1_next;
一般来说:如果您有不同的变量,这些变量必须是可重置的或不可重置的,您应该将它们的赋值分成不同的 always
块。这通常会使您的代码更具可读性。请参阅以下示例:
// Do NOT do this
always @(posedge clk or negedge reset_n)
if(~reset_n)
begin
vld <= 1'b0;
reg_1 <= 'x;
end
else
begin
vld <= vld_next;
reg_1 <= reg_1_next;
end
// Do this
always @(posedge clk or negedge reset_n)
if(~reset_n)
vld <= 1'b0;
else
vld <= vld_next;
always @(posedge clk)
reg_1 <= reg_1_next;
奖金
话虽如此,在某些情况下,在复位条件中分配 'x
以告诉综合工具 不 为特定的生成可复位触发器是有意义的变量。请看看这个答案:
让我们根据这个答案创建一个示例。假设您有一个包含 1 个有效信号 (vld
) 和 2 个数据信号(data_a
和 data_b
)的结构。该数据仅在vld
为1'b1
时有效。换句话说,我们可以通过只重置vld
而不重置data_a
和data_b
来节省空间。
现在,我们想充分发挥结构的潜力,并简单地分配完整的结构而不是单独的成员(参见 struct_example_q <= struct_example_next;
)。这意味着我们 不能 将这个 always
-block 分成两个单独的进程(就像我之前推荐的那样)。在这种情况下,我们必须明确告诉综合工具不要重置数据信号。
查看下面的代码:
typedef struct {
logic vld;
logic [31:0] data_a;
logic [31:0] data_b;
} struct_example_t;
struct_example_t struct_example_next;
struct_example_t struct_example_q;
always @(posedge clk or negedge reset_n)
if (!reset_n)
begin
/**
* Only reset the valid-bit
* We could use '{default:'x} to simplify this even further
**/
struct_example_q.data_a <= 'x;
struct_example_q.data_b <= 'x;
struct_example_q.vld <= 1'b0;
end
else
begin
struct_example_q <= struct_example_next;
end
在组合逻辑中使用'x
让我们先看看您的 RTL:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = x;
end
STATE_2:begin
out_1 = x;
out_2 = 0;
end
end
我想指出,这并不是最好的例子。假设 FSM 是满的——即 STATE_1
和 STATE_2
是仅有的两个状态 state
可以采用——你将使用下面的代码实现完全相同的效果,假设你不这样做无论如何,关于其他州的 out_1
和 out_2
的情况。
always_comb begin
out_1 = 1;
out_2 = 0;
end
现在,为了示例起见,假设我们无法重写它。在这种情况下,您应该在案例陈述之前设置默认值。这可以防止综合逻辑在您不关心的状态下推断锁存器,但它也可以帮助您 not 运行 一旦开始就遇到 'x
的问题进行门级仿真 (GLS)。使用您的示例,您的 RTL 将类似于下面的代码。 (再次注意这里的案例有点多余。)
always_comb begin
out_1 = 1;
out_2 = 0;
case(state):
STATE_1:begin
out_1 = 1;
end
STATE_2:begin
out_2 = 0;
end
end
一旦你有了更精细的 FSM,你就会发现这个策略是有意义的。
奖金
我想举一个例子,其中使用 unique
或 priority
是有意义的(而不是使用 'x
作为默认值)。看看下面的 RTL,假设 select == 3'b0
永远不会发生:
always_comb
begin
out_1 = 'x;
case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
end
为 out_1
设置默认值将阻止逻辑推断锁存器(因为它不知道 select == 3'b0
永远不会发生)。此外,这里的'x
会帮助综合工具优化这个逻辑(不一定w.r.t.area!)。然而,正如我们之前所讨论的,使用 'x
通常被认为是不好的做法。
您可以使用 priority
关键字来告诉综合工具已列出所有有效案例,并且该工具必须按顺序评估您的案例,而不是使用默认值。因此,以下情况也将被视为已满:
always_comb
priority case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
另外,如果您可以确定 select
是单热信号 ($countones(select) == 1
),则可以使用 unique
关键字。这将告诉综合工具这是完全并行的情况
always_comb
unique case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
请注意,如果您违反使用 priority
或 unique
.
所必需的假设,模拟器将尝试通过向您抛出错误来强制执行这些假设。
我的问题是关于 FPGA 设计的——如果我的设计中有一些我不关心它们的复位值是多少的寄存器,我可以将复位值设置为 x 吗?这会提高面积效率吗(合成器是否能够利用它并以更有效的方式生成设计?) 例如,
always @(posedge clk or negedge reset_n) begin
if(~reset_n) begin
reg_1 <= 'x
end
...
end
编辑: 另一个类似主题的问题——假设我有一个状态机,例如我不关心某些输出在某些状态下会是什么——将它们设置为“x”会提高面积效率吗? 例如,如果我有一个具有两个状态 STATE_1、STATE_2 和两个输出的 fsm,综合工具将能够利用以下代码:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = x;
end
STATE_2:begin
out_1 = x;
out_2 = 0;
end
end
比这个更好:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = 0;
end
STATE_2:begin
out_1 = 0;
out_2 = 0;
end
end
(假设我不关心 STATE_1 中的 out_2 和 STATE_2 中的 out_1 是什么)。 谢谢
在顺序逻辑中使用 'x
是的,在 Verilog 方面,您可以使用此语法。但是,在您的特定示例中,这样做并没有真正意义,您可以认为这是一种糟糕的编码实践。除了显式分配 'x
,您还可以省略异步重置。
以下两个进程将综合到同一个触发器。我个人会推荐使用后一种风格。
// Assigning 'x to tell synthesis tool that there is no reset value
always @(posedge clk or negedge reset_n)
if(~reset_n)
reg_1 <= 'x;
else
reg_1 <= reg_1_next;
// Omitting the asynchronous reset from the sensitivity list to tell
// synthesis tool that there is no reset
always @(posedge clk)
reg_1 <= reg_1_next;
一般来说:如果您有不同的变量,这些变量必须是可重置的或不可重置的,您应该将它们的赋值分成不同的 always
块。这通常会使您的代码更具可读性。请参阅以下示例:
// Do NOT do this
always @(posedge clk or negedge reset_n)
if(~reset_n)
begin
vld <= 1'b0;
reg_1 <= 'x;
end
else
begin
vld <= vld_next;
reg_1 <= reg_1_next;
end
// Do this
always @(posedge clk or negedge reset_n)
if(~reset_n)
vld <= 1'b0;
else
vld <= vld_next;
always @(posedge clk)
reg_1 <= reg_1_next;
奖金
话虽如此,在某些情况下,在复位条件中分配 'x
以告诉综合工具 不 为特定的生成可复位触发器是有意义的变量。请看看这个答案:
让我们根据这个答案创建一个示例。假设您有一个包含 1 个有效信号 (vld
) 和 2 个数据信号(data_a
和 data_b
)的结构。该数据仅在vld
为1'b1
时有效。换句话说,我们可以通过只重置vld
而不重置data_a
和data_b
来节省空间。
现在,我们想充分发挥结构的潜力,并简单地分配完整的结构而不是单独的成员(参见 struct_example_q <= struct_example_next;
)。这意味着我们 不能 将这个 always
-block 分成两个单独的进程(就像我之前推荐的那样)。在这种情况下,我们必须明确告诉综合工具不要重置数据信号。
查看下面的代码:
typedef struct {
logic vld;
logic [31:0] data_a;
logic [31:0] data_b;
} struct_example_t;
struct_example_t struct_example_next;
struct_example_t struct_example_q;
always @(posedge clk or negedge reset_n)
if (!reset_n)
begin
/**
* Only reset the valid-bit
* We could use '{default:'x} to simplify this even further
**/
struct_example_q.data_a <= 'x;
struct_example_q.data_b <= 'x;
struct_example_q.vld <= 1'b0;
end
else
begin
struct_example_q <= struct_example_next;
end
在组合逻辑中使用'x
让我们先看看您的 RTL:
always_comb begin
case(state):
STATE_1:begin
out_1 = 1;
out_2 = x;
end
STATE_2:begin
out_1 = x;
out_2 = 0;
end
end
我想指出,这并不是最好的例子。假设 FSM 是满的——即 STATE_1
和 STATE_2
是仅有的两个状态 state
可以采用——你将使用下面的代码实现完全相同的效果,假设你不这样做无论如何,关于其他州的 out_1
和 out_2
的情况。
always_comb begin
out_1 = 1;
out_2 = 0;
end
现在,为了示例起见,假设我们无法重写它。在这种情况下,您应该在案例陈述之前设置默认值。这可以防止综合逻辑在您不关心的状态下推断锁存器,但它也可以帮助您 not 运行 一旦开始就遇到 'x
的问题进行门级仿真 (GLS)。使用您的示例,您的 RTL 将类似于下面的代码。 (再次注意这里的案例有点多余。)
always_comb begin
out_1 = 1;
out_2 = 0;
case(state):
STATE_1:begin
out_1 = 1;
end
STATE_2:begin
out_2 = 0;
end
end
一旦你有了更精细的 FSM,你就会发现这个策略是有意义的。
奖金
我想举一个例子,其中使用 unique
或 priority
是有意义的(而不是使用 'x
作为默认值)。看看下面的 RTL,假设 select == 3'b0
永远不会发生:
always_comb
begin
out_1 = 'x;
case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
end
为 out_1
设置默认值将阻止逻辑推断锁存器(因为它不知道 select == 3'b0
永远不会发生)。此外,这里的'x
会帮助综合工具优化这个逻辑(不一定w.r.t.area!)。然而,正如我们之前所讨论的,使用 'x
通常被认为是不好的做法。
您可以使用 priority
关键字来告诉综合工具已列出所有有效案例,并且该工具必须按顺序评估您的案例,而不是使用默认值。因此,以下情况也将被视为已满:
always_comb
priority case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
另外,如果您可以确定 select
是单热信号 ($countones(select) == 1
),则可以使用 unique
关键字。这将告诉综合工具这是完全并行的情况
always_comb
unique case (1'b1)
select[0]: out_1 = a & b;
select[1]: out_1 = a ^ b;
select[2]: out_1 = a | b;
endcase
请注意,如果您违反使用 priority
或 unique
.