SoC芯片设计——为什么使用assign语句,来避免使用if-else或者case来设计电路。

0.介绍

对于一块芯片的设计,尤其是芯片CPU内核,为什么你写的代码,别人不敢用,功能正确,验证通过,综合,编译通过,为什么还是没有人会使用?答案很简单,一个主要原因是,你写出的code,性能不高,风险较高,不满足严谨的工业级的开发标准。

下面介绍一下,一个最基本的RTL编写原则——尽量使用阶梯式的assign语句来编写,代替if-else,case的编写。
虽然if-else,case有很多优势,如:

  1. 有优先级顺序;
  2. 件覆盖率容易debug,这点对于验证来说,能够更快的debug出条件的覆盖率等

1.if-else,case的潜在问题

那么if-else,case在实际的电路设计中:

  1. 很少利用其优先级的顺序,绝大多数是并行选择电路;
  2. if-else综合的电路并不利于后续时序和面积的优化,降低电路的性能
  3. 并且if-else不能够传播不定态X,这一点对于后续电路,验证中,导致不定态被掩盖,从而诱导出致命错误。

2. 详细介绍if-else问题,使用Assign解决

  1. Verilog的if-else不能传播不定态X
    对于一下代码片段,如果a的值为不定态,Verilog语法会将其a的值与a==0等效,从而out会选择in2,最终并没有将不定态传播出去。
if(a)
	out = in1;
else
	out = in2;

这种情况,有的人会说,那岂不是更好么,电路要的就是没有不定态,这个能够将不定态处理了,岂不是更好
这种思想显然是错误的,并不符合设计的规范,并且在电路的仿真阶段,掩盖了前级电路不定态传播的风险,导致,在仿真阶段没有debug出来,造成芯片的错误。

改进的方法,推荐使用assign语句,如下所示:

assign out = a ? in2: in1;

按照Verilog的语法,则此电路会将不定态传播出去,在仿真阶段就能够发现电路的错误。
虽然,随着EDA工具的发展,很多eda工具都能能够将不传播不定态的情形强行传播出来,例如Synopsys VCS提供xprop选项。但是一方面不是所有的EDA工具又可以支持。

  1. Verilog的case也不能传播不定态X,和上面的问题一样
  2. Verilog的if-else语法会被综合成为优先级选择的电路,面积和时序得不到优化
if(sel1)
	out = in1[3:0];
else if (sel2)
	out = in2[3:0];
else if (sel3)
	out = in3[3:0];
else
	out = 4'b0;

3.1 对于确实有优先级的逻辑设计
则更加推荐使用如下的设计形式:assign可以将其等效:

assign out = sel1 ? in1[3:0] :
		     sel2 ? in2[3:0] :
		     sel3 ? in3[3:0] :
		     4'b0;

此种可以规避不定态传播的问题,同时可以生成优先级电路。

3.2对于不需要优先级的逻辑设计
也推荐使用如下的设计形式,将其等效:

assign  out = ( 4{sel1}) & in1[3:0] ) |
			  ( 4{sel2}) & in2[3:0] ) |
			  ( 4{sel3}) & in3[3:0] ) |

使用assign语法编写 "与"和“或”逻辑一定能够保证综合生成并行选择电路

  1. Verilog的case优先级选额电路
    Verolog的case语法也会被综合成优先级选择电路,面积和时序均得不到优化,
    虽然有的EDA工具可以提供注释,例如Synopsys parallel case和 full case 来时综合工具能够综合出并行选择逻辑,但是这样可以会造成前仿和后仿结果不一致的严重问题,从而产生重大的BUG。电路的开发中,一般尽量少用这些指引注释,并推荐等效的assign语法编写电路

3. 其他的Colding Style

电路设计一般分为数据通路、控制模块。因此,在数据通路的设计中,可以避免使用带有reset的寄存器,这样的设计方法会减少面积,并且能够优化时序。

因此,在数据通路的设计上,可以使用不带reset的寄存器,而只在控制通路上使用带reset的寄存器

以下是使用case, if-else和assign语句分别实现四选一多路选择器的代码示例,以及它们的特点比较。 使用case语句实现四选一多路选择器: ``` module mux_case(sel, in, out); input [1:0] sel; input [3:0] in; output reg out; always @(*) begin case(sel) 2'b00: out = in[0]; 2'b01: out = in[1]; 2'b10: out = in[2]; 2'b11: out = in[3]; endcase end endmodule ``` 使用if-else语句实现四选一多路选择器: ``` module mux_if_else(sel, in, out); input [1:0] sel; input [3:0] in; output reg out; always @(*) begin if(sel == 2'b00) out = in[0]; else if(sel == 2'b01) out = in[1]; else if(sel == 2'b10) out = in[2]; else if(sel == 2'b11) out = in[3]; end endmodule ``` 使用assign语句实现四选一多路选择器: ``` module mux_assign(sel, in, out); input [1:0] sel; input [3:0] in; output out; assign out = (sel == 2'b00) ? in[0] : (sel == 2'b01) ? in[1] : (sel == 2'b10) ? in[2] : in[3]; endmodule ``` 这三种实现方式各有特点: - case语句:基于硬件描述语言的特性,可以很直观地描述多路选择器的行为,更加易于理解和维护。同时,case语句可以有效地避免出现选择器的数据冲突问题,因为每个分支只会选择一个输入信号作为输出。 - if-else语句:与case语句相比,if-else语句更加灵活,可以实现更加复杂的逻辑。但是,if-else语句可能会导致冲突问题,因为可能会同时选择多个输入信号作为输出。 - assign语句assign语句是一种连续赋值语句,可以很方便地实现多路选择器的逻辑。但是,assign语句可能会导致冲突问题,因为它不会自动解决多个输入信号同时被选中的情况,需要开发者手动解决。 综上所述,使用case语句实现多路选择器更加直观和可维护,同时能够避免冲突问题。如果需要实现更加复杂的逻辑,可以考虑使用if-else语句。而使用assign语句实现多路选择器虽然简单,但需要注意冲突问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摆渡沧桑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值