消除未使用的位:创建具有不同维度的可合成多维数组 [英] Eliminating unused bits: creating synthesisable multidimensional arrays of with different dimensions

查看:21
本文介绍了消除未使用的位:创建具有不同维度的可合成多维数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是如何迭代创建参数化大小的总线以连接同样迭代创建的模块?.答案太复杂,无法在评论中回答,该解决方案可能对其他 SO 有所帮助.此问题遵循自我回答格式.鼓励添加答案.

This is a follow-on question from How can I iteratively create buses of parameterized size to connect modules also iteratively created?. The answer is too complex to answer in a comment and the solution may be helpful for other SOs. This question is following the self-answer format. Addition answer are encouraged.

以下代码有效并使用双向数组.

The following code works and uses a bi-directional array.

module Multiplier #(parameter M = 4, parameter N = 4)(
  input [M-1:0] A, //Input A, size M
  input [N-1:0] B, //Input B, size N
  output [M+N-1:0] P );  //Output P (product), size M+N

wire [M+N-1:0] PP [N-1:0]; // Partial Product array
assign PP[0] = { {N{1'b0}} , { A & {M{B[0]}} } }; // Pad upper bits with 0s
assign P = PP[N-1]; // Product

genvar i;
generate
for (i=1; i < N; i=i+1)
begin: addPartialProduct
    wire [M+i-1:0] gA,gB,gS;  wire Cout;
    assign gA = { A & {M{B[i]}} , {i{1'b0}} };
    assign gB = PP[i-1][M+i-1:0];
    assign PP[i] = { {(N-i){1'b0}}, Cout, gS}; // Pad upper bits with 0s
    RippleCarryAdder#(M+i) adder( .A(gA), .B(gB), .S(gS), .Cin(1'b0), .* );
end
endgenerate

endmodule

有些位从未使用过,例如PP[0][M+N-1:M+1].合成器通常会在优化期间删除这些位,并可能发出警告.某些合成器不够先进,无法正确执行此操作.为了解决这个问题,设计者必须实现额外的逻辑.在此示例中,所有 RippleCarryAdder 的参数将设置为 M+N.额外的逻辑会浪费面积并严重降低性能.

Some of the bits are never used, such as PP[0][M+N-1:M+1]. A synthesizer will usually remove these bits during optimization and possibly give a warning. Some synthesizers are not advance enough to do this correctly. To resolve this, the designer must implement extra logic. In this example the parameter for all the RippleCarryAdder's would be set to M+N. The extra logic wastes area and potently degrades performance.

如何安全地消除未使用的位?可以使用不同维度的多维数组吗?最终代码是否可读和可调试?

How can the unused bits be safely eliminated? Can multidimensional arrays with different dimensions be used? Will the end code be readable and debug-able?

推荐答案

可以使用不同维度的多维数组吗?

Can multidimensional arrays with different dimensions be used?

简短的回答,不.

Verilog 不支持唯一大小的多维数组.SystemVerilog 确实支持动态数组,但是这些不能连接到模块端口,也不能合成.

Verilog does not support unique sized multidimensional arrays. SystemVerilog does support dynamic arrays however these cannot be connected to module ports and cannot be synthesized.

嵌入式代码(例如 Perl 的 EP3, Ruby 的 eRuby/ruby_it,Python 的 prepro 等)可以生成自定义的宗派数组和代码迭代,但参数必须在编译前进行硬编码.给定实例的任何参数的最终值在编译时是发现者,在嵌入式脚本运行之后很久.该参数必须作为全局常量处理,因此Multiplier#(4,4)Multiplier#(8,8)不能存在于同一个项目中,除非教脚本如何提取项目的完整层次结构和参数.(祝你编码和维护好运).

Embedded code (such as Perl's EP3, Ruby's eRuby/ruby_it, Python's prepro, etc.) can generate custom denominational arrays and code iterations, but the parameters must be hard coded before compile. The final value of any parameter of a given instance is discoverer during compile time, well after the embedded script is ran. The parameter must be treated as a global constant, therefore Multiplier#(4,4) and Multiplier#(8,8) cannot exist in the same project unless to teach the script how to extract the full hierarchy and parameters of the project. (Good luck coding and maintaining that).

如何安全地消除未使用的位?

How can the unused bits be safely eliminated?

如果合成器不够先进,无法自行排除未使用的位,则可以通过将多维数组展平为具有智能部分选择的一维数组来优化这些位.诀窍是找到可以通过以下步骤实现的方程:

If the synthesizer is not advance enough to exclude unused bits on its own, then the bits can be optimized by flattening the multidimensional array into a one-dimensional array with intelligent part-select. The trick is finding the equation which can be achieved by following these steps:

  1. 找到每个部分部分选择的 lsb 索引的模式:
  1. 假设M为4,每个part-select的lsb0, 5, 11, 18, 26, 35, ....将此模式代入 WolframAlpha 以找到方程 a(n) = (n-1)*(n+8)/2.
  2. 重复 M 等于 3 的模式 0, 4, 9, 15, ... 得到方程 a(n)=(n-1)*(n+6)/2
  3. 再次重复 M 等于 5 的模式 0, 6, 13, 21, 30, ... 得到方程a(n)=(n-1)*(n+10)/2.
  4. 由于MN的关系是线性的(即倍数;没有指数、对数等),所以只需要两个方程就可以创建一个可变参数M 方程.对于非线性方程,建议使用更多数据点方程.在这种情况下,请注意对于 M=3,4,5 模式 (n+6),(n+8),(n+10),因此通用方程可以导出为:lsb(n)=(n-1)*(n+2*M)/2
  1. Assume M is 4, the lsb for each part-select are 0, 5, 11, 18, 26, 35, .... Plug this pattern into WolframAlpha to find the equation a(n) = (n-1)*(n+8)/2.
  2. Repeat with M equal to 3 for the pattern 0, 4, 9, 15, ... to get equation a(n)=(n-1)*(n+6)/2
  3. Repeat again with M equal to 5 for the pattern 0, 6, 13, 21, 30, ... to get equation a(n)=(n-1)*(n+10)/2.
  4. Since the relation of M and N is linear (i.e. multiple; no exponential, logarithmic, etc.), only two equations are needed to create a variable parameter M equation. For non-linear equations more data-point equations are recommended. In this case note that for M=3,4,5 the pattern (n+6),(n+8),(n+10), therefore the generic equation can be derived to: lsb(n)=(n-1)*(n+2*M)/2

  • 为每个部分选择细化 msb 索引的模式:

    1. 使用与查找 lsb 相同的过程(最终为 msb(n)=(n**2+(M*2+1)*n-2)/2).或者根据lsb定义msb:msb(n)=lsb(n+1)-1
    1. Use the same process of as finding the lsb (ends up being msb(n)=(n**2+(M*2+1)*n-2)/2). Or define the msb in terms of lsb: msb(n)=lsb(n+1)-1

  • IEEE std 1364-2001 (Verilog 2001) 引入了带有参数和索引部分选择的宏;见 &sec;19.3.1 '`define' 和 §4.2.1 分别是向量位选择和部分选择寻址".或查看 IEEE std 1800-2012 §22.5.1 '`define' 和 §11.5.1 分别是向量位选择和部分选择寻址".此答案假定 SO 的模拟器和合成器支持这些功能,因为 generate 关键字也在 IEEE std 1364-2001 中引入,请参阅 §12.1.3 生成的实例化"(和 IEEE std 1800-2012§ 27.生成结构").对于不完全支持 IEEE std 1364-2001 的工具,请参阅 `ifdef 提供的示例 此处.

    IEEE std 1364-2001 (Verilog 2001) introduced macros with arguments and indexed part-select; see § 19.3.1 '`define' and § 4.2.1 'Vector bit-select and part-select addressing' respectively. Or see IEEE std 1800-2012 § 22.5.1 '`define' and § 11.5.1 'Vector bit-select and part-select addressing' respectively. This answer assumes that these features are supported by the SO's simulator and synthesizer since the generate keyword was also introduced in IEEE std 1364-2001, see § 12.1.3 'Generated instantiation' (and IEEE std 1800-2012 § 27. 'Generate constructs'). For tools that are not fully support IEEE std 1364-2001, see `ifdef examples provided here.

    由于经常使用计算部分选择范围的函数,请使用带参数的`define 宏.这将有助于防止复制/粘贴错误.宏定义中额外的 () 集是为了确保正确的操作顺序.在模块定义的末尾`undef宏也是一个好主意,防止全局空间被污染.对于扁平阵列,调试可能变得具有挑战性.通过在生成块的 for 循环中定义直通连接,信号可以变得可读并且可以在波形中探测.

    Since the functions to calculate the part-select ranges are frequently used, use `define macros with arguments. This will help prevent copy/paste bugs. The extra sets of () in the macro definitions are to insure proper order of operations. It is also a good idea to `undef the macros at the end of the module definition, preventing the global space from getting polluted. With the flattened array it may become challenging to debug. By defining pass-through connections within the generate block's for-loop the signal can become readable and can be probed in waveform.

    module Multiplier #(parameter M = 4, parameter N = 4)(
      input [M-1:0] A, //Input A, size M
      input [N-1:0] B, //Input B, size N
      output [M+N-1:0] P );  //Output P (product), size M+N
    
    // global space macros
    `define calc_pp_lsb(n) (((n)-1)*((n)+2*M)/2)
    `define calc_pp_msb(n) (`calc_pp_lsb(n+1)-1)
    `define calc_pp_range(n) `calc_pp_lsb(n) +: (M+n)
    
    wire [`calc_pp_msb(N):0] PP; // Partial Product
    assign PP[`calc_pp_range(1)] = { 1'b0 , { A & {M{B[0]}} } };
    assign P = PP[`calc_pp_range(N)]; // Product
    
    genvar i;
    generate
    for (i=1; i < N; i=i+1)
    begin: addPartialProduct
        wire [M+i-1:0] gA,gB,gS;  wire Cout;
        assign gA = PP[`calc_pp_range(i)];
        assign gB = { A & {M{B[i]}} , {i{1'b0}} };
        assign PP[`calc_pp_range(i+1)] = {Cout,gS};
        RippleCarryAdder#(M+i) adder( .A(gA), .B(gB), .S(gS), .Cin (1'b0), .* );
    end
    endgenerate
    
    // Cleanup global space
    `undef calc_pp_range
    `undef calc_pp_msb
    `undef calc_pp_lsb
    
    endmodule
    

    并排和测试台的工作示例:http://www.edaplayground.com/s/6/591

    Working example with side-by-side and test bench: http://www.edaplayground.com/s/6/591

    最终代码是否可读和可调试?

    Will the end code be readable and debug-able?

    是的,对于任何已经学会如何正确使用 generate 结构的人来说.generate 块的 for 循环定义了局部连线,这些连线被限制在循环索引的范围内.来自loop-0的gA和来自loop-1的gA是唯一的信号,不能相互交互.可以波形探测本地信号,有利于调试.

    Yes, for anyone who has already learned how to properly use the generate construct. The generate block's for-loop defines local wires which are confined to scope of the loop index. gA form loop-0 and gA from loop-1 are unique signals and cannot interact with each other. The local signals can be probed in waveform which is great for debugging.

    这篇关于消除未使用的位:创建具有不同维度的可合成多维数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆