OpenCores
URL https://opencores.org/ocsvn/adder_tree/adder_tree/trunk

Subversion Repositories adder_tree

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /adder_tree
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/trunk/trunk/adder_tree.sv
0,0 → 1,77
`ifndef _adder_tree_
`define _adder_tree_
 
// DELAY = $clog2(N)
(* multstyle = "dsp" *) module adder_tree #(parameter
N = 32, DATA_WIDTH = 33, RESULT_WIDTH = ((N-1) < 2**$clog2(N)) ? DATA_WIDTH + $clog2(N) : DATA_WIDTH + $clog2(N) + 1
)(
input clock, clock_ena,
input signed [DATA_WIDTH-1:0] data[N-1:0],
output signed [RESULT_WIDTH-1:0] result
);
generate
if (N == 2)
add #(.DATAA_WIDTH(DATA_WIDTH), .DATAB_WIDTH(DATA_WIDTH), .RESULT_WIDTH(RESULT_WIDTH))
add_inst(.clock(clock), .clock_ena(clock_ena), .dataa(data[0]), .datab(data[1]), .result(result));
else
begin
localparam RES_WIDTH = (RESULT_WIDTH > DATA_WIDTH + 1) ? DATA_WIDTH + 1 : RESULT_WIDTH;
localparam RESULTS = (N % 2 == 0) ? N/2 : N/2 + 1;
wire signed [RES_WIDTH-1:0] res[RESULTS - 1:0];
add_pairs #(.N(N), .DATA_WIDTH(DATA_WIDTH), .RESULT_WIDTH(RES_WIDTH))
add_pairs_inst(.clock(clock), .clock_ena(clock_ena), .data(data), .result(res));
adder_tree #(.N(RESULTS), .DATA_WIDTH(RES_WIDTH))
adder_tree_inst(.clock(clock), .clock_ena(clock_ena), .data(res), .result(result));
end
endgenerate
endmodule :adder_tree
 
//////////////////////
module add_pairs #(parameter
N = 32, DATA_WIDTH = 18, RESULT_WIDTH = DATA_WIDTH + 1, RESULTS = (N % 2 == 0) ? N/2 : N/2 + 1
)(
input clock, clock_ena,
input signed [DATA_WIDTH-1:0] data[N - 1:0],
output signed [RESULT_WIDTH-1:0] result[RESULTS - 1:0]
);
genvar i;
generate
for (i = 0; i < N/2; i++)
begin :a
add #(.DATAA_WIDTH(DATA_WIDTH), .DATAB_WIDTH(DATA_WIDTH), .RESULT_WIDTH(RESULT_WIDTH))
add_inst(.clock, .clock_ena, .dataa(data[2*i]), .datab(data[2*i + 1]), .result(result[i]));
end
if (RESULTS == N/2 + 1)
begin
reg [RESULT_WIDTH-1:0] res;
always @(posedge clock)
if (clock_ena)
res <= data[N-1];
assign result[RESULTS-1] = res;
end
endgenerate
endmodule :add_pairs
 
//////////////////////
module add #(parameter
DATAA_WIDTH = 16, DATAB_WIDTH = 17, RESULT_WIDTH = (DATAA_WIDTH > DATAB_WIDTH) ? DATAA_WIDTH + 1 : DATAB_WIDTH + 1
)(
input clock, clock_ena,
input signed [DATAA_WIDTH-1:0] dataa,
input signed [DATAB_WIDTH-1:0] datab,
output reg signed [RESULT_WIDTH-1:0] result
);
always_ff @(posedge clock)
if (clock_ena)
result <= dataa + datab;
endmodule :add
 
`endif
/trunk/trunk/adder_tree_tb.sv
0,0 → 1,79
timeunit 1ns;
timeprecision 1ps;
 
module adder_tree_tb;
 
localparam N = 10;
localparam DATA_WIDTH = 12;
localparam RESULT_WIDTH = ((N-1) < 2**$clog2(N)) ? DATA_WIDTH + $clog2(N) : DATA_WIDTH + $clog2(N) + 1;
 
bit clock = 0, clock_ena = 1;
 
logic signed [DATA_WIDTH-1:0] data[N-1:0];
wire signed [DATA_WIDTH-1:0] data_in[N-1:0]; // alias for wave form
 
wire signed [RESULT_WIDTH-1:0] result;
bit signed [RESULT_WIDTH-1:0] sum = 0;
 
always #10ns clock++;
 
initial begin
static bit sign = 0, error = 0;
repeat(10) @(posedge clock);
// Test 1
for (int i = 0; i < N; i++)
begin
data[i] = i + 1;
if (sign++) data[i] = -data[i];
end
sum = 0;
for (int i = 0; i < N; i++)
sum += data[i];
repeat(100) @(posedge clock);
assert (sum == result) else error |= 1;
// Test 2
for (int i = 0; i < N; i++)
data[i] = data[i]*(i+1);
sum = 0;
for (int i = 0; i < N; i++)
sum += data[i];
repeat(100) @(posedge clock);
assert (sum == result) else error |= 1;
// Test 3
for (int i = 0; i < N; i++)
data[i] = $signed( {1'b0, {(DATA_WIDTH-1){1'b1}}} ); // max value
sum = 0;
for (int i = 0; i < N; i++)
sum += data[i];
repeat(100) @(posedge clock);
assert (sum == result) else error |= 1;
if (error)
$display("ERROR");
else
$display("Test OK!");
$stop(2);
end
 
adder_tree #(.N(N), .DATA_WIDTH(DATA_WIDTH)) dut(.*);
 
genvar j;
 
generate for (j = 0; j < N; j++)
begin :gen
assign data_in[j] = data[j];
end
endgenerate
 
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.