Verilog/SystemVerilog参数化加法树

突然发现百度和Google都搜索不到参数化加法树的写法,这里贴出一个单周期纯组合逻辑版本供参考。VHDL参数化加法树是类似的,这里就不列出了。


这里实现的是倒二叉树类型的加法树,纯组合逻辑,奇偶加数均支持自动生成。大概是下图的结构
Verilog/SystemVerilog参数化加法树_第1张图片
参数有三个:

  • IN_WIDTH: 每一个输入加数的位宽;
  • NUM: 加数个数;
  • OUT_WIDTH: 输出结果尾款,注意加法树每一层中间结果均会增加1bit,输出位宽不能太小,否则会发生截断。

输入输出:

  • a: 所有加数concat在一起,位宽IN_WIDTH*NUM
  • ans: 结果

下面是systemverilog写法,verilog简单地将logic替换成 reg即可。

/*======================================================
Descripton:
parameterized adder tree, full comb

Create:  
Yipeng   [email protected]  20191126

Modify:

Notes:
1. contain constant functions
=========================================================*/
module adder_tree#(
    parameter IN_WIDTH = 8,
    parameter NUM   = 4,
    parameter OUT_WIDTH = 32
)(
    input  logic [NUM * IN_WIDTH - 1 : 0] a,
    output logic signed [OUT_WIDTH - 1 : 0] ans
);
genvar i, j;
// - gen adders ----------------------------------------------------------
generate
for(i = 1; i <= gen_level(NUM); i++)begin:gen_add_levels
    logic signed [1:gen_num_of_a_level(NUM,i)] [IN_WIDTH + i - 1 : 0] sum; // more bit for every level
    if(i == 1) begin    // - special for first level -------------------
    
        for(j = 1; j <= gen_num_of_a_level(NUM,i) - 1; j++)begin: gen_add_levels
            assign sum[j] = a[(NUM- 2*j + 2) * IN_WIDTH - 1 -: IN_WIDTH] + a[(NUM- 2*j + 1) * IN_WIDTH - 1 -: IN_WIDTH];
        end
        if(gen_odd_sign(NUM,i) == 1) 
            assign sum[gen_num_of_a_level(NUM,i)] = a[IN_WIDTH - 1 : 0]; //need auto sign extention
        else
            assign sum[gen_num_of_a_level(NUM,i)] = a[IN_WIDTH - 1 : 0] + a[2*IN_WIDTH - 1 : IN_WIDTH];

    end else if (i == gen_level(NUM)) begin    // - output for last level ------------------

        assign ans = gen_add_levels[i-1].sum[1] + gen_add_levels[i-1].sum[2];          //need auto sign extention

    end else begin      // - intermediate levels ------------------

        for(j = 1; j <= gen_num_of_a_level(NUM,i) - 1; j++)begin: gen_add_levels
            assign sum[j] = gen_add_levels[i-1].sum[(NUM- 2*j + 2) * IN_WIDTH - 1 -: IN_WIDTH] + gen_add_levels[i-1].sum[(NUM- 2*j + 1) * IN_WIDTH - 1 -: IN_WIDTH];
        end
        if(gen_odd_sign(NUM,i) == 1) 
            assign sum[gen_num_of_a_level(NUM,i)] = gen_add_levels[i-1].sum[IN_WIDTH - 1 : 0];       //need auto sign extention
        else
            assign sum[gen_num_of_a_level(NUM,i)] = gen_add_levels[i-1].sum[IN_WIDTH - 1 : 0] + gen_add_levels[i-1].sum[2*IN_WIDTH - 1 : IN_WIDTH];

    end
end
endgenerate

// - functions ----------------------------------
function integer gen_level;
input integer num;
begin
    gen_level = 0;
    while (num > 1) begin
        num = $clog2(num);
        gen_level++;
    end
end  
endfunction

function  integer  gen_odd_sign;
input integer num;
input integer i;
begin
    while(i > 1) begin
        num = $clog2(num);
        i--;
    end
    gen_odd_sign = (num % 2) == 1;
end  
endfunction

function integer  gen_num_of_a_level;
input integer num;
input integer i;
begin
    while(i > 1) begin
        num = $clog2(num);
        i--;
    end
    gen_num_of_a_level = $clog2(num);
end  
endfunction

endmodule

你可能感兴趣的:(digital)