相关阅读
HDL Compiler
https://blog.csdn.net/weixin_45791458/category_12893238.html?spm=1001.2014.3001.5482
综合指令(Synthesis Directives)是一些特殊注释,用于影响综合工具如何处理RTL代码,这些注释会被综合工具识别,但会被其他工具(如仿真器)忽略。关于综合指令相关概念的更多介绍,可以参考下面的博客。
HDL Compiler:综合指令
https://chenzhang.blog.csdn.net/article/details/148695750 首先回顾一下不可读的概念:不可读是一种状态,单元(触发器、组合逻辑门)都可能位于这种状态,简单来说,不可读就是单元直接或间接没有驱动任何输出端口。当RTL代码中包含不可读或无驱动触发器/组合逻辑门时,HDL Compiler会把它们删除,因此并不会有不可读或无驱动触发器的推断报告,例1展示了不可读触发器的删除。
// 例1
module unread(input a, b, c, clk, output z);
reg a_r1, a_r2;
wire d;
assign z = a_r1;
assign d = a_r2 & c;
always@(posedge clk) begin
a_r1 <= a;
a_r2 <= a & b;
end
endmodule
下面为HDL Compiler读取例1时产生的触发器推断报告,可以看出其中并未识别出不可读触发器a_r2_reg。
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| a_r1_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
==================================================================================
图1为此时的GTECH网表,可以看出一个触发器和两个与门都因为被认定为是直接/间接不可读状态而删除,只有触发器a_r1_reg以SEQGEN的形式存在。

图1 例1的GETCH网表
可以通过设置hdlin_preserve_sequential变量(默认值为none)控制是否保留不可读或无驱动触发器,如果将该变量设置为all或者true,触发器推断报告如下所示。
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| a_r1_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
| a_r2_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
==================================================================================
图2为此时的GTECH网表,可以看出只有不可读触发器a_r2_reg后面的与门都因为被认定为是直接不可读状态而删除,不可读触发器a_r2_reg和其前面的与门(间接)都得到了保留。

图2 例1的GETCH网表
例1展示了不可读触发器的保留,如果无驱动触发器使用该方法保留下来了,会将无驱动引脚连接到常量0。
hdlin_preserve_sequential变量
当该变量被设置为all或者true时,保留所有不可读时序单元,不包括仅作为循环变量使用的不可读时序单元;当该变量被设置为all+loop_variables或者true+loop_variables时,保留所有不可读时序单元,包括仅作为循环变量使用的不可读时序单元;当该变量被设置为ff时,仅保留所有不可读触发器,不包括仅作为循环变量使用的不可读触发器;当该变量被设置为ff+loop_variables时,仅保留所有不可读触发器,包括仅作为循环变量使用的不可读触发器;当该变量被设置为latch时,仅保留所有不可读锁存器,不包括仅作为循环变量使用的不可读锁存器;当该变量被设置为latch+loop_variables时,仅保留所有不可读触发器,包括仅作为循环变量使用的不可读锁存器;
例2展示了仅作为循环变量使用的不可读触发器,其中i信号作为integer类型的变量作为for循环内的索引变量,默认不会被推断为触发器。
// 例2
module test (input clk, rst, error);
parameter N = 4;
reg [N-1:0] fail;
integer i, j;
always @(posedge clk or posedge rst)
if (rst)
fail <= {N-1{1'b0}};
else
for ( i = 0; i < N; i = i + 1 )
fail[i] <= fail[i] | error;
endmodule
当hdlin_preserve_sequential变量被设置为none时,所有不可读触发器fail_reg[i]都被删除了;当hdlin_preserve_sequential变量被设置为all时,触发器推断报告如下所示,GETCH网表如图3所示;
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| fail_reg | Flip-flop | 4 | Y | N | None | Async | N | 7 |
==================================================================================

图3 例2的GETCH网表
当hdlin_preserve_sequential变量被设置为all+loop_variables时,触发器推断报告如下所示,GETCH网表如图4所示。
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| fail_reg | Flip-flop | 4 | Y | N | None | Async | N | 7 |
| i_reg | Flip-flop | 32 | Y | N | None | None | N | 7 |
==================================================================================

图4 例2的GETCH网表
preserve_sequential综合指令
hdlin_preserve_sequential变量只能进行粗粒度的控制,如果想要更细粒度的控制,可以使用preserve_sequential综合指令。需要强调,preserve_sequential综合指令只能用于保留有可能被推断出的时序单元,对于组合逻辑的保留是间接的。
例3展示了该综合指令的使用方法。
// 例3
module mydesign (input in1, in2, in3, input clk, output out);
reg sum1;
reg sum2 /* synopsys preserve_sequential */;
wire save;
always @ (posedge clk) begin
sum1 <= in1 | in2;
sum2 <= in1 & in2 & in3; // 该组合逻辑会被保留(间接)
end
assign out = ~sum1;
assign save = sum1 & sum2; // 该组合逻辑不会被保留,因为它位于被保留触发器sum2_reg后面
endmodule
此时的触发器推断报告如下所示,GETCH网表如图5所示。
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| sum1_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
| sum2_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
==================================================================================

图5 例3的GETCH网表
例4展示了该综合指令的使用方法。
// 例4
module mydesign (input in1, in2, in3, input clk, output out);
reg sum1;
reg sum2, save /* synopsys preserve_sequential */;
always @ (posedge clk) begin
sum1 <= in1 | in2;
sum2 <= in1 & in2 & in3; // 该组合逻辑会被保留(间接)
end
assign out = ~sum1;
always @ (posedge clk) begin
save = sum1 & sum2; // 该组合逻辑也会被保留(间接),因为save信号被定义为reg类型且添加了综合指令
end
endmodule
此时的触发器推断报告如下所示,GETCH网表如图6所示。
==================================================================================
| Register Name | Type | Width | Bus | MB | Set | Reset | ST | Line |
==================================================================================
| sum1_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
| sum2_reg | Flip-flop | 1 | N | N | None | None | N | 6 |
| save_reg | Flip-flop | 1 | N | N | None | None | N | 13 |
==================================================================================

图6 例4的GETCH网表
Design Compiler NXT在2022版本推出了report_transformed_registers命令,该命令可以报告工具在优化过程中对寄存器(包括触发器和锁存器)进行的所有变换,详细内容可以参考下面的博客。
SDC命令详解:使用report_transformed_registers命令进行报告
https://blog.csdn.net/weixin_45791458/article/details/158101563?sharetype=blogdetail&sharerId=158101563&sharerefer=PC&sharesource=weixin_45791458&spm=1011.2480.3001.8118 不管是使用hdlin_preserve_sequential变量还是preserve_sequential综合指令,它只能影响HDL Compiler在读取RTL代码时的行为,对于Design Compiler在综合时对于不可读触发器的优化,可以参考下面的博客。