数字门级电路可分为两大类:组合逻辑和时序逻辑。锁存器是组合逻辑和时序逻辑的一个交叉点,在后面会作为单独的主题处理。
组合逻辑描述了门级电路,其中逻辑块的输出直接反映到该块的输入值的组合,例如,双输入AND门的输出是两个输入的逻辑与。如果输入值发生变化,输出值将反映这一变化,组合逻辑的RTL模型需要反映这种门级行为,这意味着逻辑块的输出必须始终反映该逻辑块当前输入值的组合。
SystemVerilog有三种在可综合RTL级别表示组合逻辑的方法:连续赋值语句、always程序块和函数。接下来几篇文章将探讨每种编码风格,并推荐最佳实践编码风格。
使用函数表示组合逻辑
当编码正确时,函数的行为和综合就像组合逻辑一样。
最佳实践指南7-7 |
---|
将RTL模型中使用的函数声明为自动automatic。 |
为了表示组合逻辑行为,每次调用函数时都必须计算一个新的函数返回值。如果调用了静态函数,但没有指定返回值,则静态函数将隐式返回其上一次调用的值。这是锁存逻辑的行为,而不是组合逻辑。通过将RTL模型中使用的所有函数声明为自动函数(automatic),可以避免这种编码错误。
例7-2定义了一个使用Russian Peasant Multiplication算法(一系列加法和移位运算)计算乘法运算的函数。该函数被定义在一个包中,任何模块都可以使用该乘法器算法。
SystemVerilog会推断出一个与函数名称和数据类型相同的变量,示例7-2中的代码就是利用了这一点。函数名multiply_f被用作临时变量来保存for循环中的中间计算结果,函数名中存储的最终值在函数退出时成为函数返回值。
图7-2显示了综合该函数的结果,以及从连续赋值语句调用该函数的模块。
示例7-2:定义乘法运算的算法函数
代码语言:javascript复制//`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
package definitions_pkg;
timeunit 1ns; timeprecision 1ns;
// Russian Peasant Multiplication Algorithm
function automatic [7:0] multiply_f([7:0] a, b);
multiply_f = 0;
for (int i=0; i<=3; i ) begin
if (b == 0) continue; // all done, finish looping
else begin
if (b & 1) multiply_f = a;
a <<= 1; // multiply by 2
b >>= 1; // divide by 2
end
end
endfunction
endpackage: definitions_pkg
//`end_keywords
//`begin_keywords "1800-2012" // use SystemVerilog-2012 keywords
module algorithmic_multiplier
import definitions_pkg::*;
(input logic [3:0] a, b,
output logic [7:0] result
);
timeunit 1ns; timeprecision 1ns;
assign result = multiply_f(a, b);
endmodule: algorithmic_multiplier
//`end_keywords
图7-2:示例7-2的综合结果:作为组合逻辑的函数
最佳实践指南7-8 |
---|
在可能的情况下,使用SystemVerilog运算符,如*,而不是使用循环和其他编程语句。 |
算法乘法器的示例7-2还说明了为什么在乘法和除法等复杂运算中最好使用SystemVerilog运算符。如果在示例7-2中使用了乘法运算符(*),则综合编译器可以将该运算符映射到ASIC或FPGA的最有效的乘法器。
设计工程师在使用算术运算符或算法来表示复杂操作时需要谨慎。RTL模型不是在具有大量内存资源的通用计算机上运行的软件程序。RTL模型是门级实现的抽象。所表示的功能需要在物理上适合目标ASIC或FPGA,并且在时间上在有限的数量或时钟周期内。之前的文章有详细介绍了在RTL模型中使用算术运算符(如乘法和除法)的指导原则。